创建宽度倍数为 90 的 CVPixelBuffer 时,每行字节数错误

Byte per row is wrong when creating a CVPixelBuffer with width multiple of 90

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

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

但是,当我输入宽度为 90、180 或 360 的帧时,它会生成错误的 bytePerRow,例如对于帧宽度为 180 的 192 bytePerRow。这会导致稍后在 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;
}