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.\n");
           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.\n");
                return -1;
       }

       printf("Succeed encode frame: %5d\n",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

 

posted @ 2019-01-19 01:39  dong1  阅读(2537)  评论(0编辑  收藏  举报