zoukankan      html  css  js  c++  java
  • 4412 移植x264并且YUV422转x264

    转自http://blog.sina.com.cn/s/blog_af9acfc60101alxx.html

    一、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 <stdio.h>
    #include <stdlib.h>
    
    #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] 
    ", 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.
    ");
            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:%d
    ",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.
    ");
                    return -1;
            }
            fseek(fp_src, 0, SEEK_SET);
        }
    
        printf("frame_num:%d y_size:%d
    ",frame_num,y_size);
        //Loop to Encode
        for(i=0;i<frame_num;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.
    ");
                return -1;
            }
    
            pPic_in->i_pts = i;
            ret = x264_encoder_encode(pHandle, &pNals, &iNal, pPic_in, pPic_out);
            if(ret < 0) {
                printf("Error.
    ");
                return -1;
            }
    
            printf("Succeed encode frame: %5d
    ", i);
    
            for(j=0;j<iNal;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.
    ");
            for(j=0;j<iNal;j++)
                fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
        }
        x264_picture_clean(pPic_in);
        x264_encoder_close(pHandle);
        pHandle = NULL;
    
        free(pPic_in);
        free(pPic_out);
        free(pParam);
    
        fclose(fp_src);
        fclose(fp_dst);
    
        return 0;
    }

    然后是Makefile文件

    encode_h264:
            arm-none-linux-gnueabi-gcc encode_h264.c -o encode_h264 -L./lib/ -lx264
            cp encode_h264 /home/topeet/linux/camera/x264_code
    clean:
            rm -f encode_h264

    打完收工!

  • 相关阅读:
    几何画板绘制三棱锥的教程
    MathType给公式底部加箭头的教程
    几何画板有哪些快捷键可以用
    公式编辑器调整公式边框粗细的教程
    wdcp安装
    搭建git for windows服务器(100%可以成功)
    百度echarts
    简单的js菜单
    真正的让iframe自适应高度 兼容多种浏览器随着窗口大小改变
    Hadoop学习笔记(一)从官网下载安装包
  • 原文地址:https://www.cnblogs.com/ch122633/p/9831063.html
Copyright © 2011-2022 走看看