• YUV/RGB与H264之间的编解码


    1、源码下载

    http://download.videolan.org/x264/snapshots/

    2、编译

    ./configure --prefix=./_install --enable-shared --enable-static

    make

    make install

    3、demo 

    在x264库里的x264_config.h中确定版本号,版本太混乱了,相差太远可能还不兼容

    #define X264_POINTVER "0.157.x"

    main.c

    /**
     * 最简单的基于X264的视频编码器
     * Simplest X264 Encoder
     * leixiaohua
     * 
     * 本程序可以YUV格式的像素数据编码为H.264码流,是最简单的
     * 基于libx264的视频编码器
     *
     * This software encode YUV data to H.264 bitstream.
     * It's the simplest encoder example based on libx264.
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <unistd.h>
    //#include <pthread.h>
     
    #if defined ( __cplusplus)
    extern "C"
    {
    #include "x264.h"
    };
    #else
    #include "x264.h"
    #endif
    
    int csp=X264_CSP_I420;
    int frame_num=0;
    int width=640;
    int height=360;
    
    FILE* fp_src;
    FILE* fp_dst;   
    
    x264_nal_t* pNals;
    x264_t* pHandle;
    x264_picture_t* pPic_in;
    x264_picture_t* pPic_out;
    x264_param_t* pParam;
    
    int y_size;
    
    int en_h264_init()
    {
    
        fp_src  = fopen("./cuc_ieschool_640x360_yuv420p.yuv", "rb");
        fp_dst = fopen("output.h264", "wb");
    
        pNals = NULL;
        pHandle   = NULL;
        pPic_in = (x264_picture_t*)malloc(sizeof(x264_picture_t));
        pPic_out = (x264_picture_t*)malloc(sizeof(x264_picture_t));
        pParam = (x264_param_t*)malloc(sizeof(x264_param_t));
    
        //Check
        if(fp_src==NULL||fp_dst==NULL){
               printf("Error open files.
    ");
               return -1;
        }
    
        x264_param_default(pParam);  
        x264_param_default_preset(pParam, "fast" , "zerolatency" );
    
        pParam->i_csp=csp;
        pParam->i_width   = width;  
        pParam->i_height  = height;  
        pParam->i_fps_num  = 25;     
        pParam->i_fps_den  = 1;     
    
        pParam->i_threads  = X264_SYNC_LOOKAHEAD_AUTO;
        pParam->i_keyint_max = 10;             
    
        pParam->rc.i_bitrate = 1200;     
        pParam->rc.i_rc_method = X264_RC_ABR; 
    
        //set profile
        x264_param_apply_profile(pParam, "baseline");
    
        //open encoder
        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;
        //detect frame number
        if(frame_num==0){
           fseek(fp_src,0,SEEK_END);
           frame_num=ftell(fp_src)/(y_size*3/2);
           fseek(fp_src,0,SEEK_SET);
        }
    }
    
    int en_h264_run(char *y,char *u,char *v)
    {  
        int i,j,ret;
         int iNal = 0;
    #if 1
    
         fread(pPic_in->img.plane[0],y_size,1,fp_src);         //Y
         fread(pPic_in->img.plane[1],y_size/4,1,fp_src);       //U
         fread(pPic_in->img.plane[2],y_size/4,1,fp_src);       //V
    
    #else
          memcpy(pPic_in->img.plane[0],y,y_size);
          memcpy(pPic_in->img.plane[1],u,y_size / 4);
          memcpy(pPic_in->img.plane[2],v,y_size / 4);    
    #endif
    
           pPic_in->i_pts += 1;
    
           ret = x264_encoder_encode(pHandle, &pNals, &iNal, pPic_in, pPic_out);
           if (ret< 0){
                    printf("Error.
    ");
                    return -1;
           }
    
           printf("Succeed encode frame: %5d
    ",pPic_in->i_pts-1);
    
           for ( j = 0; j < iNal; ++j){
                     fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
           }
    
            /* Flush delayed frames */
            while( x264_encoder_delayed_frames( pHandle ) )
            {
                ret = x264_encoder_encode( pHandle, &pNals, &iNal, NULL, pPic_out );
                if( ret )
                {
                    fwrite( pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst );
                }
            }
    
    }
    
    int en_h264_release()
    {
        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;
    }
     
    
    int main(int argc, char** argv)
    {
        en_h264_init();
    
        char y[640*360];
        char u[640*360/4];
        char v[640*360/4];
    
        for(int i=0;i<frame_num;i++){
            en_h264_run(y,u,v);
        }
        en_h264_release();
    
        return 0;
    }

    其实x264源码包里自带的demo更好,x264-snapshot-20190512-2245/example.c

    /*****************************************************************************
     * example.c: libx264 API usage example
     *****************************************************************************
     * Copyright (C) 2014-2019 x264 project
     *
     * Authors: Anton Mitrofanov <BugMaster@narod.ru>
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
     *
     * This program is also available under a commercial proprietary license.
     * For more information, contact us at licensing@x264.com.
     *****************************************************************************/
    
    #ifdef _WIN32
    #include <io.h>       /* _setmode() */
    #include <fcntl.h>    /* _O_BINARY */
    #endif
    
    #include <stdint.h>
    #include <stdio.h>
    #include "x264.h"
    
    #include <math.h>
    
    #define FAIL_IF_ERROR( cond, ... )
    do
    {
        if( cond )
        {
            fprintf( stderr, __VA_ARGS__ );
            goto fail;
        }
    } while( 0 )
    
    int main( int argc, char **argv )
    {
        
        x264_param_t param;
        x264_picture_t pic;
        x264_picture_t pic_out;
        x264_t *h;
        int i_frame = 0;
        int i_frame_size;
        x264_nal_t *nal;
        int i_nal;
    
        FILE* fp_src  = fopen("./cuc_ieschool_640x360_yuv420p.yuv", "rb");
        FILE* fp_dst = fopen("cuc_ieschool.h264", "wb");
        
        int width=640,height=360;
    
    
        /* Get default params for preset/tuning */
        if( x264_param_default_preset( &param, "medium", NULL ) < 0 )
            goto fail;
    
        /* Configure non-default params */
        param.i_bitdepth = 8;
        param.i_csp = X264_CSP_I420;
        param.i_width  = width;
        param.i_height = height;
        param.b_vfr_input = 0;
        param.b_repeat_headers = 1;
        param.b_annexb = 1;
    
        /* Apply profile restrictions. */
        if( x264_param_apply_profile( &param, "high" ) < 0 )
            goto fail;
    
        if( x264_picture_alloc( &pic, param.i_csp, param.i_width, param.i_height ) < 0 )
            goto fail;
    #undef fail
    #define fail fail2
    
        h = x264_encoder_open( &param );
        if( !h )
            goto fail;
    #undef fail
    #define fail fail3
    
        int luma_size = width * height;
        int chroma_size = luma_size / 4;
        /* Encode frames */
        for( ;; i_frame++ )
        {
            /* Read input frame */
            if( fread( pic.img.plane[0], 1, luma_size, fp_src ) != luma_size )
                break;
            if( fread( pic.img.plane[1], 1, chroma_size, fp_src ) != chroma_size )
                break;
            if( fread( pic.img.plane[2], 1, chroma_size, fp_src ) != chroma_size )
                break;
    
            pic.i_pts = i_frame;
            i_frame_size = x264_encoder_encode( h, &nal, &i_nal, &pic, &pic_out );
            if( i_frame_size < 0 )
                goto fail;
            else if( i_frame_size )
            {
                if( !fwrite( nal->p_payload, i_frame_size, 1, fp_dst ) )
                    goto fail;
            }
        }
        /* Flush delayed frames */
        while( x264_encoder_delayed_frames( h ) )
        {
            i_frame_size = x264_encoder_encode( h, &nal, &i_nal, NULL, &pic_out );
            if( i_frame_size < 0 )
                goto fail;
            else if( i_frame_size )
            {
                if( !fwrite( nal->p_payload, i_frame_size, 1, fp_dst ) )
                    goto fail;
            }
        }
    
        x264_encoder_close( h );
        x264_picture_clean( &pic );
        return 0;
    
    #undef fail
    fail3:
        x264_encoder_close( h );
    fail2:
        x264_picture_clean( &pic );
    fail:
        return -1;
    }

    4、编译

    1) 务必先设置好库文件环境变量

    export LD_LIBRARY_PATH=~/gb28181/x264-snapshot-20190512-2245/_install/lib:$LD_LIBRARY_PATH

    gcc -o main main.c -I ./_install/include -L ./_install/lib -lx264 -lpthread -std=c99

    gcc -o example example.c -I ./_install/include -L ./_install/lib -lx264 -lpthread -std=c99

    #gcc -o main main.c -I ./_install/include ./_install/lib/libx264.a -lpthread -std=c99

    不知道什么原因,用静态库编译会出错

    2) 也可以不配置环境变量,将x264安装到ubuntu默认路径,直接gcc -o main main.c -lx264

    5、yuv/rgb <---> h264

    ffmpeg-4.1.tar.bz2

    ./configure --target-os=linux --cc=arm-linux-gnueabihf-gcc --arch=arm --enable-shared --enable-cross-compile --cross-prefix=arm-linux-gnueabihf- --enable-gpl --enable-ffplay --enable-libx264 --enable-postproc --prefix=$(pwd)/_install --extra-cflags=-I$(pwd)/_install/include --extra-ldflags=-L$(pwd)/_install/lib
    make
    make install

    A simple C program that convert the raw RGB stream to H264 stream and vice versa

    https://github.com/lctseng/H264-RGB-Encode-Decode

    版本不一致,编译不过,改成以上ffmpeg-4.1.tar.bz2和x264-snapshot-20190512-2245了

    https://files.cnblogs.com/files/dong1/rgb_h264_demo.zip

    6、交叉编译

    ./configure --prefix=${PWD}/_install --enable-shared --disable-asm --disable-cli --host=arm-linux-gnueabihf

    更改config.mak
    CC=arm-linux-gnueabihf-gcc
    LD=arm-linux-gnueabihf-gcc -o
    AR=arm-linux-gnueabihf-gcc-ar rc
    RANLIB=arm-linux-gnueabihf-gcc-ranlib

    make

    make install

    7、参考设计

    libx264编码---YUV图像数据编码为h.264码流
    https://blog.csdn.net/qq_41248872/article/details/83068869

    各种音视频测试文件

    http://www.live555.com/liveMedia/public/

    http://samples.mplayerhq.hu/

    使用libyuv对yuv数据进行缩放,旋转,镜像,裁剪等操作

    https://github.com/lemenkov/libyuv

  • 相关阅读:
    hdu 1003 dp最大子序列和
    模拟题 (+queue队列知识)
    hdu 1016 DFS
    OSGi 系列(二)之 Hello World
    OSGi 系列(一)之什么是 OSGi :Java 语言的动态模块系统
    Mina 系列(四)之KeepAliveFilter -- 心跳检测
    Mina 系列(三)之自定义编解码器.md
    Mina 系列(二)之基础
    Mina 快速入门
    Java 8 Optional 类深度解析
  • 原文地址:https://www.cnblogs.com/dong1/p/10290343.html
Copyright © 2020-2023  润新知