4

我捕捉视频并处理生成的 YUV 帧。输出如下所示: 来自结果视频的样本

虽然它通常出现在我的手机屏幕上。但是我的同行收到它就像上面的 img 一样。每个项目都重复并在水平和垂直方向上移动了一些值

我捕获的视频是 352x288,我的 YPixelCount = 101376,UVPixelCount = YPIXELCOUNT/4

有什么线索可以解决这个问题,或者是了解如何在 iOS 上处理 YUV 视频帧的起点?

    NSNumber* recorderValue = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
    [videoRecorderSession setSessionPreset:AVCaptureSessionPreset352x288];

这是 captureOutput 函数

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
    if(CMSampleBufferIsValid(sampleBuffer) && CMSampleBufferDataIsReady(sampleBuffer) && ([self isQueueStopped] == FALSE))
    {

        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
        CVPixelBufferLockBaseAddress(imageBuffer,0); 
        UInt8 *baseAddress[3] = {NULL,NULL,NULL};
        uint8_t *yPlaneAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer,0);
        UInt32 yPixelCount =  CVPixelBufferGetWidthOfPlane(imageBuffer,0) * CVPixelBufferGetHeightOfPlane(imageBuffer,0);
        uint8_t *uvPlaneAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer,1);
        UInt32 uvPixelCount = CVPixelBufferGetWidthOfPlane(imageBuffer,1) * CVPixelBufferGetHeightOfPlane(imageBuffer,1);
        UInt32  p,q,r;
        p=q=r=0;
        memcpy(uPointer, uvPlaneAddress, uvPixelCount);
        memcpy(vPointer, uvPlaneAddress+uvPixelCount, uvPixelCount);

        memcpy(yPointer,yPlaneAddress,yPixelCount);
        baseAddress[0] = (UInt8*)yPointer;
        baseAddress[1] = (UInt8*)uPointer;
        baseAddress[2] = (UInt8*)vPointer;
        CVPixelBufferUnlockBaseAddress(imageBuffer,0);
    }
}

上面的代码有什么问题吗?

4

1 回答 1

2

你的代码看起来还不错。我可以看到两个错误和一个潜在问题:

  • uvPixelCount是不正确的。YUV 420 格式意味着每个 2 x 2 像素块都有颜色信息。所以正确的计数是:

    uvPixelCount = (width / 2) * (height / 2);
    

    你写了一些关于的东西yPixelCount / 4,但我在你的代码中看不到。

  • UV信息是交错的,即第二平面交替地包含U和V值。或者换一种说法:所有偶数字节地址都有一个 U 值,所有奇数字节地址都有一个 V 值。如果你真的需要将U和V信息分开,那就不行了memcpy

  • 每个像素行之后可能会有一些额外的字节。您应该使用CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0)来获取两行之间的字节数。结果,单行memcpy不行。相反,您需要分别复制每个像素行以消除行之间的额外字节。

所有这些事情只解释了结果图像的一部分。其余部分可能是由于您的代码与接收对等方的期望之间存在差异。你什么都没写?对等点真的需要分开的 U 和 V 值吗?你也是 4:2:0 压缩吗?你是视频范围而不是全范围吗?

如果您提供更多信息,我可以给您更多提示。

于 2011-12-13T21:20:55.620 回答