1

ネイティブの Annex-B H.264 ストリームを解凍するコードを書いています。ストリームを解析し、S​​PS/PPS NALU から CMVideoFormatDescription を作成し、ストリームから抽出した他の NALU をラップするプロセスを実行しています。 CMSampleBuffers で。

デコーダーの CMBlockBuffer と CMSampleBuffer メモリを処理する方法について、精神的なブロックに苦しんでいます。私の問題は、何よりもCFがメモリを処理する方法を完全に理解していないことにあると思うので、私の質問はそれに関するものですが、コンテキストが役立つことを願っています.

次のように CMBlockBuffer を作成すると:

CMBlockBufferRef blockBuffer;

OSStatus status = CMBlockBufferCreateWithMemoryBlock(NULL,
                                                     memoryBlock,                       
                                                     blockBufferLength,
                                                     kCFAllocatorNull,
                                                     NULL,
                                                     0, 
                                                     blockBufferLength,          
                                                     kCMBlockBufferAlwaysCopyDataFlag | kCMBlockBufferAssureMemoryNowFlag,
                                                     &blockBuffer);

次のように CMSampleBuffer に追加します。

CMSampleBufferRef sampleBuffer;

status = CMSampleBufferCreate(kCFAllocatorDefault,
                              blockBuffer,
                              true,
                              NULL,
                              NULL,
                              formatDescription,
                              1,
                              0,
                              NULL,
                              1,
                              &sampleSize,
                              &sampleBuffer);

ブロックバッファをどのように処理すればよいですか? SampleBuffer はブロック バッファのメモリを保持していますか、それとも割り当てが解除されていないことを確認するために何かをする必要がありますか?

また、非同期デコード プロセスに関連して、デコーダが CMSampleBuffer をいつ処理するかを知る賢明な方法はありますか?

私の直感では、CMSampleBuffer は CMBlockBuffer を保持し、VTDecodeSession はデコードが完了するまで CMSampleBuffer を保持しますが、これは文書化されていない領域であり、私がさまよっているので、方向性を探しています。私が得ている結果は、私の直感が間違っている可能性があることを暗示しているので、正気を保つために問題としてメモリ管理を除外する必要があります...

4

1 に答える 1

5

CMSampleBuffers と CMBlockBuffers (オブジェクト自体) は、典型的な CF Retain/Release セマンティクスに従います。これらのオブジェクトが必要な間は保持を保持し、それらを受け入れるインターフェイスが同じことを行うと想定する必要があります。これは、CMBlockBuffer を CMSampleBuffer に渡すとすぐに自由に解放できること、およびレンダリング チェーンに渡した後に自由に CMSampleBuffer を解放できることを意味します。

CMBlockBufferCreateWithMemoryBlock() で作成された CMBlockBuffer が指すメモリは、わずかに異なる規則に従います。まず、このメソッドは、memoryBlock が指すデータをコピーしません。そのポインターを直接使用します。これは、BlockBuffer がそのメモリの管理方法についてある程度の知識を持っている必要があることを意味します。これは、CMBlockBufferCreateWithMemoryBlock() の 4 番目または 5 番目の引数のいずれかによって処理されます。いずれかが非 kCFAllocatorNull/NULL の場合、BlockBuffer は、メモリの処理が完了すると、それらのいずれかのデアロケーターを呼び出します。これは通常、BlockBuffer の Finalize() で行われます。それらが両方とも kCFAllocatorNull/NULL (コード スニペットにある) である場合、BlockBuffer は、メモリの使用が完了すると、ポインタをフロアにドロップします。

つまり、CMBlockBufferCreateWithMemoryBlock() を使用して CMBlockBuffer を作成し、レンダリング パイプラインを通過した後にその BlockBuffer の保持を解放する場合は、後でメモリを再利用できるように、アロケーター/デアロケーターに NULL 以外の引数を使用する必要があります。もちろん、これらのアロケーター/デアロケーターの実装は、memoryBlock の起源に依存しています。

于 2016-12-01T20:33:04.860 に答える