历史上的今天
返回首页

历史上的今天

今天是:2024年12月29日(星期日)

2021年12月29日 | 4412 移植x264并且YUV422转x264

2021-12-29 来源:eefocus

一、YUV422转换规律 

  做视频采集与处理,自然少不了要学会分析YUV数据。因为从采集的角度来说,一般的视频采集芯片输出的码流一般都是YUV数据流的形式,而从视频处理(例如H.264、MPEG视频编解码)的角度来说,也是在原始YUV码流进行编码和解析,所以,了解如何分析YUV数据流对于做视频领域的人而言,至关重要。本文就是根据我的学习和了解,简单地介绍如何分析YUV数据流。


         YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。


        与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。


        好了,言归正传,谈谈如何分析YUV码流吧。YUV码流有多种不同的格式,要分析YUV码流,就必须搞清楚你面对的到底是哪一种格式,并且必须搞清楚这种格式的YUV采样和分布情况。下面我将介绍几种常用的YUV码流格式,供大家参考。


        YUV码流的存储格式其实与其采样的方式密切相关,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0,关于其详细原理,可以通过网上其它文章了解,这里我想强调的是如何根据其采样格式来从码流中还原每个像素点的YUV值,因为只有正确地还原了每个像素点的YUV值,才能通过YUV与RGB的转换公式提取出每个像素点的RGB值,然后显示出来。


1.1 YUV格式

为了方便后面叙述,图片的大小定 义为:w * h,宽高分别为w和h


YUV420格式


先Y,后V,中间是U。其中的Y是w * h,U和V是w/2 * (h/2)

如果w = 4,h = 2,则:

yyyy

yyyy

uu

vv

内存则是:yyyyyyyyuuvv

需要占用的内存:w * h * 3 / 2

采样规律是:每个像素点都采样Y,寄数行采样1/2个U,不采样V,偶数行采样1/2个V,不采样U


YUV422格式

本格式使用较为广泛

每两个点为一组,共占用4个字节

YUYVYUYV…

对于每一组YUYV,前面一个Y和本组中的UV组成第一个点,第二个Y和本组中的UV组成第二个点

所以,在内存中,宽高分别为w * 2、h。

如果w = 4,h = 2,则:

YUYVYUYV

YUYVYUYV

需要占用的内存:w * h * 2


UYUY422格式

本格式和YUYV422一样,只是YUV的位置不一样罢了

每组中YUV的排列顺序为:UYUV

需要占用的内存:w * h * 2


YUV的采样格式及每种格式中单像素所占内 存大小

YUV主要的采样格式有YCbCr 4:2:0、YCbCr 4:2:2、YCbCr 4:1:1和 YCbCr 4:4:4。

 

 采样格式       单像素所占内存大小        存放的码流

 

 YCbCr 4:4:4    3byte       Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3(4像素为例)

 

 YCbCr 4:2:2    2byte              Y0 U0 Y1 V1 Y2 U2 Y3 V3(4像素为例)

 

 YCbCr 4:2:0    1.5byte     Y0 U0 Y1 Y2 U2 Y3 Y5 V5 Y6 Y7 V7 Y8(8像素为例)

 

 YCbCr 4:1:1    1.5byte              Y0 U0 Y1 Y2 V2 Y3(4像素为例)

 

1.2  存储方式

下面我用图的形式给出常见的YUV码流的存储方式,并在存储方式后面附有取样每个像素点的YUV数据的方法,其中,Cb、Cr的含义等同于U、V。

(1) YUVY 格式 (属于YUV422)

  

YUYV为YUV422采样的存储格式中的一种,相邻的两个Y共用其相邻的两个Cb、Cr,分析,对于像素点Y'00、Y'01 而言,其Cb、Cr的值均为 Cb00、Cr00,其他的像素点的YUV取值依次类推。

(2) UYVY 格式 (属于YUV422)

 

UYVY格式也是YUV422采样的存储格式中的一种,只不过与YUYV不同的是UV的排列顺序不一样而已,还原其每个像素点的YUV值的方法与上面一样。


(3) YUV422P(属于YUV422)

YUV422P也属于YUV422的一种,它是一种Plane模式,即打包模式,并不是将YUV数据交错存储,而是先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,如上图所示。其每一个像素点的YUV值提取方法也是遵循YUV422格式的最基本提取方法,即两个Y共用一个UV。比如,对于像素点Y'00、Y'01 而言,其Cb、Cr的值均为 Cb00、Cr00。

 

二、移植x264

首先下载对应的源文件http://ftp.videolan.org/pub/videolan/x264/snapshots/

我选择了x264-snapshot-20181021-2245-stable.tar.bz2


tar jxvf x264-snapshot-20181021-2245-stable.tar.bz


./configure --host=arm-linux --prefix=/opt/wecam/ffmpeg --enable-shared --disable-asm


host:是要使用的平台

prefix:是make install的目录

enable-shared:是使能动态链接库

disable-asm:是关闭汇编命令


然后需要修改config.mak文件

然后运行指令:


make

make install


然后在/opt/wecam/ffmpeg目录下就有了对应的文件:

然后把libx264.so.155和pkgconfig目录放到4412开发板的/lib目录,再用指令创建软链接


ln -s libx264.so.155 libx264.so


而头文件x264.h是编译程序时需要使用的头文件


三、使用库编写YUV422转x264应用

#include

#include


#include "stdint.h"


#include "include/x264.h"


int main(int argc, char *argv[])

{

    int ret;

    int y_size;

    int i, j;


    if(argc != 3) {

        printf("usage: %s [source file] [dest file] n", argv[0]);

        return -1;

    }


    //source file

    FILE *fp_src = fopen(argv[1], "rb");

    FILE *fp_dst = fopen(argv[2], "wb");


    //Encode 0 frame

    int frame_num = 50;

    int csp = X264_CSP_I422;                //YUYV

    int width=640,height=480;               //640*480


    int iNal = 0;

    x264_nal_t *pNals = NULL;

    x264_t *pHandle = NULL;

    x264_picture_t *pPic_in = (x264_picture_t *)malloc(sizeof(x264_picture_t));

    x264_picture_t *pPic_out = (x264_picture_t *)malloc(sizeof(x264_picture_t));

    x264_param_t *pParam = (x264_param_t *)malloc(sizeof(x264_param_t));


    if(fp_src == NULL || fp_dst == NULL) {

        printf("Error open files.n");

        return -1;

    }


    x264_param_default(pParam);

    pParam->i_width = width;

    pParam->i_height = height;

    pParam->i_csp = csp;

    x264_param_apply_profile(pParam, x264_profile_names[4]);

    pHandle = x264_encoder_open(pParam);


    x264_picture_init(pPic_out);

    x264_picture_alloc(pPic_in, csp, pParam->i_width, pParam->i_height);

    y_size = pParam->i_width * pParam->i_height;

    printf("w:%d h:%drn",pParam->i_width,pParam->i_height);


    //detect frame number

    if(frame_num == 0) {

        fseek(fp_src, 0, SEEK_END);

        switch(csp) {

            case X264_CSP_I444:

                frame_num = ftell(fp_src)/(y_size*3);

                break;

            case X264_CSP_I420:

                frame_num = ftell(fp_src)/(y_size*3/2);

                break;

            case X264_CSP_I422:

                frame_num = ftell(fp_src)/(y_size*2);

                break;

            default:

                printf("Colorspace Not Support.n");

                return -1;

        }

        fseek(fp_src, 0, SEEK_SET);

    }


    printf("frame_num:%d y_size:%drn",frame_num,y_size);

    //Loop to Encode

    for(i=0;i        switch(csp) {

        case X264_CSP_I444:

            fread(pPic_in->img.plane[0], y_size, 1, fp_src);

            fread(pPic_in->img.plane[1], y_size, 1, fp_src);

            fread(pPic_in->img.plane[2], y_size, 1, fp_src);

            break;

        case X264_CSP_I420:

            fread(pPic_in->img.plane[0], y_size, 1, fp_src);

            fread(pPic_in->img.plane[1], y_size/4, 1, fp_src);

            fread(pPic_in->img.plane[2], y_size/4, 1, fp_src);

            break;

        case X264_CSP_I422:

            {

                int index = 0;

                int y_i = 0, u_i = 0, v_i = 0;

                for(index = 0; index < y_size*2; ) {

                    fread(&pPic_in->img.plane[0][y_i++], 1, 1, fp_src);         //Y

                    index++;

                    fread(&pPic_in->img.plane[1][u_i++], 1, 1, fp_src);         //U

                    index++;

                    fread(&pPic_in->img.plane[0][y_i++], 1, 1, fp_src);         //Y

                    index++;

                    fread(&pPic_in->img.plane[2][v_i++], 1, 1, fp_src);         //V

                    index++;

                }

                break;

            }

        default:

            printf("Colorspace Not Support.n");

            return -1;

        }


        pPic_in->i_pts = i;

        ret = x264_encoder_encode(pHandle, &pNals, &iNal, pPic_in, pPic_out);

        if(ret < 0) {

            printf("Error.n");

            return -1;

        }


        printf("Succeed encode frame: %5dn", i);


        for(j=0;j            fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);

        }    

    }


    //flush encoder

    while(1) {

        ret = x264_encoder_encode(pHandle, &pNals, &iNal, NULL, pPic_out);

        if(ret == 0)

            break;

        printf("Flush 1 frame.n");

        for(j=0;j            fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);

    }

    x264_picture_clean(pPic_in);

    x264_encoder_close(pHandle);

推荐阅读

史海拾趣

Dongguan City Niuhang Electronics Co.LTD公司的发展小趣事

在技术创新的基础上,Dongguan City Niuhang Electronics Co.LTD开始积极拓展市场。公司先后在安徽省池州市、江苏省扬州市和宿迁市等地设立生产基地,形成了覆盖全国的销售网络。同时,公司还加强品牌建设,通过参加行业展会、举办技术研讨会等方式,提升品牌知名度和影响力。随着市场的不断扩大,公司的销售业绩也实现了快速增长。

Eink公司的发展小趣事
2001年6月,E-Ink再次宣布技术突破,推出了“Ink-in-Motion”技术,使得电子纸上可以显示活动影像。这一技术为电子纸的应用开辟了新的领域,如动态广告、电子书等。
Aydin Corp公司的发展小趣事

Aydin Corp公司诞生于电子行业的初期,当时的市场充满了机遇与挑战。创始人凭借对电子技术的深厚理解和对市场需求的敏锐洞察,决定投身于这一领域。初创时期,公司面临着资金短缺、技术瓶颈和市场竞争等多重困难。然而,通过不懈的努力和持续的创新,Aydin Corp逐渐在市场中站稳了脚跟。

永丰盈(CST)公司的发展小趣事

随着市场的不断发展,CST意识到技术创新是企业持续发展的关键。因此,公司加大了对技术研发的投入,引进了一批高素质的研发人才,建立了先进的研发实验室。经过不懈努力,CST在电子接插件领域取得了多项技术突破,产品性能得到了显著提升,进一步巩固了其在市场中的领先地位。

General Magnetics Inc公司的发展小趣事
如发出嗡嗡声、吱吱声或噼啪声等,可能表示内部有松动、短路或放电现象。
Crouzet公司的发展小趣事

Crouzet公司,这家以生产自控产品为主的跨国公司,于1921年正式成立。创立之初,Crouzet主要专注于自控产品的研发和生产,凭借其卓越的技术和创新能力,很快在市场中占据了一席之地。公司逐渐扩大生产规模,提升产品质量,赢得了客户的信赖。

问答坊 | AI 解惑

牛人对模拟电路的理解

一牛人对模拟电路的理解,看后受益匪浅,大家分享!…

查看全部问答>

【西门逛中发】(一)初识中发,少花钱多办事

序言:   “不是在中发,就是在去中发的路上,”用这句话形容西门,似乎一点儿也不为过。   常年混迹于中发的西门,在那里拥有为数众多的好朋友,与经常去那里的工程师相比,他更像其中一员,就差摆个摊铺坐在那里了。这样一位“圈内”人士, ...…

查看全部问答>

哪位高手能给我解释解释什么是数据恢复电路啊?

老师安排的题目是数据恢复电路 用verilog编程的 自己上网查了也没搜到什么东西 哪位高手能给我解释解释这个电路啊 还有编程方面要注意些什么问题啊 先谢谢了!!! 对了 这是要求 数据恢复电路:半字节数据输入,不定长码流,MSB在前,起始位 ...…

查看全部问答>

学生求助CE串口开发问题

大家好,学生以前接触的硬件类比较多,这次需要在2440板子下跑wince,用串口读数据,我找了很多资料,发现都是直接给代码的,学生求助,是在什么环境下编译?PB吗?如果是PB的话,就是改PB里哪里的程序呢???学生很疑惑,学生其实是想用VS2005中 ...…

查看全部问答>

你努力工作是为了谁?

当你满怀激情的投入到工作当中的时候,   你有没有想过,你的工作包含了多少有益成分?在你的工作成绩中,有多少是在为自己打拼,有多少是在为他人做嫁衣呢?    …

查看全部问答>

悲剧啊,69端口竟然被占用!

1.昨天在公司电脑上配置的TFTP成功以后,下班回到家满心欢喜把家里的电脑也比葫芦画瓢来一遍,结果死活都启动不了。查了下端口UDP6协议下,后面占用是69端口,而不是udp。而且执行service tftpd-hpa restart ,他竟然停在那里,连命令行也不出来了 ...…

查看全部问答>

中国消费类电子企业有哪些????

像华为、中兴这样的消费类电子有哪些??? 这些企业都做得怎么样??? 一起来聊聊啊!!!!…

查看全部问答>

电机控制 - 无刷直流 (BLDC) 电机主推产品

本帖最后由 dontium 于 2015-1-23 13:10 编辑 器件型号:RDK_BLDC                     DRV8312-C2-KIT (电机控制评估套件)    &nbs ...…

查看全部问答>

DSP的SPI通信

各位大虾,小弟一个PCB上边有两个2812,要使用SPI通信,请问SPI的四个端口能直接连接在一起么?需要注意些什么?谢谢了…

查看全部问答>

ls -bash: ls: command not found .

原因:在设置环境变量时,编辑profile文件没有写正确,导致在命令行下ls等命令不能够识别。 解决方案: exportPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin…

查看全部问答>