Weird bug with AVCaptureSession

天涯浪子 提交于 2019-12-23 00:25:42

问题


I use the following code to set up an AVCaptureSession, record a video file, and play it back: Sometimes this works just fine, and other times I get a black screen on playback. As far as I can tell it's completely random.

When the bug happens, if I try to open the file in quicktime, i get a "file cannot be opened, format not recognized" message. This leads me to believe its a recording issue rather than a playback issue.

Also, if comment out the part of the code which adds the microphone input, the bug does not occur (but my video file doesn't have an audio track of course)...so maybe the audio feed randomly corrupts the file for some reason?

- (void)viewDidLoad {
[super viewDidLoad];

....

captureSession = [[AVCaptureSession alloc] init];
[captureSession setSessionPreset:AVCaptureSessionPresetHigh];

NSArray *devices = [AVCaptureDevice devices];
AVCaptureDevice *frontCamera;
AVCaptureDevice *mic = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];

for (AVCaptureDevice *device in devices) {

    NSLog(@"Device name: %@", [device localizedName]);

    if ([device hasMediaType:AVMediaTypeVideo]) 
    {
        if ([device position] == AVCaptureDevicePositionFront) {
            NSLog(@"Device position : front");
            frontCamera = device;
        }
    }
}

NSError *error = nil;

AVCaptureDeviceInput * microphone_input = [AVCaptureDeviceInput deviceInputWithDevice:mic error:&error];

AVCaptureDeviceInput *frontFacingCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:frontCamera error:&error];

if (!error) 
{
    if ([captureSession canAddInput:frontFacingCameraDeviceInput])
    {
        [captureSession addInput:frontFacingCameraDeviceInput];
    }

    if([captureSession canAddInput:microphone_input])
    {
        [captureSession addInput:microphone_input];
    }

}
[captureSession startRunning];
}

When record is pressed, I record to a "movie.mov" file with:

movieOutput = [[AVCaptureMovieFileOutput alloc]init];
[captureSession addOutput:movieOutput];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pathString = [documentsDirectory stringByAppendingPathComponent:@"movie.mov"];
NSURL *pathUrl = [NSURL fileURLWithPath:pathString];

[movieOutput startRecordingToOutputFileURL:pathUrl recordingDelegate:self];

And when play is pressed, I play back the movie file with:

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pathString = [documentsDirectory stringByAppendingPathComponent:@"movie.mov"];
NSURL *pathUrl = [NSURL fileURLWithPath:pathString];

mPlayer = [AVPlayer playerWithURL:pathUrl];

[self.video setPlayer:self.mPlayer];
[video setVideoFillMode:@"AVLayerVideoGravityResizeAspectFill"];
[self.mPlayer play];

Ive been at this for a while now and can't figure it out, it really is very random. Any help is appreciated!

EDIT: If the movie.mov file already exists, I delete it before starting the new recording.

EDIT2: Could it have something to do with the line: [movieOutput startRecordingToOutputFileURL:pathUrl recordingDelegate:self]; Xcode gives me a "Sending ViewController *const_strong 'to parameter of incompatible type 'id'" warning on this line

EDIT3: Problem solved, will post answer shortly. Thanks!


回答1:


I think I've figured it out:

The AVCaptureMovieFileOutput class has a movieFragmentInterval variable which defaults to 10. So every 10 seconds, a "sample table" is written to the quicktime file. Without a sample table the file is unreadable.

When I tested this all of my recordings were pretty short, so it seems like the bug happened whenever a sample table wasnt written out to the file. That's weird because I assumed when i call [movieOutput stopRecording] that this would write out the sample table, but I guess it didnt. When I lower the fragmentInterval to 5 seconds with:

CMTime fragmentInterval = CMTimeMake(5,1);

[movieOutput setMovieFragmentInterval:fragmentInterval];
[movieOutput startRecordingToOutputFileURL:pathUrl recordingDelegate:self];

The bug seems to have dissapeared. Im still unsure why the error only happened whenever the mic was added as an input device though.




回答2:


Call this before recording,

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];

and this before playback,

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

I think it should help considering you do not experience any issues unless trying to record audio.

Since you are using the same URL every time, you should delete it first

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pathString = [documentsDirectory stringByAppendingPathComponent:@"movie.mov"];
NSURL *pathUrl = [NSURL fileURLWithPath:pathString];
[[NSFileManager defaultManager] removeItemAtURL:pathUrl error:nil];
[movieOutput startRecordingToOutputFileURL:pathUrl recordingDelegate:self];



回答3:


You should set the fragmentInterval property of AVCaptureMovieFileOutput to a a higher limit. By default it is 10 sec.

I also had the same issue of my video recording using AVCaptureSession anything above 10 sec was not getting audio recorded. When i set the fragment interval to 300 sec which is the maximum second I allow to take video , and it recorded with audio.

AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
CMTime fragmentInterval = CMTimeMake(300,1);

[aMovieFileOutput setMovieFragmentInterval:fragmentInterval];



回答4:


Its a repeat answer, but adding this to help someone starting out in ios like me, I tried KCMTimeInvalid but it just wasn't working for me. One frazzled hour later, I realised that I am setting movieFragmentInterval after calling startRecordingToOutputFileURL.

So for newbies who type blindly like me - keep the logical and very obvious sequence in mind

videoFileOutput.movieFragmentInterval = kCMTimeInvalid
videoFileOutput.startRecordingToOutputFileURL(filePath, recordingDelegate: recordingDelegate)


来源:https://stackoverflow.com/questions/10543180/weird-bug-with-avcapturesession

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!