YUV-NV12视频缓冲区的Y平面和UV平面的持续时间

3
我有一个(CMSampleBufferRef)imageBuffer,它的类型是yuv_nv12(4:2:0)。

现在我运行了以下代码,并发现结果令人困惑。

UInt8 *baseSRC = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer);
UInt8 *yBaseSRC = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
UInt8 *uvBaseSRC = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 1);
int width = (int)CVPixelBufferGetWidthOfPlane(imageBuffer, 0);    //width = 480;
int height = (int)CVPixelBufferGetHeightOfPlane(imageBuffer, 0);  //height = 360;

int y_base = yBaseSRC - baseSRC;     //y_base = 64;
int uv_y = uvBaseSRC-yBaseSRC;       //uv_y = 176640;
int delta = uv_y - width*height;     //delta = 3840;

我对这个结果有几个问题。

1:为什么 baseSRC 不等于 yBaseSRC

2:理论上, yBaseSRC + width * height 不等于 uvBaseSRC 吗? 理论上,y分量数据后面紧跟着uv分量数据,没有任何中断,是吗?现在它被3840字节大小的某些东西所打断了,我不明白。

3:我尝试使用以下代码将此示例像素转换为cvmat,在大多数iOS设备上,这可以正常工作,但在iPhone 4s上不行。在转换后,像素缓冲区的侧面会出现一些绿线。

Mat nv12Mat(height*1.5,width,CV_8UC1,(unsigned char *)yBaseSRC);
Mat rgbMat;
cvtColor(nv12Mat, rgbMat, CV_YUV2RGB_NV12);

现在rgbMat看起来像这样:

enter image description here


1
CVPixelBuffer是不透明类型,我推断你发现的增量是CVPixelBuffer数据类型的一部分。由于该数据类型未记录,而且苹果提供了提取所需数据的API,因此我不会假设数据的组织方式。至于opencv mat,为什么要使用(height * 1.5)的高度?你应该只传递“height”。 - blackirishman
@blackirishman 因为“height”是y平面的高度,所以uv平面的高度等于“height/2.0”,因此缓冲区的总大小应为“widthheight+widthheight/2.0”,这与“widthheight1.5”的意思相同。 - Li Fumin
当你最初编写这个时,你是在创建y平面的Mat,对吧?调用CVPixelBufferGetWidthOfPlane和CVPixelBufferGetHeightOfPlane可以给你应该输入到Mat中的宽度和高度。 - blackirishman
你更新了你的帖子,所以它不太清楚了。 - blackirishman
这种转换在其他iOS设备上都能正常运行,但只有iPhone 4s存在故障。 - Li Fumin
显示剩余3条评论
1个回答

2

最终找到了解决方案,基本上解决方案是分配一块新的内存,并连接y平面数据和uv平面数据。然后将其转换为cvmat后就可以正常工作了。

以下是代码片段:

UInt8 *newBase = (UInt8 *)malloc(landscapeWidth*landscapeHeight*1.5);
memcpy(newBase, yBaseSRC, landscapeWidth*landscapeHeight);
memcpy(newBase+landscapeWidth*landscapeHeight, uvBaseSRC, landscapeWidth*landscapeHeight*0.5);
Mat nv12Mat(landscapeHeight*1.5,landscapeWidth,CV_8UC1,(unsigned char *)newBase);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接