关闭

ffmpeg.c

735人阅读 评论(0) 收藏 举报
分类:

本文主要以转码为例子,流程主要为解析命令,转码,转码又可以细分为:打开编解码器,开始转码,关闭编解码器。

FFmpeg的总体函数调用结构图如下图所示:

命令解析

ffmpeg_parse_options

命令解析主要在ret = ffmpeg_parse_options(argc, argv);

find_option

 po = find_option(options, opt);  //从全局const OptionDef options[]中查找opt,opt是字符串,对应OptionDef的第一列。

void opt_output_file(void *optctx, const char *filename)
{
    //略…
    err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
 
    if (!oc) {
        print_error(filename, err);
        exit(1);
    }
    //略…
   new_video_stream();
   …
   new_audio_stream();
   …
   new_subtitle_stream ();
    //略…
}

avformat_find_stream_info

        avformat_find_stream_info()函数可以读取一部分视音频数据并且获得一些相关的信息。函数正常执行后返回值大于等于0。该函数上下文部分是调节起播延迟效果最明显的地方。函数分析流的时间主要由传入的AVFormatContext的probesize 和 max_analyze_duration两个属性决定,probesize是探测读入大小,默认值为32K;max_analyze_duration默认值为5S。在网络状况比较好的情况下可分别设置4K和1S,也可根据具体情况在起播画面效果、起播延迟、分析成功率等因素间取舍。这两个参数的设置在avformat_open_input()函数对结构体AVFormatContext处理完成后进行设置。


在ffmpeg_parse_options中,会调用libavfornat/utils.c里的avformat_find_stream_info,其中会会调用try_decode_frame(avcodec_open2,avcodec_decode_xxx,),avcodec_close;重要步骤为:
1.查找解码器:find_decoder()
2.打开解码器:avcodec_open2()
3.读取完整的一帧压缩编码的数据:read_frame_internal()
4.解码一些压缩编码数据:try_decode_frame()

update_stream_timings
start_time1 = av_rescale_q(st->start_time, st->time_base,AV_TIME_BASE_Q);
start_time = FFMIN(start_time, start_time1);
ic->start_time = start_time;  //90000基转成1000000基,修改了开始时间。如133200变成1480000。

try_decode_frame
从try_decode_frame()的定义可以看出,该函数首先判断视音频流的解码器是否已经打开,如果没有打开的话,先打开相应的解码器。接下来根据视音频流类型的不同,调用不同的解码函数进行解码:视频流调用avcodec_decode_video2(),音频流调用avcodec_decode_audio4(),字幕流调用avcodec_decode_subtitle2()。解码的循环会一直持续下去直到满足了while()的所有条件。while()语句的条件中有一个has_codec_parameters()函数,用于判断AVStream中的成员变量是否都已经设置完毕。该函数在avformat_find_stream_info()中的多个地方被使用过。

转码

转码的内容封装在transcode函数里,会重新打开解码器,编码器。

# 打开编解码器

如上图,打开编码器,到最后还是调用具体的编码器(X264编码器),X264初始化的函数为int X264_init(AVCodecContext *avctx),可以看出ffmpeg通过AVCodecContext结构体,将编码参数传递给x264的x264_param_t。

process_input_packet

该函数对帧数据进行解码并通过所有适用的过滤器进行处理。时间戳校准和字幕处理的工作也在这个函数中进行。最后,在函数返回之前,已解码的帧被复制到每个相关的输出流。
for (i = 0; pkt && i < nb_output_streams; i++) {
  ...  // check constraints
  do_streamcopy(ist, ost, pkt);   
}

transcode_step()

transcode_step()调用了如下函数:

process_input():完成解码工作。

transcode_step()函数调用reap_filters()函数(第1424行)来循环遍历每个输出流。reap_filters()函数的for循环负责收集缓冲区中待处理的帧,并将这些帧进行编码,然后封装到一个输出文件中。

reap_filters()

reap_filters()主要完成了编码的工作。其函数调用结构如下图所示。

reap_filters()调用了如下函数
av_buffersink_get_buffer_ref():从AVFilterContext中取出一帧解码后的数据(结构为AVFilterBufferRef,可以转换为AVFrame)。
avfilter_copy_buf_props():AVFilterBufferRef转换为AVFrame。
do_audio_out():编码音频。
do_video_out():编码视频。
avfilter_unref_buffer():释放资源。
 
do_video_out()调用了如下函数
avcodec_encode_video2():编码一帧视频。
write_frame():写入编码后的视频压缩数据。
 
write_frame()调用了如下函数:
av_bitstream_filter_filter():使用AVBitStreamFilter的时候,会调用此函数进行处理。
av_interleaved_write_frame():写入压缩编码数据。
 
do_audio_out()调用的函数与do_video_out()基本上一样。唯一的不同在于视频编码函数avcodec_encode_video2()变成了音频编码函数avcodec_encode_audio2()。

copy怎么工作?
在main()->ffmpeg-parse_options()->open_files()->open_output_file()->new_video->stream()->new_output_stream()->choose_encoder()有:
if (!strcmp(codec_name, "copy"))
        ost->stream_copy = 1;

另一个地方会        ost->encoding_needed = !ost->stream_copy,表明是否需要解码。
在transcode_init中
 if (ost->stream_copy) {
    所有的参数都用解码后得到的参数。
}else{
   使用转码参数。
   调用init_simple_filtergraph();有这句ost->filter = fg->outputs[0];这样ost->filter就有了值,在reap_filters就会进行编码(会判断ost->filter)。
}


多线程问题

#要想使用多线程,需要编译的时候加上--enable-pthread。

#有些编解码不支持多线程,配置了线程数也不会起作用。

参考:http://blog.csdn.net/leixiaohua1020/article/details/39760711


dup!

打印位置:

static void do_video_out(AVFormatContext *s,
                         OutputStream *ost,
                         AVFrame *next_picture,
                         double sync_ipts)
{

    if (nb_frames > (nb0_frames && ost->last_dropped) + (nb_frames > nb0_frames)) {
        if (nb_frames > dts_error_threshold * 30) {
            av_log(NULL, AV_LOG_ERROR, "%d frame duplication too large, skipping\n", nb_frames - 1);
            nb_frames_drop++;
            return;
        }
        nb_frames_dup += nb_frames - (nb0_frames && ost->last_dropped) - (nb_frames > nb0_frames);
        av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
    }

}

"Drop" means it has dropped a frame during encoding.
"Dup" means it has duplicated a frame during encoding.


0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

ffmpeg.c函数结构简单分析(画图)

前一阵子研究转码的时候看了FFmpeg的源代码。由于ffmpeg.c的代码相对比较长,而且其中有相当一部分是AVFilter有关的代码(这一部分一直不太熟),因此之前学习FFmpeg的时候一直也没有好好分析一下其源代码。最近正好看了看AVFilter的知识,顺便就看了下FFmpeg的源代码,在这里画...
  • leixiaohua1020
  • leixiaohua1020
  • 2014-10-04 00:12
  • 25224

如何用vs08编译ffmpeg

本文主要参考:如何用vc6编译ffmpeg, 并单步调试。 1. 下载最新git版本的源代码(http://ffmpeg.zeranoe.com/builds/, 本例下载的是2011-12-12版本) 2. 放到MSYS环境里配置,生成config.h文件。mingw gcc是能顺利编译通过整...
  • fallenink
  • fallenink
  • 2013-03-12 15:46
  • 1814

MAC下使用ndk编译ffmpeg

ffmpeg是c语言的库,主要作用是对音视频进行编解码等操作。是android进阶必须要掌握的一门技术。通过使用ffmpeg可以提高对android ndk的认识和熟练度。第一步当然就是编译ffmpeg编译为android可以使用的.so文件。
  • ZACH_ZHOU
  • ZACH_ZHOU
  • 2017-12-20 17:56
  • 60

ffmpeg.c源码中关于参数设置的流程

ffmpeg,ffmpeg参数设置源码分析
  • sidumqz
  • sidumqz
  • 2016-10-16 15:19
  • 909

在VC2010下编译ffmpeg.c(版本2.1.4)

在VC2010下编译ffmpeg.c(版本2.1.4)
  • relar
  • relar
  • 2014-03-18 15:37
  • 2963

最新版ffmpeg源码分析一:框架

(ffmpeg v0.9) 框架 最新版的ffmpeg中发现了一个新的东西:avconv,而且ffmpeg.c与avconv.c一个模样,一研究才发现是libav下把ffmpeg改名为avconv了. 到底libav与ffmpeg现在是什么个关系?我也搞得希里糊涂的,先不管它了. ...
  • heng615975867
  • heng615975867
  • 2014-03-19 17:27
  • 2424

ffmpeg.c函数结构简单分析(画图) .

前一阵子研究转码的时候看了FFmpeg的源代码。由于ffmpeg.c的代码相对比较长,而且其中有相当一部分是AVFilter有关的代码(这一部分一直不太熟),因此之前学习FFmpeg的时候一直也没有好好看一下其源代码。最近正好看了看AVFilter的知识,顺便就看了下FFmpeg的源代码,在这里画图...
  • pbooq26826
  • pbooq26826
  • 2014-10-04 13:28
  • 617

ffmpeg.c函数结构简单分析(画图)

前一阵子研究转码的时候看了FFmpeg的源代码。由于ffmpeg.c的代码相对比较长,而且其中有相当一部分是AVFilter有关的代码(这一部分一直不太熟),因此之前学习FFmpeg的时候一直也没有好好看一下其源代码。最近正好看了看AVFilter的知识,顺便就看了下FFmpeg的源代码,在这里画图...
  • wishfly
  • wishfly
  • 2016-07-22 17:10
  • 439

ffmpeg.c函数结构简单分析(画图)

祭奠雷博!!! 前一阵子研究转码的时候看了FFmpeg的源代码。由于ffmpeg.c的代码相对比较长,而且其中有相当一部分是AVFilter有关的代码(这一部分一直不太熟),因此之前学习FFmpeg的时候一直也没有好好看一下其源代码。最近正好看了看AVFilter的知识,顺便就看了下FFmpeg...
  • xiaojun111111
  • xiaojun111111
  • 2016-10-14 14:06
  • 472

FFMPEG源码分析(1)--持续更新

以FFMPEG 1.0为参考,对FFMPEG源码分析,其中调用以H264为例 一、main()中;在ffmpeg.c文件中 1、OptionsContext o ={ 0 }: 初始化结构体变量o,这个结构体主要是一些参数选项; 初始化的结果是:整型和浮点型都为0,指针型成员都为NUL...
  • beitiandijun
  • beitiandijun
  • 2013-01-04 21:50
  • 9251
    个人资料
    • 访问:615291次
    • 积分:9092
    • 等级:
    • 排名:第2382名
    • 原创:206篇
    • 转载:396篇
    • 译文:0篇
    • 评论:42条
    最新评论