如何修正代码以获取AVFrame中各宏块的对应YUV像素值?
如何正确获取帧中每个宏块的YUV像素值?
嘿,我一眼就瞅出问题所在了——你现在的代码完全没把宏块的位置(也就是mbx和mby)纳入像素坐标的计算里!不管遍历到哪个宏块,你都在取帧最左上角那16x16区域的像素,难怪所有宏块的YUV值都一模一样。
问题根源拆解
你原来的代码里,计算Y像素坐标用的是linesize[0]*y+x,这里的y和x只是宏块内部的相对坐标,没有加上当前宏块在整个帧里的偏移量。相当于每个宏块都在重复读取帧开头的那16x16像素,结果自然全一样。
修改思路与代码实现
要解决这个问题,核心就是把宏块的坐标转换成帧中的绝对像素偏移量,具体步骤如下:
第一步:计算宏块的起始像素坐标
每个宏块是16x16的,所以:- Y平面上,宏块
(mbx, mby)的起始行是mby * 16,起始列是mbx * 16 - 对于常见的4:2:0 YUV格式,UV平面的分辨率是Y的一半,所以宏块在UV平面的起始行是
mby * 8,起始列是mbx * 8
- Y平面上,宏块
第二步:修正像素坐标计算逻辑
把宏块内部的相对坐标,加上宏块的起始偏移量,得到像素在整个帧中的绝对坐标。
下面是修改后的完整代码:
//遍历帧中所有宏块,mb_height和mb_width为帧中宏块的垂直和水平数量 for(int mby=0; mby<mb_height;mby++) { for(int mbx=0; mbx<mb_width;mbx++) { // 计算当前宏块在Y平面的起始像素坐标 int mb_y_start = mby * 16; int mb_x_start = mbx * 16; // 计算当前宏块在UV平面的起始像素坐标(针对4:2:0格式) int mb_uv_y_start = mby * 8; int mb_uv_x_start = mbx * 8; //处理当前16x16宏块(宏块尺寸为16x16) for(int y=0; y<16;y++) { for(int x=0; x<16;x++) { // 计算当前像素在Y平面的绝对坐标 int y_abs = mb_y_start + y; int x_abs = mb_x_start + x; // 获取当前宏块内像素的YUV值 int y_val = data[0][linesize[0] * y_abs + x_abs]; int u_val = data[1][linesize[1] * (mb_uv_y_start + y/2) + (mb_uv_x_start + x/2)]; int v_val = data[2][linesize[2] * (mb_uv_y_start + y/2) + (mb_uv_x_start + x/2)]; // 在这里添加对y_val/u_val/v_val的业务处理逻辑 } } //处理下一个宏块 } }
关键改动说明
- 新增宏块起始偏移量:
mb_y_start、mb_x_start定位了当前宏块在Y平面的左上角位置,mb_uv_y_start、mb_uv_x_start则对应UV平面的起始位置。 - 计算绝对像素坐标:
y_abs和x_abs把宏块内部的相对坐标转换成了帧中的绝对位置,确保每个宏块读取的是自己对应的区域。 - 修正UV值计算:原来的UV坐标只用到了宏块内部的相对偏移,现在加上了宏块在UV平面的起始偏移,终于能正确读取当前宏块对应的UV像素了。
补充:如果你的YUV格式不是4:2:0(比如4:2:2或4:4:4),需要调整UV平面的起始坐标计算逻辑,但绝大多数视频编码场景都是4:2:0,所以上面的代码应该能直接用。
内容的提问来源于stack exchange,提问作者Enock
相关产品推荐
相关产品推荐

