2013-03-26 9 views
7

AVAssetWriterInputのiOSドキュメントで、niloutputSettingsディクショナリに入力データを再エンコードしないよう指定することができます。生のNALユニットでAVAssetWriterを使用

出力に追加されたメディアのエンコードに使用される設定。追加されたサンプルを再エンコードしないように指定するには、nilを渡します。

私は生のH.264のNALのストリームに渡すためにこの機能を利用したいが、私はAVAssetWriterInputのappendSampleBufferメソッドに渡すことができ、トラブルCMSampleBufferに私の生のバイトストリームを適応を持っています。私のNALストリームには、SPS/PPS/IDR/P NAL(1,5,7,8)のみが含まれています。 AVAssetWriterで事前にエンコードされたH264データを使用する方法に関するドキュメントや決定的な回答は見つかりませんでした。結果のビデオファイルは再生できません。

NALユニットを正しくCMSampleBuffersにパッケージ化するにはどうすればよいですか?スタートコードプレフィックスを使用する必要がありますか?長さ接頭辞? CMSampleBufferごとにNALを1つだけ入れる必要がありますか?私の最終目標は、H264/AACでMP4またはMOVコンテナを作成することです。私は私が実際によ前に、有効な時間と思われるものでwriteSampleBuffer方法の内のサンプルバッファーにCMSampleBufferSetOutputPresentationTimeStampを呼んでいる

-(void)addH264NAL:(NSData *)nal 
{ 
    dispatch_async(recordingQueue, ^{ 
     //Adapting the raw NAL into a CMSampleBuffer 
     CMSampleBufferRef sampleBuffer = NULL; 
     CMBlockBufferRef blockBuffer = NULL; 
     CMFormatDescriptionRef formatDescription = NULL; 
     CMItemCount numberOfSampleTimeEntries = 1; 
     CMItemCount numberOfSamples = 1; 


     CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, 480, 360, nil, &formatDescription); 
     OSStatus result = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, NULL, [nal length], kCFAllocatorDefault, NULL, 0, [nal length], kCMBlockBufferAssureMemoryNowFlag, &blockBuffer); 
     if(result != noErr) 
     { 
      NSLog(@"Error creating CMBlockBuffer"); 
      return; 
     } 
     result = CMBlockBufferReplaceDataBytes([nal bytes], blockBuffer, 0, [nal length]); 
     if(result != noErr) 
     { 
      NSLog(@"Error filling CMBlockBuffer"); 
      return; 
     } 
     const size_t sampleSizes = [nal length]; 
     CMSampleTimingInfo timing = { 0 }; 
     result = CMSampleBufferCreate(kCFAllocatorDefault, blockBuffer, YES, NULL, NULL, formatDescription, numberOfSamples, numberOfSampleTimeEntries, &timing, 1, &sampleSizes, &sampleBuffer); 

     if(result != noErr) 
     { 
      NSLog(@"Error creating CMSampleBuffer"); 
     } 
     [self writeSampleBuffer:sampleBuffer ofType:AVMediaTypeVideo]; 
    }); 
} 

注:ここでは

は私がプレーしてきたコードですそれを追加しようとしています。

何か助けていただければ幸いです。

+0

少なくとも私の問題の一部は、どのように私がCMSampleTimingInfoを扱っていたかでした。実際のタイムスタンプを埋めるために 'setOutputPresentationTimeStamp'を使っていたと言いました。私は今、CMSampleTimingInfoの他のフィールドにも記入する必要があることを認識しています。 'decodeTimeStamp'を' kCMTimeInvalid'に、 'duration'を' CMTimeMake(1、30) 'に設定しています。私は今、適切な総時間でシーク可能なビデオコンテナを取得しますが、ビデオはありません(VLCでのテスト)。 – bsirang

答えて

3

VLCではビデオ再生ができますが、QuickTimeでは再生できませんでした。私はH.264 NALをCMSampleBuffersに入れるために上に掲示したのと同様のコードを使用しました。

は、私は2つの主要な問題を持っていた:私は正しくCMSampleTimingInfoを設定していませんでした

  1. (状態上記の私のコメントとして)。
  2. 生のNALデータを正しくパックしていませんでした(どこに書かれているか分かりません)。

#1を解決するには、timing.duration = CMTimeMake(1, fps);と設定します。ここで、fpsは予想されるフレームレートです。次に、timing.decodeTimeStamp = kCMTimeInvalid;を、デコード順でサンプルが与えられるように設定します。最後に、絶対時間を計算することによってtiming.presentationTimeStampを設定しました。これもstartSessionAtSourceTimeと一緒に使用しました。

は試行錯誤を通じて、#2を解決するために、私は次の形で私のNALユニットを与えること働いたことが判明:各NALユニットは、32ビットのスタートコードが 0x00000001に等しいによって付けられ

[7 8 5] [1] [1] [1]..... [7 8 5] [1] [1] [1]..... (repeating) 

おそらく、QuickTimeで再生していないのと同じ理由で、結果の.movファイルを写真アルバムに移動するのにまだ問題があります(ALAssetLibraryの方法videoAtPathIsCompatibleWithSavedPhotosAlbumは「ムービーを再生できませんでした」)ありがとう!

+0

これはVLCでのみ動作することを考えれば、QuickTimeが動作するためにNALをバッファにパックする方法を変更する必要があります。誰にでもアイデアはありますか? – bsirang

+0

結果のmovファイルのhexdumpを取りました。ファイルの先頭にmdatアトムが1つ、下に向かってavc1アトムが2つありますが、avcCアトムはありません。 mdatの中には、この答えで記述するNALのストリーム(0x00000001プレフィックスで区切られたストリーム)があります。私はmdatの下のデータがAnnex-Bフォーマットであり、avcCアトムが存在しないため、QuickTimeがファイルを再生するのを拒否していると仮定しています。私は、AVAssetWriterInputにデータを正しく供給する方法を理解する必要があります。 – bsirang

+0

私はすべてがうまくいくように管理しました。私はNALの長さを(0x00000001の代わりに)各NALに先行させており、avcCデータをmovコンテナに適切に渡すこともできました。私の質問と回答はこちらをご覧ください:http://stackoverflow.com/questions/15673379/avassetwriterinput-h-264-passthrough-to-quicktime-mov-passing-in-sps-pps-to/ – bsirang

関連する問題