9

入力データを再エンコードしないように指定するために辞書をAVAssetWriterInput渡すことができるiOS ドキュメントで気付きました。niloutputSettings

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

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

NALユニットを適切にパッケージ化するにはどうすればよいCMSampleBuffersですか? 開始コードのプレフィックスを使用する必要がありますか? 長さのプレフィックス?1 つにつき NAL を 1 つだけ配置する必要がありCMSampleBufferますか? 私の最終目標は、H264/AAC で MP4 または MOV コンテナーを作成することです。

これが私が遊んでいるコードです:

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

実際に追加しようとする前に、有効な時間と思われるメソッドCMSampleBufferSetOutputPresentationTimeStamp内のサンプルバッファーを呼び出していることに注意してください。writeSampleBuffer

どんな助けでも大歓迎です。

4

1 に答える 1

3

ビデオの再生は VLC で動作させることができましたが、QuickTime では動作しませんでした。上記の投稿と同様のコードを使用して、H.264 NAL を CMSampleBuffer に取得しました。

私は2つの主な問題を抱えていました:

  1. CMSampleTimingInfo を正しく設定していませんでした (上記のコメントが述べているように)。
  2. 生のNALデータを正しくパックしていませんでした(どこに文書化されているかわかりません)。

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

#2を解決するために、試行錯誤の結果、NALユニットを次の形式で指定するとうまくいくことがわかりました。

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

各 NAL ユニットの前に 32 ビットの開始コードが0x00000001.

おそらくQuickTimeで再生されないのと同じ理由で、結果の.movファイルをフォトアルバムに移動するのにまだ問題があります(このALAssetLibrary方法videoAtPathIsCompatibleWithSavedPhotosAlbumは「ムービーを再生できませんでした」と言って失敗しています。コメントすることができます. ありがとう!

于 2013-03-27T02:34:22.427 に答える