x264源代码简单分析 x264命令行工具(x264 exe)

本文深入分析了x264项目中的x264.exe命令行工具,详细介绍了main()函数如何调用parse()解析命令行参数,以及encode()如何进行编码。在parse()中,x264_param_default()和x264_param_default_preset()设置参数默认值,而help()提供使用帮助。
摘要由CSDN通过智能技术生成
               

=====================================================

H.264源代码分析文章列表:

【编码 - x264】

x264源代码简单分析:概述

x264源代码简单分析:x264命令行工具(x264.exe)

x264源代码简单分析:编码器主干部分-1

x264源代码简单分析:编码器主干部分-2

x264源代码简单分析:x264_slice_write()

x264源代码简单分析:滤波(Filter)部分

x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)

x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

x264源代码简单分析:宏块编码(Encode)部分

x264源代码简单分析:熵编码(Entropy Encoding)部分

FFmpeg与libx264接口源代码简单分析

【解码 - libavcodec H.264 解码器

FFmpeg的H.264解码器源代码简单分析:概述

FFmpeg的H.264解码器源代码简单分析:解析器(Parser)部分

FFmpeg的H.264解码器源代码简单分析:解码器主干部分

FFmpeg的H.264解码器源代码简单分析:熵解码(EntropyDecoding)部分

FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)

FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)

FFmpeg的H.264解码器源代码简单分析:环路滤波(Loop Filter)部分

=====================================================


本文简单分析x264项目中的命令行工具(x264.exe)的源代码。该命令行工具可以调用libx264将YUV格式像素数据编码为H.264码流。



函数调用关系图

X264命令行工具的源代码在x264中的位置如下图所示。



X264命令行工具的源代码的调用关系如下图所示。
 

从图中可以看出,X264命令行工具调用了libx264的几个API完成了H.264编码工作。使用libx264的API进行编码可以参考《 最简单的视频编码器:基于libx264(编码YUV为H.264)》,这个流程中最关键的API包括:
x264_param_default():设置参数集结构体x264_param_t的缺省值。
x264_encoder_open():打开编码器。
x264_encoder_headers():输出SPS,PPS,SEI等信息。
x264_encoder_encode():编码输出一帧图像。
x264_encoder_close():关闭编码器。

在X264命令行工具中,main()首先调用parse()解析输入的命令行参数,然后调用encode()进行编码。parse()首先调用x264_param_default()为存储参数的结构体x264_param_t赋默认值;然后在一个大循环中调用getopt_long()逐个解析输入的参数,并作相应的处理;最后调用select_input()和select_output()解析输入文件格式(例如yuv,y4m…)和输出文件格式(例如raw,flv,MP4…)。encode()首先调用x264_encoder_open()打开H.264编码器,然后调用x264_encoder_headers()输出H.264码流的头信息(例如SPS、PPS、SEI),接着进入一个循环并且调用encode_frame()逐帧编码视频,最后调用x264_encoder_close()关闭解码器。其中encode_frame()中又调用了x264_encoder_encode()完成了具体的编码工作。下文将会对上述流程展开分析。



main()

main()是x264控制台程序的入口函数,定义如下所示。
//主函数int main( int argc, char **argv )//参数集    x264_param_t param;    cli_opt_t opt = {
   0};    int ret = 0;    FAIL_IF_ERROR( x264_threading_init(), "unable to initialize threading\n" )#ifdef _WIN32    FAIL_IF_ERROR( !get_argv_utf8( &argc, &argv ), "unable to convert command line to UTF-8\n" )    GetConsoleTitleW( org_console_title, CONSOLE_TITLE_SIZE );    _setmode( _fileno( stdin ),  _O_BINARY );    _setmode( _fileno( stdout ), _O_BINARY );    _setmode( _fileno( stderr ), _O_BINARY );#endif    /* Parse command line */    //解析命令行输入    if( parse( argc, argv, ¶m, &opt ) < 0 )        ret = -1;#ifdef _WIN32    /* Restore title; it can be changed by input modules */    SetConsoleTitleW( org_console_title );#endif    /* Control-C handler */    signal( SIGINT, sigint_handler );    //编码    if( !ret )        ret = encode( ¶m, &opt );    /* clean up handles */    if( filter.free )        filter.free( opt.hin );    else if( opt.hin )        cli_input.close_file( opt.hin );    if( opt.hout )        cli_output.close_file( opt.hout, 0, 0 );    if( opt.tcfile_out )        fclose( opt.tcfile_out );    if( opt.qpfile )        fclose( opt.qpfile );#ifdef _WIN32    SetConsoleTitleW( org_console_title );    free( argv );#endif    return ret;}

可以看出main()的定义很简单,它主要调用了两个函数:parse()和encode()。main()首先调用parse()解析输入的命令行参数,然后调用encode()进行编码。下面分别分析这两个函数。



parse()

parse()用于解析命令行输入的参数(存储于argv[]中)。它的定义如下所示。
//解析命令行输入static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ){    char *input_filename = NULL;    const char *demuxer = demuxer_names[0];    char *output_filename = NULL;    const char *muxer = muxer_names[0];    char *tcfile_name = NULL;    x264_param_t defaults;    char *profile = NULL;    char *vid_filters = NULL;    int b_thread_input = 0;    int b_turbo = 1;    int b_user_ref = 0;    int b_user_fps = 0;    int b_user_interlaced = 0;    cli_input_opt_t input_opt;    cli_output_opt_t output_opt;    char *preset = NULL;    char *tune = NULL;    //初始化参数默认值    x264_param_default( &defaults );    cli_log_level = defaults.i_log_level;    memset( &input_opt, 0, sizeof(cli_input_opt_t) );    memset( &output_opt, 0, sizeof(cli_output_opt_t) );    input_opt.bit_depth = 8;    input_opt.input_range = input_opt.output_range = param->vui.b_fullrange = RANGE_AUTO;    int output_csp = defaults.i_csp;    opt->b_progress = 1;    /* Presets are applied before all other options. */    for( optind = 0;; )    {        int c = getopt_long( argc, argv, short_options, long_options, NULL );        if( c == -1 )            break;        if( c == OPT_PRESET )            preset = optarg;        if( c == OPT_TUNE )            tune = optarg;        else if( c == '?' )            return -1;    }    if( preset && !strcasecmp( preset, "placebo" ) )        b_turbo = 0;    //设置preset,tune    if( x264_param_default_preset( param, preset, tune ) < 0 )        return -1;    /* Parse command line options */    //解析命令行选项    for( optind = 0;; )    {        int b_error = 0;        int long_options_index = -1;        int c = getopt_long( argc, argv, short_options, long_options, &long_options_index );        if( c == -1 )        {            break;        }        //不同的选项做不同的处理        switch( c )        {            case 'h':                help( &defaults, 0 );//"-h"帮助菜单                exit(0);            case OPT_LONGHELP:                help( &defaults, 1 );                exit(0);            case OPT_FULLHELP:                help( &defaults, 2 );                exit(0);            case 'V':                print_version_info();//打印版本信息                exit(0);            case OPT_FRAMES:                param->i_frame_total = X264_MAX( atoi( optarg ), 0 );                break;            case OPT_SEEK:                opt->i_seek = X264_MAX( atoi( optarg ), 0 );                break;            case 'o':                output_filename = optarg;//输出文件路径                break;            case OPT_MUXER:                FAIL_IF_ERROR( parse_enum_name( optarg, muxer_names, &muxer ), "Unknown muxer `%s'\n", optarg )                break;            case OPT_DEMUXER:                FAIL_IF_ERROR( parse_enum_name( optarg, demuxer_names, &demuxer ), "Unknown demuxer `%s'\n", optarg )                break;            case OPT_INDEX:                input_opt.index_file = optarg;                break;            case OPT_QPFILE:                opt->qpfile = x264_fopen( optarg, "rb" );                FAIL_IF_ERROR( !opt->qpfile, "can't open qpfile `%s'\n", optarg )                if( !x264_is_regular_file( opt->qpfile ) )                {                    x264_cli_log( "x264", X264_LOG_ERROR, "qpfile incompatible with non-regular file `%s'\n", optarg );                    fclose( opt->qpfile );                    return -1;                }                break;            case OPT_THREAD_INPUT:                b_thread_input = 1;                break;            case OPT_QUIET:                cli_log_level = param->i_log_level = X264_LOG_NONE;//设置log级别                break;            case 'v':                cli_log_level = param->i_log_level = X264_LOG_DEBUG;//设置log级别                break;            case OPT_LOG_LEVEL:                if( !parse_enum_value( optarg, log_level_names, &cli_log_level ) )                    cli_log_level += X264_LOG_NONE;                else                    cli_log_level = atoi( optarg );                param->i_log_level = cli_log_level;//设置log级别                break;            case OPT_NOPROGRESS:                opt->b_progress = 0;                break;            case OPT_TUNE:            case OPT_PRESET:                break;            case OPT_PROFILE:                profile = optarg;                break;            case OPT_SLOWFIRSTPASS:                b_turbo = 0;                break;            case 'r':                b_user_ref = 1;                goto generic_option;            case OPT_FPS:                b_user_fps = 1;                param->b_vfr_input = 0;                goto generic_option;            case OPT_INTERLACED:                b_user_interlaced = 1;                goto generic_option;          
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值