5

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

当我尝试使用下面的代码创建一个 CVPixelBuffer,宽度为 120、240 或 480 时,它会分配内存并为两个平面创建一个具有正确 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 一起使用时导致内存泄漏。

4

1 回答 1

6

我找到了这个错误的原因,同时从 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;
}
于 2018-03-13T08:14:10.803 回答