Phi*_*Bot 7 cocoa objective-c avfoundation ios avcapturesession
NSInvalidArgumentException当我开始在一个视频viewController控制器中拍摄照片时开始录制视频时,我偶尔会遇到异常.我已经尝试了Google和So的一些建议,但仍然在startRecordingToOutputFileURL:fileURL通话时收到此错误.
如果我没有访问另一个拍摄照片的视图控制器,我就不会收到错误 - 只有当我拍照时才会出现错误,然后切换到进行视频录制的新视图控制器.
我认为拍照留下了一些遗留问题,但是当我初始化我的录像机视图控制器时,我没有错误设置会话和诸如此类的东西.有什么想法或如何从中恢复?为什么这是一个NSInvalidArgumentException例外?谢谢!
这是我的代码:
dispatch_async(dispatch_get_main_queue(), ^{
// Try to Fix bug:
// http://stackoverflow.com/questions/5979962/error-while-recording-video-on-iphone-using-avfoundation
[self.captureSession beginConfiguration];
// Ensure session is running
if ( [self.captureSession isRunning] == NO ) {
NSLog(@"Capture session is NOT running... Starting it now!");
[self.captureSession startRunning];
}
else {
NSLog(@"Capture session is ALREADY running...");
}
NSLog(@"File URL is: %@",fileURL);
NSLog(@"FileOutput is: %@",self.fileOutput);
[self.fileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];
// Try to Fix bug:
// http://stackoverflow.com/questions/5979962/error-while-recording-video-on-iphone-using-avfoundation
[self.captureSession commitConfiguration];
});
Run Code Online (Sandbox Code Playgroud)
这是错误回溯:
2014-05-18 16:01:38.818 app[1699:60b] *** Start recording
2014-05-18 16:01:38.820 app[1699:60b] Capture session is ALREADY running...
2014-05-18 16:01:38.827 app[1699:60b] Capture session is ALREADY running...
2014-05-18 16:01:38.828 app[1699:60b] File URL is: file:////var/mobile/Applications/73FFC590-05A8-4D74-82D9-EBA122B00A20/Documents/2014-05-18-16-01-38-0.mp4
2014-05-18 16:01:38.828 app[1699:60b] FileOutput is: <AVCaptureMovieFileOutput: 0x16513b10>
2014-05-18 16:01:38.829 app[1699:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] - no active/enabled connections.'
*** First throw call stack:
(0x2fe5ff0b 0x3a5f6ce7 0x2ed5751d 0xfb4b5 0x3aadfd53 0x3aadfd3f 0x3aae26c3 0x2fe2a681 0x2fe28f4d 0x2fd93769 0x2fd9354b 0x34d006d3 0x326f2891 0xe40c9 0x3aaf4ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
Run Code Online (Sandbox Code Playgroud)
这就是captureSession的初始化方式(来自OpenSource项目:https://github.com/shu223/SlowMotionVideoRecorder):
- (id)initWithPreviewView:(UIView *)previewView {
self = [super init];
if (self) {
NSError *error;
self.captureSession = [[AVCaptureSession alloc] init];
self.captureSession.sessionPreset = AVCaptureSessionPresetInputPriority;
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *videoIn = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if (error) {
NSLog(@"Video input creation failed");
return nil;
}
if (![self.captureSession canAddInput:videoIn]) {
NSLog(@"Video input add-to-session failed");
return nil;
}
[self.captureSession addInput:videoIn];
// save the default format
self.defaultFormat = videoDevice.activeFormat;
defaultVideoMaxFrameDuration = videoDevice.activeVideoMaxFrameDuration;
AVCaptureDevice *audioDevice= [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput *audioIn = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
[self.captureSession addInput:audioIn];
self.fileOutput = [[AVCaptureMovieFileOutput alloc] init];
[self.captureSession addOutput:self.fileOutput];
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
self.previewLayer.frame = previewView.bounds;
self.previewLayer.contentsGravity = kCAGravityResizeAspectFill;
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[previewView.layer insertSublayer:self.previewLayer atIndex:0];
[self.captureSession startRunning];
}
return self;
}
Run Code Online (Sandbox Code Playgroud)
我的代码在viewDidLoad中使用了这样的初始化代码:
self.captureManager = [[AVCaptureManager alloc] initWithPreviewView:self.view];
self.captureManager.delegate = self;
Run Code Online (Sandbox Code Playgroud)
实际开始和停止录制的代码是从IBAction方法完成的,如下所示:
- (IBAction)recButtonTapped:(id)sender {
// REC START
if (self.captureManager.isRecording == NO ) {
NSLog(@"*** Start recording");
// change UI
[self.recBtn setImage:self.recStopImage
forState:UIControlStateNormal];
self.fpsControl.enabled = NO;
// timer start
startTime = [[NSDate date] timeIntervalSince1970];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(timerHandler:)
userInfo:nil
repeats:YES];
[self.captureManager startRecording];
}
// REC STOP
else {
NSLog(@"*** Stop recording");
isNeededToSave = YES;
[self.captureManager stopRecording];
[self.timer invalidate];
self.timer = nil;
// change UI
[self.recBtn setImage:self.recStartImage
forState:UIControlStateNormal];
self.fpsControl.enabled = YES;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑 - 我肯定在Photo视图中关闭会话,这是代码.我确认在离开Photo视图控制器时正在调用它.
NSLog(@"RELEASE PHOTO SESSION NOW!");
for(AVCaptureInput *input1 in _mySesh.inputs) {
[_mySesh removeInput:input1];
}
for(AVCaptureOutput *output1 in _mySesh.outputs) {
[_mySesh removeOutput:output1];
}
[_mySesh stopRunning];
// Fix closing of session
dispatch_after(
dispatch_time(0,500000000),
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
_mySesh = nil;
}
);
Run Code Online (Sandbox Code Playgroud)
更新#####
根据下面的唯一答案,我试图在开始录制之前"取消链接"文件.它仍然无法正常工作.
NSURL *fileURL = [NSURL URLWithString:[@"file://" stringByAppendingString:filePath]];
//NSLog(@"Beginning to record to output file...");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// Wait for session to start
//[NSThread sleepForTimeInterval:1.0];
dispatch_async(dispatch_get_main_queue(), ^{
// Ensure session is running
if ( [self.captureSession isRunning] == NO ) {
NSLog(@"Capture session is NOT running... Starting it now!");
[self.captureSession startRunning];
}
else {
NSLog(@"Capture session is ALREADY running...");
}
NSLog(@"File URL is: %@",fileURL);
NSLog(@"FileOutput is: %@",self.fileOutput);
// Delete the file
unlink([[@"file://" stringByAppendingString:filePath] UTF8String]);
[self.fileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];
});
});
Run Code Online (Sandbox Code Playgroud)
UPDATE
仅仅为后代,我称之为'didFinishRecordingToOutputFileAtURL'委托方法:
- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections error:(NSError *)error
{
// Print any errors
if ( error ) {
NSLog(@"Error Recording Video! %@",error.localizedDescription);
}
_isRecording = NO;
if ([self.delegate respondsToSelector:@selector(didFinishRecordingToOutputFileAtURL:error:)]) {
[self.delegate didFinishRecordingToOutputFileAtURL:outputFileURL error:error];
}
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这是由于该文件已经存在。
尝试在调用startRecordingToOutputFileURL:with 之前删除文件:
[[NSFileManager defaultManager] removeItemAtPath:fileURL];
您可以仔细检查:
[[NSFileManager defaultManager] fileExistsAtPath:fileURL];
If a file at the given URL already exists when capturing starts, recording to the new file will fail.
可能导致崩溃的另一件事是如果您没有实现委托方法。
需要实施:
captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:
因为这是获得输出的唯一可靠的地方。
还有一件可疑的事:
当你创造时fileURL,你就做
NSURL *fileURL = [NSURL URLWithString:[@"file://" stringByAppendingString:filePath]];
Run Code Online (Sandbox Code Playgroud)
你能把它改成
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
Run Code Online (Sandbox Code Playgroud)
并确保filePath有效。
从文档中:This method throws an NSInvalidArgumentException if the URL is not a valid file URL.