ffmpeg 代码阅读笔记2/2
调试才是你掌握核心的钥匙,把不懂的东西变成懂. 令你有很多收获.
调试让你搞得懂来龙去脉.
有益的文档帮助你节省时间!
============================================================
0. ffmpeg 主流程
============================================================
ret = ffmpeg_parse_options(argc, argv); //一招完成所有初始化.
if (transcode() < 0) // 一招完成循环处理所有数据.
transcode()退出就结束了. 有点一分为2的思想.
============================================================
乙: transcode() 分析
============================================================
ret = transcode_init();
while(1) ret = transcode_step(); // 循环执行
============================================================
一. transcode_init() 分析,
============================================================
1. ret = init_input_stream(i, error, sizeof(error)); // 重要的是它打开了输入流
(ret = avcodec_open2(ist->dec_ctx, codec, &ist->decoder_opts)) < 0)
输出流init 重要项没看见.
============================================================
二. transcode_step() 分析
============================================================
0. choose_output(); //选择ost->st->cur_dts 比较小的流来处理
1. 先跳过filter 部分,目前未使用.
2. ret = process_input(ist->file_index);
3. return reap_filters(0);
2.2 process_input
----------------------------------------
ret = get_input_packet(ifile, &pkt);--> return av_read_frame(f->ctx, *pkt); //获得一个包
进行了一番时间戳检查,修正等,然后
process_input_packet ();
decode_audio()/decode_video();
decode(); //call avcodec_send_packet(),avcodec_receive_frame()
//然后
err = send_frame_to_filters(ist, decoded_frame);
2.3 reap_filters()
----------------------------------------
static int reap_filters(int flush); //从过滤器中获取, 收割filters
/* Get and encode new output from any of the filtergraphs, without causing activity.*/
注意以下几点,原来也是如此的简单! 注意区分是底层的handle 还是它自己的数据!!!
/* Reap all buffers present in the buffer sinks */ 取得所有缓冲接收器中存在的缓冲.
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
OutputFile *of = output_files[ost->file_index];
int ret = 0;
// ost->filter 只是OutputFilter, 是ffmpeg 自定义的结构(应用)
// ost->filter->filter 才是是AVFilterContext !!!, 是libav 定义的结构(库)
// ost->filter->graph 只是FilterGraph, 是ffmpeg 自定义的结构(应用)
// ost->filter->graph->graph 才是AVFilterGraph !!!, 是libav 定义的结构(库)
if (!ost->filter || !ost->filter->graph->graph) continue;
//原来的AVFilterGraph 是空的,它是何时变成非空的,这才是关键! 你需要跟踪调试!才能掌握.
//参见后述.
AVFilterContext *filter = ost->filter->filter; // 这才是真正的AVFilterContext
while (1) { // 获取frame
ret = av_buffersink_get_frame_flags(filter, filtered_frame, AV_BUFFERSINK_FLAG_NO_REQUEST);
//编码frame, do_audio_out()/do_video_out()
switch (av_buffersink_get_type(filter)) {
case AVMEDIA_TYPE_VIDEO:
do_video_out(of, ost, filtered_frame);
break;
case AVMEDIA_TYPE_AUDIO:
do_audio_out(of, ost, filtered_frame);
break;
default:
// TODO support subtitle filters
av_assert0(0);
}
av_frame_unref(filtered_frame);
}
}
//实际的编码操作, do_audio_out()/do_video_out()
ret = avcodec_send_frame(enc, frame);
ret = avcodec_receive_packet(enc, pkt);
----------------------------------------
AVFilterGraph 配置的实现
----------------------------------------
调用链如下图:
#0 configure_filtergraph (fg=0x5555558bb200) at ffmpeg_filter.c:991
#1 ifilter_send_frame (ifilter=0x5555558afd80, frame=0x55555599ddc0) at ffmpeg.c:2238
#2 send_frame_to_filters (ist=0x555555af3d40, decoded_frame=0x55555599ddc0) at ffmpeg.c:2319
#3 decode_audio (ist=0x555555af3d40, pkt=0x555555895a00, got_output=0x7fffffffd488, decode_failed=0x7fffffffd490) at ffmpeg.c:2386
#4 process_input_packet (ist=0x555555af3d40, pkt=0x55555597fe80, no_eof=0) at ffmpeg.c:2671
#5 process_input (file_index=0) at ffmpeg.c:4610
#6 transcode_step () at ffmpeg.c:4750
#7 transcode () at ffmpeg.c:4804
当转换时,以audio 为例,解码audio,向filter 发送,当发现没有配置时,进行一次初始化配置.
配置完filter, 即可向里边添加frame 了