7

OSX でビデオ ファイルをフレームごとに処理するコードを作成しました。以下は、正常にビルドされ、ファイルが開かれ、ビデオ トラック (トラックのみ) が特定され、問題なく CMSampleBuffers の読み取りが開始されるコードからの抜粋です。ただし、取得した各 CMSampleBufferRef は、ピクセル バッファー フレームを抽出しようとすると NULL を返します。iOS のドキュメントには、なぜ NULL の戻り値が期待できるのか、または問題をどのように修正できるのかについては示されていません。キャプチャ ソースや CODEC に関係なく、テストしたすべてのビデオで発生します。

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

NSString *assetInPath = @"/Users/Dave/Movies/movie.mp4";
NSURL *assetInUrl = [NSURL fileURLWithPath:assetInPath];
AVAsset *assetIn = [AVAsset assetWithURL:assetInUrl];

NSError *error;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:assetIn error:&error];
AVAssetTrack *track = [assetIn.tracks objectAtIndex:0];
AVAssetReaderOutput *assetReaderOutput = [[AVAssetReaderTrackOutput alloc]
                                              initWithTrack:track
                                              outputSettings:nil];
[assetReader addOutput:assetReaderOutput];

// Start reading
[assetReader startReading];

CMSampleBufferRef sampleBuffer;
do {
       sampleBuffer = [assetReaderOutput copyNextSampleBuffer];

       /**
        ** At this point, sampleBuffer is non-null, has all appropriate attributes to indicate that
        ** it's a video frame, 320x240 or whatever and looks perfectly fine. But the next
        ** line always returns NULL without logging any obvious error message
        **/

       CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

       if( pixelBuffer != NULL ) {
           size_t width = CVPixelBufferGetWidth(pixelBuffer);
           size_t height = CVPixelBufferGetHeight(pixelBuffer);
           CVPixelBufferLockBaseAddress(pixelBuffer, 0);
           ...
           other processing removed here for clarity
        }
} while( ... );

明確にするために、すべてのエラー チェック コードを取り除きましたが、そのコードには問題が示されていませんでした。つまり、AVAssetReader が読み取られている、CMSampleBufferRef が問題ないように見えるなどです。

4

3 に答える 3

5

outputSettings を指定していないため、フレームに含まれる生データを使用する必要があります。

を使用してサンプル バッファからブロック バッファをCMSampleBufferGetDataBuffer(sampleBuffer)取得する必要があります。その後、 を使用してブロック バッファの実際の場所を取得する必要があります。

size_t blockBufferLength; char *blockBufferPointer; CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &blockBufferLength, &blockBufferPointer);

必要なコーデック*blockBufferPointerのフレーム ヘッダー情報を使用して、バイトを調べてデコードします。

于 2015-12-07T22:11:24.400 に答える
2

FWIW: CMSampleBufferGetImageBuffer の戻り値についての公式ドキュメントの内容は次のとおりです。

「結果はメディア データの CVImageBuffer です。CMSampleBuffer に CVImageBuffer が含まれていない場合、または CMSampleBuffer に CMBlockBuffer が含まれている場合、またはその他のエラーがある場合、結果は NULL になります。」

また、呼び出し元は CMSampleBufferGetImageBuffer から返された dataBuffer を所有していないため、呼び出し元が参照を維持する必要がある場合は明示的に保持する必要があることに注意してください。

この情報がお役に立てば幸いです。

于 2013-06-01T14:32:31.297 に答える