ffmpeg源码分析二:main函数和transcode函数

首先从main函数看起,关键解释部分已加注释,该函数在ffmpeg.c文件中。代码如下:

int main(int argc, char **argv)
{
    int ret;
    int64_t ti;
    // 注册清理回调函数
    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);

    term_init();

    /* 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);
//     }

    current_time = ti = getutime();
    // 音视频转换函数
    if (transcode() < 0)
        exit_program(1);
    ti = getutime() - ti;
    if (do_benchmark) {
        printf("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;
}

下面阅读transcode函数:

static int transcode(void)
{
    int ret, i;
    AVFormatContext *os;
    OutputStream *ost;
    InputStream *ist;
    int64_t timer_start;

    // 初始化,打开所有输出流的编码器,打开所有输入流的解码器,写入所有输出文件的文件头。后面详细介绍。
    ret = transcode_init();
    if (ret < 0)
        goto fail;

    if (stdin_interaction) {
        av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
    }

    timer_start = av_gettime();

#if HAVE_PTHREADS
    if ((ret = init_input_threads()) < 0)
        goto fail;
#endif
   
    // 循环,直到收到系统信号才退出 。
    while (!received_sigterm) {
        int64_t cur_time= av_gettime();

        /* if 'q' pressed, exits */
        if (stdin_interaction)
            if (check_keyboard_interaction(cur_time) < 0)
                break;

        /* check if there's any stream where output is still needed */
        if (!need_output()) {
            av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");
            break;
        }

        // 具体的转换工作,后面将详细介绍。
        ret = transcode_step();
        if (ret < 0) {
            if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
                continue;

            av_log(NULL, AV_LOG_ERROR, "Error while filtering.\n");
            break;
        }

        /* dump report by using the output first video and audio streams */
        print_report(0, timer_start, cur_time);
    }
#if HAVE_PTHREADS
    free_input_threads();
#endif

    // 文件处理完了,把缓冲中剩余的数据写到输出文件中。
    /* at the end of stream, we must flush the decoder buffers */
    for (i = 0; i < nb_input_streams; i++) {
        ist = input_streams[i];
        if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
            output_packet(ist, NULL);
        }
    }
    flush_encoders();

    term_exit();

    /* write the trailer if needed and close file */
    // 为输出文件写文件尾(有的不需要)。  
    for (i = 0; i < nb_output_files; i++) {
        os = output_files[i]->ctx;
        av_write_trailer(os);
    }

    /* dump report by using the first video and audio streams */
    print_report(1, timer_start, av_gettime());

    // 关闭所有编码器。
    /* close each encoder */
    for (i = 0; i < nb_output_streams; i++) {
        ost = output_streams[i];
        if (ost->encoding_needed) {
            av_freep(&ost->st->codec->stats_in);
            avcodec_close(ost->st->codec);
        }
    }

    // 关闭所有解码器。
    /* close each decoder */
    for (i = 0; i < nb_input_streams; i++) {
        ist = input_streams[i];
        if (ist->decoding_needed) {
            avcodec_close(ist->st->codec);
            if (ist->hwaccel_uninit)
                ist->hwaccel_uninit(ist->st->codec);
        }
    }

    /* finished ! */
    ret = 0;

 fail:
#if HAVE_PTHREADS
    free_input_threads();
#endif

    if (output_streams) {
        for (i = 0; i < nb_output_streams; i++) {
            ost = output_streams[i];
            if (ost) {
                if (ost->stream_copy)
                    av_freep(&ost->st->codec->extradata);
                if (ost->logfile) {
                    fclose(ost->logfile);
                    ost->logfile = NULL;
                }
                av_freep(&ost->st->codec->subtitle_header);
                av_freep(&ost->forced_kf_pts);
                av_freep(&ost->apad);
                av_dict_free(&ost->opts);
                av_dict_free(&ost->swr_opts);
                av_dict_free(&ost->resample_opts);
            }
        }
    }
    return ret;
}



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FFmpeg 是一套功用十分强大的开源媒体框架,被广泛应用于媒体处理和转码等方面。该框架由 C 语言编写实现,其核心功能主要包括媒体解码、编码、过滤、封装等。下面我们主要从源码层面展开分析FFmpeg 作为开源软件,源码具有极高的可读性和可扩展性,但是难度也很大,不适合初学者。如果我们要逐层分析 FFmpeg 常用流程,我们可以先从 FFmpeg 的主要模块开始,例如 AVFormatContext、AVCodecContext、AVFrame 等数据结构。 在一个典型的流程中,FFmpeg 首先通过 AVFormatContext 处理输入文件,然后通过 AVCodecContext 解码处理后输出到 AVFrame,最后通过 AVFormatContext 实现封装输出成文件。 此外,FFmpeg 还可以通过多种输入视频流格式(例如 RTSP,HTTP,FLV 等)对视频进行采集和处理,并支持多种输出格式(例如 MP4,FLV,AVI 等)。同时,FFmpeg 还能够实现多幅图像的合并、重采样和音视频混合等功能。要实现这些功能,我们需要从源代码层面着手。 FFmpeg 的源代码分别包括 libavformat、libavcodec、libavutil 等库,实现不同的功能。其中,libavformat 库主要提供了媒体文件的输入输出、封装和解封装等功能,libavcodec 库主要提供了音视频编码解码的功能,libavutil 库则提供了一些公共的工具函数和数据类型定义。通过逐层深入分析,我们可以深入地了解 FFmpeg 的实现原理,以及如何使用 FFmpeg 库来完成多种媒体处理和转码任务。 总的来说,FFmpeg 是一款优秀的媒体处理和转码库,它的源码具有极高的可扩展性和自定义性,同时难度也较大。如果要深入了解和使用 FFmpeg,需要有扎实的编程背景和相关经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值