2014-05-18 123 views
7

我偶尔会遇到NSInvalidArgumentException异常,当我开始在viewController中录制视频时,但只有在先前的视图控制器中拍摄照片后。我尝试了Google和So的一些建议,但仍然在拨打startRecordingToOutputFileURL:fileURL时遇到此错误。AVCaptureMovieFileOutput NSInvalidArgumentException没有活动/启用连接

如果我不访问拍摄照片的其他视图控制器,我就不会收到错误 - 它只发生在拍照时,然后切换到进行视频录制的新视图控制器。

我认为拍摄照片时留下了一些残留物,但是当我初始化我的视频录像机视图控制器时,我无法设置会话和其他内容。任何想法正在发生什么或如何从中恢复?为什么是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]; 

     }); 

以下是错误回溯:

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 

这是captureSession如何初始化(从开源项目位置: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; 
} 

我的代码在viewDi中使用了这样的初始化代码DLOAD:

self.captureManager = [[AVCaptureManager alloc] initWithPreviewView:self.view]; 
self.captureManager.delegate = self; 

实际启动和停止记录从一个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; 

    } 
} 

编辑 - 我肯定在图片浏览会议结束时,这里是代码。我确认它在离开照片视图控制器时被调用。

 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; 
         } 

     ); 
UPDATE #####

根据下面唯一的答案,我想“取消链接”的前开始录音文件。它仍然没有工作。

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]; 

     }); 

    }); 
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]; 
    } 

} 
+0

你的'beginConfiguration'和'commitConfiguration'是毫无意义的,因为_你没有做任何配置_。事实上,你所说的代码中没有涉及的整个问题是'self.captureSession'是如何配置的。这是什么时候完成的,完成了什么? – matt

+0

感谢您的评论 - 我已经添加更多信息的问题。 – PhilBot

+0

您确定在完成对话后正确销毁会话吗? iOS不支持多个AVCaptureSession实例。也许会话照片捕捉不会被释放。当你创建另一个会话时,它不能创建连接,因为输入端口被另一个会话实例占用。您可以亲自查看,也可以向我们展示照片和视频捕获的代码,同时分配和取消分配会话。 – creker

回答

2

从我所看到的,这是由于已经存在的文件。

尝试删除你的电话之前,文件startRecordingToOutputFileURL:[[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]]; 

您可以更改到

NSURL *fileURL = [NSURL fileURLWithPath:filePath]; 

并确保filePath是有效的。

从文档:This method throws an NSInvalidArgumentException if the URL is not a valid file URL.所有的

+0

我试过这个,但它仍然没有修复错误。感谢您的建议,但您能想到其他任何东西吗?我发布了删除代码作为对我的问题的编辑。 – PhilBot

+0

@PhilBot你可以仔细检查它的删除是否正确?在你的输出日志中,你的'filePath'已经有'file://',但是你重新添加了它。你可以用BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath]来检查文件的存在吗?只是想确定! – Jack

+0

@PhilBot如果这不起作用,你有'captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:'委托方法集?我相信如果你没有这个委托方法,它可能会崩溃。 – Jack

4

首先,先启动AVCaptureSession。之后,您可以创建AVPreviewLayer和AVCaptureMovieFileOutput。

其次,使用-[AVCaptureSession canAddOutput:]-[AVCaptureSession canAddInput:]在向捕获会话添加任何内容之前,这将为您节省大量时间和挫败感。第三,只需要beginConfigurationcommitConfiguration,当你想要一次性更改captureSession中的很多东西时,例如,你只需要使用beginConfigurationcommitConfiguration。删除输入,更改预设。如果要实施它,它对前/后摄像头切换很有用。在这些呼叫之间开始或停止会话不是bueno。

0

尝试评论self.captureSession.sessionPreset = ...行,看看是否有帮助。它为我制造了诡计。问题的原因是我试图捕获最高质量和FOV的照片,但使用此设置时,当我试图捕捉视频时,出现“无活动/启用连接”的例外情况。

+0

您是否知道在不设置预设的情况下录制视频的方法?正如苹果所建议的,有时你需要直接设置activeFormat。 –

相关问题