我一直在努力弄清楚我的代码存在什么问题。我正在创建一个平面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通道的循环逻辑。
我做错了什么?
答案 0 :(得分:2)
所以,我无法正式确认,但AVAssetWriter
似乎不喜欢iOS上的3平面像素格式(即kCVPixelFormatType_420YpCbCr8Planar
)。在OS X上,它几乎可以用于任何事情。当我将3平面缓冲区转换为双平面像素缓冲区格式时,这适用于iOS。这并不令人惊讶,因为相机本身以kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
像素格式捕获,因此AV Foundation可能也会使用该格式。
尽管vImageConvert_PlanarToChunky8
有助于将Cb和Cr平面交错为单个平面,但如果我不必自己做这个显式转换步骤,那就很好了。