AVCaptureMovieFileOutput NSInvalidArgumentException没有活动/启用的连接

时间:2014-05-18 21:09:57

标签: ios objective-c cocoa avfoundation avcapturesession

当我开始在NSInvalidArgumentException中录制视频但仅在以前的视图控制器中拍摄照片后,我偶尔会遇到viewController异常。我已尝试过Google及其他几项建议,但仍然会在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];

        });

以下是错误追溯:

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的初始化方式(来自这里的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;
}

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

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;

    }
}

编辑 - 我肯定在Photo视图中关闭会话,这是代码。我确认在离开Photo View控制器时正在调用它。

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

        );
更新#####

根据下面的唯一答案,我尝试在开始录制之前“取消链接”文件。它仍然无效。

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

}

4 个答案:

答案 0 :(得分:4)

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

其次,在向捕获会话添加任何内容之前使用-[AVCaptureSession canAddOutput:]-[AVCaptureSession canAddInput:],这将为您节省大量时间和挫折。

第三,当您想要立即更改captureSession中的大量内容时,您只需要beginConfigurationcommitConfiguration,例如删除输入,更改预设。如果您要实现它,它在前/后摄像头开关上很有用。在这些调用之间启动或停止会话绝不是简单的。

答案 1 :(得分: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.

答案 2 :(得分:0)

尝试评论self.captureSession.sessionPreset = ...行,看看是否有帮助。它成了我的伎俩。问题的原因是我试图捕获具有最高质量和FOV的照片,但是当我尝试捕获视频时,我在这个设置中得到“没有活动/启用连接”异常。

答案 3 :(得分:0)

只需将sessionPreset设置为高。

迅捷4 self.captureSession.sessionPreset = .high