这code通过AVAssetWriter和AVAssetWriterInputs工作不写图像+声音。为什么? [英] This code to write video+audio through AVAssetWriter and AVAssetWriterInputs is not working. Why?

查看:915
本文介绍了这code通过AVAssetWriter和AVAssetWriterInputs工作不写图像+声音。为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在试图编写使用AVAssetWriter和AVAssetWriterInputs视频+音频。

I've been trying to write a video+audio using AVAssetWriter and AVAssetWriterInputs.

我看了这个论坛的人说他们是能够完成的多个职位,但它不是为我工作。
如果我只是写视频,然后在code为做它的工作非常出色。当我添加音频输出文件被损坏,无法复制。

I read multiple posts in this forum of people saying they were able to accomplish that, but it is not working for me. If I just write video then the code is doing its job very well. When I add audio the output file is corrupted and cannot be reproduced.

下面是我的code的一部分:

Here is part of my code:

设置AVCaptureVideoDataOutput和AVCaptureAudioDataOutput:

Setting up AVCaptureVideoDataOutput and AVCaptureAudioDataOutput:

 NSError *error = nil;

 // Setup the video input
 AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
 // Create a device input with the device and add it to the session.
 AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
 // Setup the video output
 _videoOutput = [[AVCaptureVideoDataOutput alloc] init];
 _videoOutput.alwaysDiscardsLateVideoFrames = NO;
 _videoOutput.videoSettings =
 [NSDictionary dictionaryWithObject:
  [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];     

 // Setup the audio input
 AVCaptureDevice *audioDevice     = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeAudio];
 AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error ];     
 // Setup the audio output
 _audioOutput = [[AVCaptureAudioDataOutput alloc] init];

    // Create the session
 _capSession = [[AVCaptureSession alloc] init];
 [_capSession addInput:videoInput];
 [_capSession addInput:audioInput];
 [_capSession addOutput:_videoOutput];
 [_capSession addOutput:_audioOutput];

 _capSession.sessionPreset = AVCaptureSessionPresetLow;     

 // Setup the queue
 dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL);
    [_videoOutput setSampleBufferDelegate:self queue:queue];
 [_audioOutput setSampleBufferDelegate:self queue:queue];
     dispatch_release(queue);

设置AVAssetWriter以及音频和视频AVAssetWriterInputs它关联:

Setting up AVAssetWriter and associating both audio and video AVAssetWriterInputs to it:

-(BOOL) setupWriter{
 NSError *error = nil;
 _videoWriter = [[AVAssetWriter alloc] initWithURL:videoURL fileType:AVFileTypeQuickTimeMovie
                                                        error:&error];
 NSParameterAssert(_videoWriter);


 // Add video input
 NSDictionary *videoCompressionProps = [NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSNumber numberWithDouble:128.0*1024.0], AVVideoAverageBitRateKey,
                                                      nil ];

 NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                            AVVideoCodecH264, AVVideoCodecKey,
                                            [NSNumber numberWithInt:192], AVVideoWidthKey,
                                            [NSNumber numberWithInt:144], AVVideoHeightKey,
                                            videoCompressionProps, AVVideoCompressionPropertiesKey,
                                            nil];

 _videoWriterInput = [[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                 outputSettings:videoSettings] retain];


 NSParameterAssert(_videoWriterInput);
 _videoWriterInput.expectsMediaDataInRealTime = YES;


 // Add the audio input
 AudioChannelLayout acl;
 bzero( &acl, sizeof(acl));
 acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;


 NSDictionary* audioOutputSettings = nil;          
 // Both type of audio inputs causes output video file to be corrupted.
 if( NO ) {
      // should work from iphone 3GS on and from ipod 3rd generation
      audioOutputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                            [ NSNumber numberWithInt: kAudioFormatMPEG4AAC ], AVFormatIDKey,
                                   [ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,
                            [ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
                            [ NSNumber numberWithInt: 64000 ], AVEncoderBitRateKey,
                            [ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey,
                            nil];
 } else {
      // should work on any device requires more space
      audioOutputSettings = [ NSDictionary dictionaryWithObjectsAndKeys:                       
                            [ NSNumber numberWithInt: kAudioFormatAppleLossless ], AVFormatIDKey,
                                  [ NSNumber numberWithInt: 16 ], AVEncoderBitDepthHintKey,
                            [ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
                            [ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,                                      
                            [ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey,
                               nil ];
 } 

 _audioWriterInput = [[AVAssetWriterInput 
                          assetWriterInputWithMediaType: AVMediaTypeAudio 
                outputSettings: audioOutputSettings ] retain];

      _audioWriterInput.expectsMediaDataInRealTime = YES;



 // add input
 [_videoWriter addInput:_videoWriterInput];
 [_videoWriter addInput:_audioWriterInput];

 return YES;}

下面是功能开始/停止视频录制

here are functions to start/stop video recording

-(void) startVideoRecording
{
         if( !_isRecording )
         {
              NSLog(@"start video recording...");
              if( ![self setupWriter] )
                   return;

              _isRecording = YES;
         }
    }

-(void) stopVideoRecording
{
         if( _isRecording )
         {
              _isRecording = NO;

              [_videoWriterInput markAsFinished];
              [_videoWriter endSessionAtSourceTime:lastSampleTime];

              [_videoWriter finishWriting];

              NSLog(@"video recording stopped");
         }
    }

和最后CaptureOutput code

And finally the CaptureOutput code

    - (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
        fromConnection:(AVCaptureConnection *)connection
{
     if( !CMSampleBufferDataIsReady(sampleBuffer) )
     {
          NSLog( @"sample buffer is not ready. Skipping sample" );
          return;
     }


     if( _isRecording == YES )
     {
          lastSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
                if( _videoWriter.status != AVAssetWriterStatusWriting  )
          {
               [_videoWriter startWriting];
               [_videoWriter startSessionAtSourceTime:lastSampleTime];
          }

          if( captureOutput == _videoOutput )
               [self newVideoSample:sampleBuffer];

                /*
                // If I add audio to the video, then the output file gets corrupted and it cannot be reproduced
          else
               [self newAudioSample:sampleBuffer];
                */
     }
}

-(void) newVideoSample:(CMSampleBufferRef)sampleBuffer
{     
     if( _isRecording )
     {
          if( _videoWriter.status > AVAssetWriterStatusWriting )
          {
               NSLog(@"Warning: writer status is %d", _videoWriter.status);
               if( _videoWriter.status == AVAssetWriterStatusFailed )
                    NSLog(@"Error: %@", _videoWriter.error);
               return;
          }

          if( ![_videoWriterInput appendSampleBuffer:sampleBuffer] )
               NSLog(@"Unable to write to video input");

     }

}



-(void) newAudioSample:(CMSampleBufferRef)sampleBuffer

{     
     if( _isRecording )
     {
          if( _videoWriter.status > AVAssetWriterStatusWriting )
          {
               NSLog(@"Warning: writer status is %d", _videoWriter.status);
               if( _videoWriter.status == AVAssetWriterStatusFailed )
                    NSLog(@"Error: %@", _videoWriter.error);
               return;
          }

          if( ![_audioWriterInput appendSampleBuffer:sampleBuffer] )
               NSLog(@"Unable to write to audio input");

     }

我将非常高兴,如果有人能找到它在这个code中的问题。

I would be very glad if someone could find which is the problem in this code.

推荐答案

在startVideoRecording我打电话(我假设你在某些时候调用这个)

In startVideoRecording I call (I assume you are calling this at some point)

[_capSession startRunning] ;

在stopVideoRecording我不叫

In stopVideoRecording I do not call

[_videoWriterInput markAsFinished];
[_videoWriter endSessionAtSourceTime:lastSampleTime];

该markAsFinished则多为与块式拉法使用。见requestMediaDataWhenReadyOnQueue:usingBlock在AVAssetWriterInput一个解释。图书馆应计算交织缓冲区适当的时机。

The markAsFinished is more for use with the block style pull method. See requestMediaDataWhenReadyOnQueue:usingBlock in AVAssetWriterInput for an explanation. The library should calculate the proper timing for interleaving the buffers.

您不需要调用endSessionAtSrouceTime。在样本数据的最后一个时间标记将在调用之后使用

You do not need to call endSessionAtSrouceTime. The last time stamp in the sample data will be used after the call to

[_videoWriter finishWriting];

我也明确地检查捕获的输出类型。

I also explicitly check for the type of capture output.

else if( captureOutput == _audioOutput) {
    [self newAudioSample:sampleBuffer]; 
}

下面是我。音频和视频,我来通过。这是可能的,我改变一些东西。如果这不会为你工作,那么我会后我的一切。

Here is what I have. The audio and video come through for me. It is possible I changed something. If this does not work for you then I will post everything I have.

-(void) startVideoRecording
    {
        if( !_isRecording )
         {
            NSLog(@"start video recording...");
            if( ![self setupWriter] ) {
                NSLog(@"Setup Writer Failed") ;

                return;
            }

            [_capSession startRunning] ;
            _isRecording = YES;
         }
    }

    -(void) stopVideoRecording
    {
        if( _isRecording )
         {
            _isRecording = NO;

            [_capSession stopRunning] ;

            if(![_videoWriter finishWriting]) { 
                NSLog(@"finishWriting returned NO") ;
            }
            //[_videoWriter endSessionAtSourceTime:lastSampleTime];
            //[_videoWriterInput markAsFinished];
            //[_audioWriterInput markAsFinished];

            NSLog(@"video recording stopped");
         }
    }

这篇关于这code通过AVAssetWriter和AVAssetWriterInputs工作不写图像+声音。为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆