播放电影停止 avcapturesession 录制

Posted

技术标签:

【中文标题】播放电影停止 avcapturesession 录制【英文标题】:playing a movie stops avcapturesession recording 【发布时间】:2012-09-20 10:08:47 【问题描述】:

我有一个 ios 应用,可以在后台录制前置摄像头的视频,并且运行良好。但现在我正在尝试同时播放一个简短的 mp4,并且使用 MPMoviePlayerController 播放会停止捕获会话。

我尝试了 AVPlayer,但结果相同。 我还设置了 [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; 仍然没有运气。有没有人遇到并解决了同样的问题。 感谢您的任何建议。

使用 ios5 SDK。

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIButton *recButton=[[UIButton alloc] initWithFrame:CGRectMake(10,200, 200,40)] ;
    recButton.backgroundColor = [UIColor blackColor];
    [recButton addTarget:self action:@selector(startRecording) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:recButton];
    isRecording=NO;


- (void)viewDidUnload

    [super viewDidUnload];
    // Release any retained subviews of the main view.


-(void) viewWillAppear:(BOOL)animated

    self.navigationController.navigationBarHidden = YES;


-(void) viewWillDisappear:(BOOL)animated

        self.navigationController.navigationBarHidden = NO;


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) 
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
     else 
        return YES;
    


#pragma mark video playing
-(void) startRecording

    if (isRecording) 
        [self stopVideoRecording];
        isRecording=NO;
    
    else
    
        [self initCaptureSession];
        [self startVideoRecording];
        isRecording=YES;
    


    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
                                         pathForResource:@"new"
                                         ofType:@"mov"]];
    [self playMovieAtURL:url];


-(void) playMovieAtURL: (NSURL*) theURL 

    player =
    [[MPMoviePlayerController alloc] initWithContentURL: theURL ];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

    player.scalingMode = MPMovieScalingModeAspectFill;
    player.controlStyle = MPMovieControlStyleNone;
    [player prepareToPlay];
    // Register for the playback finished notification
    [[NSNotificationCenter defaultCenter]
     addObserver: self
     selector: @selector(myMovieFinishedCallback:)
     name: MPMoviePlayerPlaybackDidFinishNotification
     object: player];
    [player.view setFrame: self.view.bounds];
    [self.view addSubview:player.view];
    // Movie playback is asynchronous, so this method returns immediately.
    [player play];


// When the movie is done, release the controller.
-(void) myMovieFinishedCallback: (NSNotification*) aNotification

    MPMoviePlayerController* theMovie = [aNotification object];

    [[NSNotificationCenter defaultCenter]
     removeObserver: self
     name: MPMoviePlayerPlaybackDidFinishNotification
     object: theMovie];
    [player.view removeFromSuperview];
    [self stopVideoRecording];


#pragma mark -

#pragma mark recording

-(void) initCaptureSession

    NSLog(@"Setting up capture session");
    captureSession = [[AVCaptureSession alloc] init];
    //----- ADD INPUTS -----
    NSLog(@"Adding video input");

    //ADD VIDEO INPUT
    AVCaptureDevice *VideoDevice =  [self frontFacingCameraIfAvailable ];

    //[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    if (VideoDevice)
    
        NSError *error;
        videoInputDevice = [AVCaptureDeviceInput deviceInputWithDevice:VideoDevice error:&error];
        if (!error)
        
            if ([captureSession canAddInput:videoInputDevice])
                [captureSession addInput:videoInputDevice];
            else
                NSLog(@"Couldn't add video input");
        
        else
        
            NSLog(@"Couldn't create video input");
        
    
    else
    
        NSLog(@"Couldn't create video capture device");
    

    //ADD AUDIO INPUT
    NSLog(@"Adding audio input");
    AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    NSError *error = nil;
    AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error];
    if (audioInput)
    

        [captureSession addInput:audioInput];
    

    //----- ADD OUTPUTS ---
    //ADD MOVIE FILE OUTPUT
    NSLog(@"Adding movie file output");
    movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];

//  Float64 TotalSeconds = 60;          //Total seconds
//  int32_t preferredTimeScale = 30;    //Frames per second
//  CMTime maxDuration = CMTimeMakeWithSeconds(TotalSeconds, preferredTimeScale);   //<<SET MAX DURATION
//  movieFileOutput.maxRecordedDuration = maxDuration;

    movieFileOutput.minFreeDiskSpaceLimit = 1024 * 1024;    //<<SET MIN FREE SPACE IN BYTES FOR RECORDING TO CONTINUE ON A VOLUME

    if ([captureSession canAddOutput:movieFileOutput])
        [captureSession addOutput:movieFileOutput];

    //SET THE CONNECTION PROPERTIES (output properties)
    [self CameraSetOutputProperties];           //(We call a method as it also has to be done after changing camera)

    //----- SET THE IMAGE QUALITY / RESOLUTION -----
    //Options:
    //  AVCaptureSessionPresetHigh - Highest recording quality (varies per device)
    //  AVCaptureSessionPresetMedium - Suitable for WiFi sharing (actual values may change)
    //  AVCaptureSessionPresetLow - Suitable for 3G sharing (actual values may change)
    //  AVCaptureSessionPreset640x480 - 640x480 VGA (check its supported before setting it)
    //  AVCaptureSessionPreset1280x720 - 1280x720 720p HD (check its supported before setting it)
    //  AVCaptureSessionPresetPhoto - Full photo resolution (not supported for video output)
    NSLog(@"Setting image quality");
    [captureSession setSessionPreset:AVCaptureSessionPresetMedium];
    if ([captureSession canSetSessionPreset:AVCaptureSessionPreset640x480])     //Check size based configs are supported before setting them
        [captureSession setSessionPreset:AVCaptureSessionPreset640x480];
    //----- START THE CAPTURE SESSION RUNNING -----
    [captureSession startRunning];


//********** CAMERA SET OUTPUT PROPERTIES **********
- (void) CameraSetOutputProperties

    AVCaptureConnection *CaptureConnection=nil;
    //SET THE CONNECTION PROPERTIES (output properties)
    NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare: @"5.0.0" options: NSNumericSearch];
    if (order == NSOrderedSame || order == NSOrderedDescending) 
        // OS version >= 5.0.0
        CaptureConnection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
//        if (CaptureConnection.supportsVideoMinFrameDuration)
//            CaptureConnection.videoMinFrameDuration = CMTimeMake(1, CAPTURE_FRAMES_PER_SECOND);
//        if (CaptureConnection.supportsVideoMaxFrameDuration)
//            CaptureConnection.videoMaxFrameDuration = CMTimeMake(1, CAPTURE_FRAMES_PER_SECOND);
//        if (CaptureConnection.supportsVideoMinFrameDuration)
//        
//           // CMTimeShow(CaptureConnection.videoMinFrameDuration);
//           // CMTimeShow(CaptureConnection.videoMaxFrameDuration);
//        
     else 
        // OS version < 5.0.0
        CaptureConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[movieFileOutput connections]];

    


    //Set landscape (if required)
    if ([CaptureConnection isVideoOrientationSupported])
    
        AVCaptureVideoOrientation orientation =  AVCaptureVideoOrientationPortrait;// AVCaptureVideoOrientationLandscapeRight;      //<<<<<SET VIDEO ORIENTATION IF LANDSCAPE
        [CaptureConnection setVideoOrientation:orientation];
    

    //Set frame rate (if requried)
    //CMTimeShow(CaptureConnection.videoMinFrameDuration);
    //CMTimeShow(CaptureConnection.videoMaxFrameDuration);



- (void) startVideoRecording

        //Create temporary URL to record to
        NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"];
        NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
        NSFileManager *fileManager = [NSFileManager defaultManager];
        if ([fileManager fileExistsAtPath:outputPath])
        
            NSError *error;
            if ([fileManager removeItemAtPath:outputPath error:&error] == NO)
            
                //Error - handle if requried
                NSLog(@"file remove error");
            
        
        //Start recording
        [movieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];



-(void) stopVideoRecording

    [movieFileOutput stopRecording];


//********** DID FINISH RECORDING TO OUTPUT FILE AT URL **********/
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
      fromConnections:(NSArray *)connections
                error:(NSError *)error


    NSLog(@"didFinishRecordingToOutputFileAtURL - enter");

    BOOL RecordedSuccessfully = YES;
    if ([error code] != noErr)
    
        // A problem occurred: Find out if the recording was successful.
        id value = [[error userInfo] objectForKey:AVErrorRecordingSuccessfullyFinishedKey];
        if (value)
        
            RecordedSuccessfully = [value boolValue];
        
    
    if (RecordedSuccessfully)
    
        //----- RECORDED SUCESSFULLY -----
        NSLog(@"didFinishRecordingToOutputFileAtURL - success");
        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
        if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputFileURL])
        
            [library writeVideoAtPathToSavedPhotosAlbum:outputFileURL
                                        completionBlock:^(NSURL *assetURL, NSError *error)
             
                 if (error)
                 
                     NSLog(@"File save error");
                 
                 else
                 
                     recordedVideoURL=assetURL;
                 
             ];
        
        else 

            NSString *assetURL=[self copyFileToDocuments:outputFileURL];
            if(assetURL!=nil)
            
                recordedVideoURL=[NSURL URLWithString:assetURL];
            
        
    


- (NSString*) copyFileToDocuments:(NSURL *)fileURL

    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd_HH-mm-ss"];
    NSString *destinationPath = [documentsDirectory stringByAppendingFormat:@"/output_%@.mov", [dateFormatter stringFromDate:[NSDate date]]];
    NSError *error;
    if (![[NSFileManager defaultManager] copyItemAtURL:fileURL toURL:[NSURL fileURLWithPath:destinationPath] error:&error]) 
        NSLog(@"File save error %@", [error localizedDescription]);
        return nil;

    
    return destinationPath;


- (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections

    for ( AVCaptureConnection *connection in connections ) 
        for ( AVCaptureInputPort *port in [connection inputPorts] ) 
            if ( [[port mediaType] isEqual:mediaType] ) 
                return connection;
            
        
    
    return nil;


- (AVCaptureDevice *)frontFacingCameraIfAvailable

    //  look at all the video devices and get the first one that's on the front
    NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    AVCaptureDevice *captureDevice = nil;
    for (AVCaptureDevice *device in videoDevices)
    
        if (device.position == AVCaptureDevicePositionFront)
        
            captureDevice = device;
            break;
        
    

    //  couldn't find one on the front, so just get the default video device.
    if ( ! captureDevice)
    
        captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    

    return captureDevice;

#pragma mark -

@end

【问题讨论】:

【参考方案1】:

我也有这个问题,不知道怎么解决,但我知道问题出在这里:

[captureSession addInput:audioInput];

如果你删除这行代码,它会正常工作,我认为是音频混合或一些音频问题。

我还在寻找答案。

我在这里找到了答案:answer,它有效!

但你记得加AudioToolbox.framework,也许对你有帮助。

【讨论】:

以上是关于播放电影停止 avcapturesession 录制的主要内容,如果未能解决你的问题,请参考以下文章

当音频输入添加到 AVCaptureSession 时 AVAudioPlayer 停止

如何停止播放电影?

停止在电影XNA结束时播放视频

当用户尝试全屏播放时,MPMoviePlayerController 停止并重置电影 [iOS]

如何记录使用 AVCaptureSession 捕获的第一个和最后一个电影帧的确切时间?

电影播放器​​不会在表格单元格中停止