我正在处理从网络接收的原始 yuv420 双平面帧数据,需要创建 CVPixelBuffer 以便将其处理到 Core Image 以及使用 AVAssetWriter 写入磁盘。

当我尝试使用以下代码创建 CVPixelBuffer 时,它会分配内存并为两个平面创建一个具有正确 bytePerRow 值的正确 CVPixelBuffer(例如,宽度 120 产生 120 bytePerRow 的值)。

但是,当我输入一个宽度为 90、180 或 360 的帧时,它会生成错误的 bytePerRow,例如 192 bytePerRow,帧宽度为 180。这会导致稍后在 CoreImage 或 AVAssetWriter 中绘制的问题。

请参阅下面的代码来创建 CVPixelBuffer。

CGSize frameSize = CGSizeMake(180,240);
CVPixelBufferRef pixelBuffer = NULL;
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfaceOpenGLESFBOCompatibilityKey : (id)kCFBooleanTrue,
                                  (id)kCVPixelBufferIOSurfaceCoreAnimationCompatibilityKey : (id)kCFBooleanTrue,
                                  (id)kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey : (id)kCFBooleanTrue,
                                  (id)kCVPixelBufferOpenGLESCompatibilityKey: (id)kCFBooleanTrue};

CVReturn result = CVPixelBufferCreate(NULL, frameSize.width, frameSize.height, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, (__bridge CFDictionaryRef _Nullable)(pixelAttributes), &pixelBuffer);

请注意,我不能使用 CVPixelBufferCreateWithPlanarBytes 这迫使我自己分配内存并导致稍后与 Core Image 一起使用时内存泄漏,这不是此问题的主题。

最佳答案

我已经找到了这个错误的原因,同时从 Apple DTS 那里收到了一个符合我直觉的答案。以下是答案:

根据 Core Video 工程,每行字节从 180 向上舍入到 196 的原因是因为需要 16 字节对齐。 180/16 = 11.25; 192/16 = 12.0。

有一些方法可以强制每行精确的字节数,但这在这里听起来是个坏主意。需要对齐的原因是显卡有硬件限制。听起来您想使用 CoreImage。使用未对齐的 CVPixelBuffers 要么不起作用,要么在某处强制进行额外的复制。

我们建议逐行填充缓冲区。像这样的东西:

int srcRowbytes = 180; // Or whatever it is from wherever
int dstRowbytes = CVPixelBufferGetBytesPerRowOfPlane( dstBuffer, plane );
void * dstBytes = CVPixelBufferGetBaseAddressOfPlane( dstBuffer, plane );
for( int line = 0; line < height; line++ ) {
    memcpy( dstBytes, srcBytes, srcRowbytes );
    srcBytes += srcRowbytes;
    dstBytes += dstRowbytes;
}

关于ios - 创建宽度倍数为 90 的 CVPixelBuffer 时,每行字节错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46879895/

10-12 03:23