ffmpeg里面处理两路输入的模块都放在libavfilter/dualinput.c里面
首先定义了一个context用于描述dualinput的信息
typedef struct FFDualInputContext {
FFFrameSync fs;
AVFrame *(*process)(AVFilterContext *ctx, AVFrame *main, const AVFrame *second);
int shortest; ///< terminate stream when the second input terminates
int repeatlast; ///< repeat last second frame
int skip_initial_unpaired; ///< Skip initial frames that do not have a 2nd input
} FFDualInputContext;
process是一个函数指针,以vf_overlay为例,调用过程为
static AVFrame *do_blend(AVFilterContext *ctx, AVFrame *mainpic,
const AVFrame *second)
{
......
}
static av_cold void uninit(AVFilterContext *ctx)
{
OverlayContext *s = ctx->priv;
ff_dualinput_uninit(&s->dinput);
......
}
s->dinput.process = do_blend;
但是到这里还是不明白main和second怎么传入do_blend的
用gdb分析,先b do_blend再bt,得到的结果为
(gdb) bt
#0 do_blend (ctx=0x2b6d7a0, mainpic=0x2b6cb80, second=0x2fa7e00) at libavfilter/vf_overla
y.c:772
#1 0x000000000066e3dc in process_frame (fs=0x2e60708) at libavfilter/dualinput.c:37
#2 0x000000000046fe07 in ff_framesync_process_frame (fs=0x2e60708, all=0) at libavfilter/
framesync.c:291
#3 0x000000000046fee5 in ff_framesync_filter_frame (fs=0x2e60708, inlink=0x2e61f00, in=0x
2fa7e00) at libavfilter/framesync.c:312
#4 0x000000000066e5c3 in ff_dualinput_filter_frame (s=0x2e60708, inlink=0x2e61f00, in=0x2
fa7e00) at libavfilter/dualinput.c:79
#5 0x0000000000541d9e in filter_frame (inlink=0x2e61f00, inpicref=0x2fa7e00) at libavfilt
er/vf_overlay.c:805
#6 0x0000000000458992 in ff_filter_frame_framed (link=0x2e61f00, frame=0x2fa7e00) at liba
vfilter/avfilter.c:1116
#7 0x0000000000458ff8 in ff_filter_frame_to_filter (link=0x2e61f00) at libavfilter/avfilt
er.c:1264
#8 0x00000000004591f0 in ff_filter_activate_default (filter=0x2b6d7a0) at libavfilter/avf
ilter.c:1315
#9 0x0000000000459350 in ff_filter_activate (filter=0x2b6d7a0) at libavfilter/avfilter.c:
1476
#10 0x000000000045db83 in ff_filter_graph_run_once (graph=0x29d6020) at libavfilter/avfilt
ergraph.c:1449
#11 0x000000000045dd70 in get_frame_internal (ctx=0x2e612e0, frame=0x0, flags=1, samples=0
) at libavfilter/buffersink.c:110
#12 0x000000000045ddcd in av_buffersink_get_frame_flags (ctx=0x2e612e0, frame=0x0, flags=1
) at libavfilter/buffersink.c:121
#13 0x000000000045d916 in avfilter_graph_request_oldest (graph=0x29d6020) at libavfilter/a
vfiltergraph.c:1402
#14 0x000000000042f25a in transcode_from_filter (graph=0x25154c0, best_ist=0x7fffffffdcf8)
at ffmpeg.c:4455
#15 0x000000000042f511 in transcode_step () at ffmpeg.c:4521
#16 0x000000000042f789 in transcode () at ffmpeg.c:4597
#17 0x000000000042fe75 in main (argc=8, argv=0x7fffffffdf88) at ffmpeg.c:4803
可以看出,17~6都是解码器完成的,filter只完成5~1即可
ffmpeg里面多路输入都要用framesync来同步
每一个输入在初始化过滤器的时候会有一个权重
权重最大的会触发on_event
on_event是一个callback函数
dualinput不过是利用framesync重写了一遍
static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
{
OverlayContext *s = inlink->dst->priv;
//注意这里已经执行过config_input
av_log(inlink->dst, AV_LOG_DEBUG, "Incoming frame (time:%s) from link #%d\n", av_ts2timestr(inpicref->pts, &inlink->time_base), FF_INLINK_IDX(inlink));
return ff_dualinput_filter_frame(&s->dinput, inlink, inpicref);
}
这个函数在dualinput.c里面
int ff_dualinput_filter_frame(FFDualInputContext *s,
AVFilterLink *inlink, AVFrame *in)
{
return ff_framesync_filter_frame(&s->fs, inlink, in);
}
直接return ff_framesync_filter_frame
位于framesync.h里面
int ff_framesync_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
AVFrame *in);
/**
* Request a frame on the filter output.
*
* This function can be the complete implementation of all filter_frame
* methods of a filter using framesync if it has only one output.
*/
如果多路输入一个输出需要这个函数充当filter_frame()的角色
其实现为
int ff_framesync_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
AVFrame *in)
{
int ret;
if ((ret = ff_framesync_process_frame(fs, 1)) < 0)
return ret;
if ((ret = ff_framesync_add_frame(fs, FF_INLINK_IDX(inlink), in)) < 0)
return ret;
if ((ret = ff_framesync_process_frame(fs, 0)) < 0)
return ret;
return 0;
}
这个函数分别执行三个函数,小于0则退出
在vf_overlay.c里面三个都执行了,do_blend是在第三次执行的时候被调用的
ff_framesync_process_frame的定义
int ff_framesync_process_frame(FFFrameSync *fs, unsigned all)
{
int ret, count = 0;
av_assert0(fs->on_event);
while (1) {
ff_framesync_next(fs);
if (fs->eof || !fs->frame_ready)
break;
if ((ret = fs->on_event(fs)) < 0)
//在这里调用process_frame,具体在下面说
return ret;
ff_framesync_drop(fs);
count++;
if (!all)
break;
}
if (!count && fs->eof)
return AVERROR_EOF;
return count;
}
注意 FFFrameSync里面有
typedef struct FFFrameSync {
......
int (*on_event)(struct FFFrameSync *fs);
/**
* Opaque pointer, not used by the API
*/
......
} FFFrameSync;
dualinput.c的代码
static int process_frame(FFFrameSync *fs)
{
......
if (secondpic && !ctx->is_disabled)
mainpic = s->process(ctx, mainpic, secondpic);
ret = ff_filter_frame(ctx->outputs[0], mainpic)
}
int ff_dualinput_init(AVFilterContext *ctx, FFDualInputContext *s)
{
......
s->fs.on_event = process_frame;
......
对dinput进行初始化,在这里存放不同视频的帧数据
void ff_dualinput_uninit(FFDualInputContext *s)
{
ff_framesync_uninit(&s->fs);
}
void ff_framesync_uninit(FFFrameSync *fs);
/**
* Add a frame to an input
*
* Typically called from the filter_frame() method.
*
* @param fs frame sync structure
* @param in index of the input
* @param frame input frame, or NULL for EOF
*/
对于双路输入,自己写过滤器的话,