我希望将视频从iOS相机直播到服务器。我意识到可以使用AVCaptureVideoDataOutput来获取单个帧;但是,我想主要用于iPad 2和3,这些iOS设备内置的mp4硬件压缩。 AVCaptureVideoDataOutput提供原始视频数据,这不是我真正想要的。虽然确实可以使用ffmpeg在发送到服务器之前获取原始视频并进行压缩,但ffmpeg是我们不能用作基于GPL的代码,而我们的代码是封闭源代码。经过几天的研究,主要是谷歌搜索,我没有找到很多关于如何创建一个新文件,比如每5或10秒,从这些小文件中获取所有字节并发送到服务器。
我一直在考虑的两种方法:
使用AVCaptureMovieFileOutput将该数据流式传输到iOS上的磁盘。然后在单独的线程或带有操作对象的异步操作队列中,读取特定数量的字节,将这些字节附加到可变NS数据对象,并以某种方式将NSMutableData变量重建为可在设备iPad上播放的视频。目前,我还没有建立任何网络通信,所以我想拍摄那个视频,从NSMutableData变量重建,只显示在我的AVCaptureViewPreviewLayer旁边。我觉得这样做不会很好。
- 首先,AVCaptureMovieFileOutput可能是缓冲区,导致文件写入时间延迟。 - 第二,即使我要阅读部分书面文件,随着录制时间变长,文件也会增长,在某些时候,文件会变得太大而录制会停止。
所以第一种方法可能不是最好的。
方法2是我要去的地方。
这是我到目前为止所做的:
#define LIVE_VIDEO_STREAM_INTERVAL 3
@interface AVCam (FileOutputDelegate) <AVCaptureFileOutputRecordingDelegate>
@end
// class AVCam
@implementation AVCam
- (id) initWithSession:(AVCaptureSession *)aSession
{
if ( (self = [super init]) )
{
AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([aSession canAddOutput:aMovieFileOutput])
[aSession addOutput:aMovieFileOutput];
// thinking of changing this to a property, not sure yet.
_movieFileOutput = [aMovieFileOutput retain];
[aMovieFileOutput release];
[self setSession:aSession];
_tempFileCount = 0;
_writtenFiles = [[NSMutableArray alloc] init];
_liveVideoStreamTimer = [[NSTimer scheduledTimerWithTimeInterval:LIVE_VIDEO_STREAM_INTERVAL target:self selector:@selector(onStreamingRecordFired:) userInfo:nil repeats:YES] retain];
[self pauseTimer];
}
}
- (void) startStream
{
[self startRecording];
[_liveVideoStreamTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:LIVE_VIDEO_STREAM_INTERVAL]];
}
- (void) stopStream
{
[self stopRecording];
[_liveVideoStreamTimer invalidate];
}
- (BOOL) isRecording
{
return [_movieFileOutput isRecording];
}
- (void) startRecording
{
_currentWritePath = [self tempFileURL];
AVCaptureConnection *videoConnection = [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo fromConnection:[_movieFileOutput connections]];
if ([videoConnection isVideoOrientationSupported])
[videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
[_movieFileOutput startRecordingToOutputFileURL:_currentWritePath recordingDelegate:self];
}
- (void) stopRecording
{
[_movieFileOutput stopRecording];
}
- (NSURL *) tempFileURL
{
//NSURL *tempURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@%d%@", [[self appDelegate] applicationDocumentsDirectory], @"output", _tempFileCount, @".mov"]];
NSURL *tempURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@%d%@", NSTemporaryDirectory(), @"output", _tempFileCount, @".mov"]];
_tempFileCount++;
return tempURL;
}
- (void) onStreamingRecordFired:(id)context
{
if ([self isRecording])
{
NSLog(@"onStreamingRecordFired and isRecording");
[_session beginConfiguration];
[self stopRecording];
[_session removeOutput:_movieFileOutput];
_movieFileOutput = nil;
_movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([_session canAddOutput:_movieFileOutput])
[_session addOutput:_movieFileOutput];
[self startRecording];
[_session commitConfiguration];
}
}
@end
@implementation AVCam (FileOutputDelegate)
- (void) captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnection:(NSArray *)connections
{
NSLog(@"recording started");
}
- (void) captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnection:(NSArray *)connections error:(NSError *)error
{
NSLog(@"recording finished at URL: %@", outputFileURL);
// add outputFileURL to _writtenFiles array, will need to purge file(s) after
// a specific amount of time, say 60 secs files that were recorded more than that
// should be purged.
[_writtenFiles addObject:outputFileURL];
}
@end
我对AVFoundation没有太多经验,所以我不确定在beginConfiguration和commitConfiguration之间停止和启动录制是否正确。
不幸的是,我的代码效果不佳。
我在想,因为我停止录制然后立即从_session中移除movieFileOutput,因为它无法调用它的委托。 captureOutput:didFinishRecordingToOutputFileAtURL:fromConnection:error:被调用一次。
这是我的调试输出:
recording started
onStreamingRecordFired and isRecording
recording finished at URL: file://localhost/private/var/mobile/Applications/6768112A-10B4-41F9-B6A2-4579735B6F14/tmp/output1.mov