ffmpeg.c源码阅读

来源:互联网 发布:手机淘宝链接怎么弄 编辑:程序博客网 时间:2024/05/28 06:08

入口函数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);}

打印一些信息,如下图
这里写图片描述

main - ffmpeg_parse_options

AVOption 结构体

移步到雷神的博客

原创粉丝点击