x264中遍历一帧图像的YUV所有像素

x264中遍历一帧图像的YUV所有像素

由于实现算法需要获取当前编码帧的所有亮度和色度的图像,通过调试代码发现了一些跟通常理解不一致的像素存储方式,主要是色度。在此前阅读编码器的过程中没有关注色度像素的需要,本次在获取色度像素时发现跟亮度像素的获取有较大差别。

实现位置

代码的实现位置位于 encoder/encoder.c->slices_write(x264_t *h) 函数中。传入函数的参数只有一个x264_t 的结构体 h。在编码器的整个编码过程中结构体x264_t几乎贯穿所有过程,其中保存了所有的编码所需要的信息。在结构体x264_t中有一个x264_frame_t *fenc,其中存储的是当前编码帧。

获取亮度像素

获取亮度像素较为简单,主要过程如下:

  1. 通过fenc->i_stride[0]获取亮度stride;
  2. 通过fenc->i_lines[0]获取图像帧的高,这个值一般等于图像高度;
  3. 通过h->fenc->plane[0]获取亮度像素指针;
  4. 最后通过像素指针的遍历即可获取所有像素。

获取色度像素

获取色度像素是本篇文章的核心,其过程跟亮度像素的获取有很大区别。
首先介绍下fenc中几个重要的变量,在编码器输入为420YUV_416x240时,对应变量的值为:

  1. i_stride:长度为3,i_stride[0]=i_stride[1]=512,i_stride[2]=0;
  2. i_width:长度为3,i_width[0]=416,i_width[1]=208,i_width[2]=0;
  3. i_lines:长度为3,i_lines[0]=240,i_lines[1]=120,i_lines[2]=0;
  4. planes:长度为3的指针数组,planes[0]和planes[1]有值,planes[2]为空

i_stride[2]=0,i_width[2]=0,i_lines[2]=0,planes[2]为空可以看出,所有的像素都存储在planes[0]和planes[1]中,又因为planes[0]存储的是亮度像素,故色度像素的U和V都存储在planes[1]中。
起初认为U和V是类似于下图中的存储方式并列排放,但通过调试验证发现并不对。
在这里插入图片描述
最后通过不断尝试,发现在planes[1]中U和V的像素是交替存储的

实现代码

int img_width = h->param.i_width;
int img_height = h->param.i_height;
int img_stride = h->fenc->i_stride[0];   //luma
const uint8_t *img_plane = h->fenc->plane[0];    //luma
const uint8_t *img_plane1 = h->fenc->plane[1];    //chroma

int loca;
int loca1;

for(int mb_y = 0; mb_y < h->mb.i_mb_height; mb_y++)
{
    for(int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x++)
    {
        loca = mb_x * 16 + mb_y * 16 * img_stride;
        loca1 = mb_x * 8 + mb_y * 8 * img_stride;
        uint8_t pix = 0;    //Y
        uint8_t pix1 =0;    //U
        uint8_t pix2 =0;    //V
        for(int idx_y = 0; idx_y < 16; idx_y++)
        {
            for(int idx_x = 0; idx_x < 16; idx_x++)
            {
                pix = img_plane[loca + idx_x + idx_y * img_stride];
                if (idx_x < 8 && idx_y < 8)
                {
                    pix1 = img_plane1[loca1 + idx_x * 2 + idx_y * img_stride];
                    pix2 = img_plane1[loca1 + idx_x * 2 + idx_y * img_stride + 1];
                }
            }
        }

    }
}

获取YUV的方式如代码所示,由于一些原因写的是以宏块为单位分别获取的。本篇文章的核心在于UV的获取方式

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值