3

私はコードの問題が何であるかを理解するのに苦労しています。CVPixelBufferRefに書き込む平面を作成していAVAssetWriterます。このピクセル バッファは、他のプロセスを通じて手動で作成されます (つまり、これらのサンプルをカメラなどから取得することはありません)。iOS シミュレーターでは、サンプルの追加と有効な出力ムービーの作成に問題はありません。

ただし、デバイスでは、最初のサンプルですぐに失敗し、役に立たないエラー情報が提供されます。

AVAssetWriterError: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSUnderlyingError=0x12fd2c670 {Error Domain=NSOSStatusErrorDomain Code=-12780 "(null)"}, NSLocalizedFailureReason=An unknown error occurred (-12780), NSLocalizedDescription=The operation could not be completed}

私はピクセル形式に非常に慣れていないため、何らかの方法で無効なピクセル バッファを作成したとしても驚かないでしょうが、シミュレータ (つまり、OS X) で問題なく動作するという事実は、私を混乱させます。

これが私のコードです:

const int pixelBufferWidth = img->get_width();
const int pixelBufferHeight = img->get_height();

size_t planeWidths[3];
size_t planeHeights[3];
size_t planeBytesPerRow[3];
void* planeBaseAddresses[3];

for (int c=0;c<3;c++) {
  int stride;
  const uint8_t* p = de265_get_image_plane(img, c, &stride);

  int width = de265_get_image_width(img,c);
  int height = de265_get_image_height(img, c);

  planeWidths[c] = width;
  planeHeights[c] = height;
  planeBytesPerRow[c] = stride;

  planeBaseAddresses[c] = const_cast<uint8_t*>(p);
}

void* descriptor = calloc(1, sizeof(CVPlanarPixelBufferInfo_YCbCrPlanar));
CVPixelBufferRef pixelBufferRef;
CVReturn result = CVPixelBufferCreateWithPlanarBytes(NULL,
                                                     pixelBufferWidth,
                                                     pixelBufferHeight,
                                                     kCVPixelFormatType_420YpCbCr8Planar,
                                                     NULL,
                                                     0,
                                                     3,
                                                     planeBaseAddresses,
                                                     planeWidths,
                                                     planeHeights,
                                                     planeBytesPerRow,
                                                     &pixelBufferReleaseCallback,
                                                     NULL,
                                                     NULL,
                                                     &pixelBufferRef);


CMFormatDescriptionRef formatDescription = NULL;
CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixelBufferRef, &formatDescription);

if (assetWriter == nil) {
  // ... create output file path in Caches directory

  assetWriter = [AVAssetWriter assetWriterWithURL:fileOutputURL fileType:AVFileTypeMPEG4 error:nil];

  NSDictionary *videoSettings = @{AVVideoCodecKey : AVVideoCodecH264,
                                  AVVideoWidthKey : @(pixelBufferWidth),
                                  AVVideoHeightKey : @(pixelBufferHeight),
                                  AVVideoCompressionPropertiesKey : @{AVVideoMaxKeyFrameIntervalKey : @1}};

  assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings sourceFormatHint:formatDescription];
  [assetWriter addInput:assetWriterInput];

  NSDictionary *pixelBufferAttributes = @{(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_420YpCbCr8Planar),
                                          (id)kCVPixelBufferWidthKey : @(pixelBufferWidth),
                                          (id)kCVPixelBufferHeightKey : @(pixelBufferHeight)};

  pixelBufferAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:assetWriterInput sourcePixelBufferAttributes:pixelBufferAttributes];

  [assetWriter startWriting];
  [assetWriter startSessionAtSourceTime:kCMTimeZero];
}

samplePresentationTime = CMTimeMake(frameIndex++, framesPerSecond);

BOOL success = [pixelBufferAdaptor appendPixelBuffer:pixelBufferRef withPresentationTime:samplePresentationTime];

successは常にNOで、アセット ライターからのエラーは上に貼り付けたものです。

AVAssetWriterInputPixelBufferAdaptor可能性のある問題としてそれを排除するためだけに使用するのではなく、手動でサンプル バッファーを作成しようとしましたが、結果は同じです。

繰り返しますが、これシミュレーターで機能するため、ピクセル バッファーに適切なデータが含まれていることがわかります。

また、ファイル先への書き込みができることを確認しました。その場所にダミーファイルを作成してみましたが、成功しました。

バッファを RGB に変換する必要はないので、避けたいと思います。まず、Y'CbCr バッファーがあり、それらを Y'CbCr をサポートする H.264 ビデオにエンコードしたいだけです。

これらのバッファを作成しているソースには、次のように記載されています。

The image is currently always 3-channel YCbCr, with 4:2:0 chroma.

8 ビット YUV チャネルを扱うループ ロジックに常に入ることを確認しました。

私は何を間違っていますか?

4

1 に答える 1

2

したがって、これを公式に確認することはできませんが、iOSAVAssetWriterでは 3 プレーン ピクセル フォーマット (つまり ) が気に入らないようです。kCVPixelFormatType_420YpCbCr8PlanarOS X では、ほとんど何でも動作するようです。3 プレーン バッファをバイプレーン ピクセル バッファ形式に変換すると、iOS で動作しました。カメラはネイティブにピクセル形式でキャプチャするため、これは当然のことであり、kCVPixelFormatType_420YpCbCr8BiPlanarVideoRangeAV Foundation もその形式で動作する可能性があります。

それでも、この明示的な変換手順を自分で行う必要がなければいいのですがvImageConvert_PlanarToChunky8、Cb プレーンと Cr プレーンを 1 つのプレーンにインターリーブするのに役立ちます。

于 2015-12-08T00:21:57.987 に答える