libx264 encoding parameter adjustment -- streaming media

Add a suffix to the title - streaming media. Therefore, we mainly use libx264 to study the setting of bias in streaming media scene (low delay), encoder bit rate, image effect, etc. there are many parameters, which may have mutual influence. We don't understand much. Here, we can learn from various blogs, x264 official wiki, libx264 source code and official website https://www.videolan.org/developers/x264.html (for a vlc organization, go to the vlc official website, and you can also find wiki documents.) record the parameter settings of water testing libx264 streaming media low latency coding.
Environmental Science:
Generation 5 Corei7 CPU, Ubuntu system.
libx264 configuration -- Disable ASM is turned off, which may reduce efficiency. It needs to be turned on in actual use. This is just a research test.
After libx264 and configure + make, the x264 executable file is generated by default. However, we do not intend to use the x264 tool to study here. There is an example in its source directory C file, which can be used as a reference for api calls. Need us to execute
#make example
Generate an example executable file. This film refers to the example source code to write its own demo
1.0 setting parameters. 2.0 input a frame yuv420 data. 3.0 encoding and fetching data

Q1: how to set the encoder not to generate B frames?

param.i_bframe=0 / / / * how many b-frame between 2 references pictures * / source code comments

Q2: how to set GOP value

param.i_keyint_max=xx /* Force an IDR keyframe at this interval */

Q3: add sps pps information in front of each I frame

param.b_repeat_headers=1 /* put SPS/PPS before each keyframe */

Q4: key point: how to make the encoder not cache and expect it to send in one frame of data and output one frame of data after coding?

x264_param_default_preset( &param, "ultrafast", "zerolatency" )
The second parameter, zerorate. After this is set, the sequence of one frame in and one frame out is. You may not need to do this when encoding and storing local files, but you must do so for those with high factual requirements, otherwise there will always be a delay.
The first parameter actually sets a combination of a series of parameters. You can set some column parameters according to the speed you choose, such as param i_ When bframe selects ultrafast, it will be set to 0, which is in the source code base c ::param_ apply_ Detailed information can be seen in preset (x264_param_t * param, const char * preset) function. Optional values: {"ultrafast", "superfast", "veryfast", "fast", "fast", "medium", "slow", "slow", "slow", "veryslow", "placebo"}
Just look at the name.

Other parameters:

   param.i_bitdepth = 8;
    param.i_csp = X264_CSP_I420;// color space?
    param.i_width  = width;
    param.i_height = height;
    param.b_vfr_input = 0; // Setting to 1 will control the timestamp?
    param.b_annexb = 1;// Each frame carries the start code 00 00 01. If it is set to 0, 00 00 01 is not added, but the data size value of this frame is stored. (4 bytes)

Comparison results

If "zerorate" is not set, even if the first parameter is set to "ultrafast", there is a cache and delayed output:

For example, the above is not output until 12 frames are input.
After "ZERODEGREE" is turned on:

This is the real-time requirement of our streaming media.
You can see my hardware environment. ultrafast sets the speed of encoding a frame within 4ms, (the original YUV data resolution here is 640x480,yuv420sp, and libx264 do not enable asm assembly level platform optimization). And basically, the encoding time of I-frame is higher than that of P-frame, and the above nal - > i_type = = 7 is I-frame. (originally, it was thought that P-frame information has less redundancy, and it may take more time to refer to the frame, but it seems not.)

Place the debug demo:

//canok 20210804

#include <stdint.h>
#include <stdio.h>
#include <sys/time.h>
#include <x264.h>

#define FAIL_IF_ERROR( cond, ... )\
do\
{\
    if( cond )\
    {\
        fprintf( stderr, __VA_ARGS__ );\
        goto fail;\
    }\
} while( 0 )


int64_t getNowUs(){
    struct timeval tv;
    gettimeofday(&tv, 0);
    return (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec;
}

int main( int argc, char **argv )
{//https://www.cnblogs.com/wainiwann/p/5647521.html
    int width, height;
    x264_param_t param;
    x264_picture_t pic;
    x264_picture_t pic_out;
    x264_t *h;
    int i_frame = 0;
    int out_frame=0;
    int i_frame_size;
    x264_nal_t *nal;
    int i_nal;

    //FAIL_IF_ERROR( !(argc > 1), "Example usage: example 352x288 <input.yuv >output.h264\n" );
    if(argc !=3){
        printf("usage: my_encoder WxH inputfile.yuv\n");
        return -1;
    }

    FILE *fp_in=fopen(argv[2],"r");
    if(fp_in==NULL){
        printf("[%s%d] fopen err:%s\n",__FUNCTION__,__LINE__,argv[2]);
        return -1;
    }

    FILE *fp_out=fopen("out.h264","w+");
    if(fp_out==NULL){
        printf("[%s%d] fopen err:out.h264 \n",__FUNCTION__,__LINE__);
        return -1;
    }

    FAIL_IF_ERROR( 2 != sscanf( argv[1], "%dx%d", &width, &height ), "resolution not specified or incorrect\n" );



    /* Get default params for preset/tuning */
    #if 0
    if( x264_param_default_preset( &param, "medium", NULL ) < 0 )
        goto fail;
    #else
    //Set to fastest
    //Specific parameters can be found in base c::param_ apply_ preset
    //Zerorate does not delay. After this setting, one frame goes in and one frame goes out. No delay
    //char speed[][16]={"ultrafast","superfast","veryfast","faster","fast","medium","slow","slower","veryslow","placebo"};
    if( x264_param_default_preset( &param, "ultrafast", "zerolatency" ) < 0 )
    //if( x264_param_default_preset( &param, "ultrafast", NULL ) < 0 )
        goto fail;
    #endif
    /* Configure non-default params */
    param.i_bitdepth = 8;
    param.i_csp = X264_CSP_I420;//color space 
    param.i_width  = width;
    param.i_height = height;
    param.b_vfr_input = 0; //Setting to 1 will control the timestamp?
    param.b_repeat_headers = 1; //Add sps pps before each I frame
    param.b_annexb = 1;//Each frame carries the start code 00 00 01. If it is set to 0, 00 00 01 is not added, but the data size value of this frame is stored. (4 bytes)

    param.i_bframe =0; // B-frame not used / * how many b-frame between 2 references pictures*/

    //param.i_keyint_min =
    param.i_keyint_max = 5; //gop

//https://blog.csdn.net/bingqingsuimeng/article/details/79197901
    param.rc.b_mb_tree = 0;//Real time coding is strongly recommended as 0

    /* 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_in ) != (unsigned)luma_size )
            break;
        if( fread( pic.img.plane[1], 1, chroma_size, fp_in ) != (unsigned)chroma_size )
            break;
        if( fread( pic.img.plane[2], 1, chroma_size, fp_in ) != (unsigned)chroma_size )
            break;

        pic.i_pts = i_frame;
        int64_t t1=getNowUs();
        
        printf("[%s%d]in:%d %ld\n",__FUNCTION__,__LINE__,i_frame, t1);
        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 )
        {
            int64_t t2=getNowUs();
            printf("[%s%d]out:%d %ld\n",__FUNCTION__,__LINE__,out_frame, t2);
            //SLICE_TYPE_P SLICE_TYPE_B SLICE_TYPE_I 
            //nal->i_type nal_unit_type_e
            /*enum sei_payload_type_e
            {
                SEI_BUFFERING_PERIOD       = 0,
                SEI_PIC_TIMING             = 1,
                SEI_PAN_SCAN_RECT          = 2,
                SEI_FILLER                 = 3,
                SEI_USER_DATA_REGISTERED   = 4,
                SEI_USER_DATA_UNREGISTERED = 5,
                SEI_RECOVERY_POINT         = 6,
                SEI_DEC_REF_PIC_MARKING    = 7,
                SEI_FRAME_PACKING          = 45,
                SEI_ALTERNATIVE_TRANSFER   = 147,
            };*/
            printf("[%s%d]in:%d---%dout,taketimes:%ld,nal->i_type:%d\n",__FUNCTION__,__LINE__,i_frame,out_frame,t2-t1,nal->i_type);
            out_frame++;
            if( !fwrite( nal->p_payload, i_frame_size, 1, fp_out ) )
                goto fail;
        }
    }
    /* Flush delayed frames */
    //After "ZERODEGREE" is set, there will be no 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 )
        {
            int64_t t2=getNowUs();
            printf("[%s%d]out-delayframe:%d %ld\n",__FUNCTION__,__LINE__,out_frame, t2);
            out_frame++;
            if( !fwrite( nal->p_payload, i_frame_size, 1, fp_out ) )
                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:
    fclose(fp_in);
    fclose(fp_out);
    return -1;
}

makefile: just one copy of the output when referring to make example

all:
	gcc -Wno-maybe-uninitialized -Wshadow -O3 -ffast-math -m64  -Wall -I. -I../x264-master/my_install/include -std=gnu99 -D_GNU_SOURCE -mpreferred-stack-boundary=6 -fomit-frame-pointer -fno-tree-vectorize -fvisibility=hidden  -c my_encoder.c -o my_encoder.o
	gcc -o my_encoder  my_encoder.o ../x264-master/my_install/lib/libx264.a -m64  -lm -lpthread -ldl

#my_ encoder. C demo file
#../ x264-master/my_install/lib/libx264.a lib264 Library

Keywords: h264

Added by darkhorn on Mon, 03 Jan 2022 20:53:34 +0200