2010-11-10 11 views
57

मैं AVAssetWriter और AVAssetWriterInputs का उपयोग कर एक वीडियो + ऑडियो लिखने की कोशिश कर रहा हूं।AVAssetWriter और AVAssetWriterInputs के माध्यम से वीडियो + ऑडियो लिखने के लिए यह कोड काम नहीं कर रहा है। क्यूं कर?

मैंने लोगों के इस मंच में कई पोस्ट पढ़ीं कि वे इसे पूरा करने में सक्षम थे, लेकिन यह मेरे लिए काम नहीं कर रहा है। अगर मैं सिर्फ वीडियो लिखता हूं तो कोड अपना काम बहुत अच्छी तरह से कर रहा है। जब मैं ऑडियो जोड़ता हूं तो आउटपुट फ़ाइल दूषित हो जाती है और इसे पुन: उत्पन्न नहीं किया जा सकता है।

AVCaptureVideoDataOutput और 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 जोड़: यहाँ

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

कर रहे हैं वीडियो रिकॉर्डिंग शुरू/बंद करने के लिए कार्य

- (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 कोड

- (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"); 
     } 
    } 
} 

मैं अगर किसी को मिल सकता है जो इस कोड में समस्या बहुत खुशी होगी।

+0

मुझे आपके ऑडियो सेटिंग के साथ कोड के साथ बहुत ही समस्याएं आ रही हैं। मेरा ऐप वीडियो रिकॉर्ड करेगा, लेकिन जैसे ही मैं AVAssetWritterInput को बताता हूं, मैंने ऑडियो को एपेंड करने के लिए बनाया है नमूनाबफर: यह मुझे बताता है कि आउटपुट बफर एक असम्पीडित प्रारूप में होना चाहिए जब आउटपुट सेटिंग्स नील हो।क्या आप कभी इस समस्या से आए थे? यह मेरी छोटी नट चला रहा है! – Baza207

+1

हैलो कालोस, आपके उदाहरण में ऑडियो इनपुट माइक्रोफ़ोन या एप्लिकेशन से ही है? – justicepenny

+0

@ kalos भाई क्या आप मुझे बता सकते हैं कि हम videoURL का उपयोग कैसे कर सकते हैं। – morroko

उत्तर

23

startVideoRecording में मैं फोन

[_capSession startRunning] ; 

stopVideoRecording में मैं कॉल नहीं करते

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

markAsFinished ब्लॉक शैली खींच के साथ उपयोग के लिए अधिक है (मैं तुम्हें कुछ बिंदु पर इस बुला रहे हैं मान) तरीका। RequestMediaDataWhenReadyOnQueue देखें: एक स्पष्टीकरण के लिए AVAssetWriterInput में ब्लॉक का उपयोग करें। लाइब्रेरी को बफर को अंतःस्थापित करने के लिए उचित समय की गणना करनी चाहिए।

आपको endSessionAtSrouceTime को कॉल करने की आवश्यकता नहीं है। नमूना डेटा में पिछली बार टिकट मैं भी स्पष्ट रूप से कब्जा उत्पादन के प्रकार के लिए जाँच

[_videoWriter finishWriting]; 

करने के लिए कॉल के बाद इस्तेमाल किया जाएगा।

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

यहां मेरे पास है। ऑडियो और वीडियो मेरे लिए आते हैं। यह संभव है कि मैंने कुछ बदल दिया। यदि यह आपके लिए काम नहीं करता है तो मैं अपनी सारी चीज़ें पोस्ट करूंगा।

-(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"); 
     } 
    } 
+1

आपको बहुत धन्यवाद स्टीव, आपके संकेत बहुत उपयोगी थे। अब वीडियो रिकॉर्डिंग भी ऑडियो है! – kalos

+2

@ स्टेव और कालोस क्या आप सही कामकाजी कोड दे सकते हैं जहां ऑडियो और वीडियो दोनों रिकॉर्ड करना संभव है? – sach

+0

आप डब्ल्यूडब्ल्यूडीसी 2010 नमूना कोड से AVCamDemo पर एक नज़र डालना चाहते हैं। –

6

सबसे पहले, [NSNumber numberWithInt: kCVPixelFormatType_32BGRA] का उपयोग न करें, क्योंकि यह कैमरे का मूल प्रारूप नहीं है। [NSNumber संख्या WithInt: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange]

इसके अलावा, आपको हमेशा कॉल करने से पहले जांचना चाहिए कि यह पहले से चल रहा है। आपको सत्र समाप्ति समय सेट करने की आवश्यकता नहीं है, क्योंकि StopWriting ऐसा करेगा।

+1

kCVPixelFormatType_32BGRA के साथ क्या गलत है? यदि आप देशी प्रारूप का उपयोग करते हैं, तो संभवतया आप बीजीआरए को शेडर्स के माध्यम से परिवर्तित कर देते हैं, जो शायद बीजीआरए निर्दिष्ट करते समय ऐप्पल आपके लिए करता है ... – jjxtra

संबंधित मुद्दे