ffmpeg.c源码阅读

入口函数main

int main(int argc, char **argv)
{
    int i, ret;
    int64_t ti;

    init_dynload();

    register_exit(ffmpeg_cleanup);

    setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */

    av_log_set_flags(AV_LOG_SKIP_REPEATED);
    parse_loglevel(argc, argv, options);

    if(argc>1 && !strcmp(argv[1], "-d")){
        run_as_daemon=1;
        av_log_set_callback(log_callback_null);
        argc--;
        argv++;
    }
    //注册
    avcodec_register_all();
#if CONFIG_AVDEVICE
    avdevice_register_all();
#endif
    avfilter_register_all();
    av_register_all();
    avformat_network_init();
    //显示版本信息
    show_banner(argc, argv, options);
    //解析输入参数,并打开输入输出
    /* parse options and open all input/output files */
    ret = ffmpeg_parse_options(argc, argv);
    if (ret < 0)
        exit_program(1);

    if (nb_output_files <= 0 && nb_input_files == 0) {
        show_usage();
        av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
        exit_program(1);
    }

    /* file converter / grab */
    if (nb_output_files <= 0) {
        av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");
        exit_program(1);
    }

//     if (nb_input_files == 0) {
//         av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n");
//         exit_program(1);
//     }

    for (i = 0; i < nb_output_files; i++) {
        if (strcmp(output_files[i]->ctx->oformat->name, "rtp"))
            want_sdp = 0;
    }
    //开始转码
    current_time = ti = getutime();
    if (transcode() < 0)
        exit_program(1);
    ti = getutime() - ti;
    if (do_benchmark) {
        av_log(NULL, AV_LOG_INFO, "bench: utime=%0.3fs\n", ti / 1000000.0);
    }
    av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n",
           decode_error_stat[0], decode_error_stat[1]);
    if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])
        exit_program(69);

    exit_program(received_nb_signals ? 255 : main_return_code);
    return main_return_code;
}

main 函数主要做了如下工作:

  1. 注册各种信息
  2. 解析参数并打开输入输出
  3. 持续转码
  4. 退出,清理

main - avcodec_register_all

以avcodec_register_all为例主要学习

void avcodec_register_all(void)
{
    static AVOnce control = AV_ONCE_INIT;
    ff_thread_once(&control, register_all);
}
//只初始化一次
#define ff_thread_once(control, routine) pthread_once(control, routine)
//传入的静态函数
static void register_all(void)
{
    /* hardware accelerators */
    REGISTER_HWACCEL(H263_VAAPI,        h263_vaapi);
                       ...
    REGISTER_PARSER(H264,               h264);
    REGISTER_PARSER(HEVC,               hevc);
                       ...
}
//宏定义
//REGISTER_PARSER(H264,               h264);
#define REGISTER_PARSER(X, x)                                           \
    {                                                                   \
        //extern AVCodecParser ff_h264_parser;  
        extern AVCodecParser ff_##x##_parser;                           \
        //if (CONFIG_H264_PARSER) 
        if (CONFIG_##X##_PARSER)                                        \
            //av_register_codec_parser(&ff_h264_parser);                 \
            av_register_codec_parser(&ff_##x##_parser);                 \
    }

//注册
void av_register_codec_parser(AVCodecParser *parser)
{
    do {
        parser->next = av_first_parser;
    } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser));
}

一句话概括就是:遍历链表并把当前的AVCodec加到链表的尾部。
关于注册可以参考雷神的blog

main-show_banner

void show_banner(int argc, char **argv, const OptionDef *options)
{
    int idx = locate_option(argc, argv, options, "version");
    if (hide_banner || idx)
        return;
    print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);
    print_all_libs_info(INDENT|SHOW_CONFIG,  AV_LOG_INFO);
    print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);
}

打印一些信息,如下图
ffmpeg.c源码阅读_第1张图片

main - ffmpeg_parse_options

AVOption 结构体

移步到雷神的博客

你可能感兴趣的:(ffmpeg源码阅读)