send_frame_to_filters滤镜处理—ffmpeg.c源码分析
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
send_frame_to_filters()
函数会把 AVFrame
发送给输入流关联的所有入口滤镜进行处理。但是它的代码是比较简单的,如下:
可以看到 send_frame_to_filters()
只不过就是在循环调 ifilter_send_frame()
函数而已。
send_frame_to_filters()
函数只有一个重点,就是在调 ifilter_send_frame()
之前,创建多了一份 AVFrame
的引用,为什么需要这样做呢?
答:因为发送完 AVFrame
给滤镜之后,就会调 av_frame_unref()
把引用减一,滤镜容器是异步线程,所以为了让滤镜容器里面能拿到 AVFrame
的内存,需要先把引用加一,要不发送完之后就立即释放内存,滤镜线程就拿不到内存了,如下:
下面来分析一下 ifilter_send_frame()
函数。
ifilter_send_frame()
函数首先需要对比 InputFilter ifilter
跟 AVFrame
的格式,采样率,宽高等参数,如果不一样,就把 need_init
设置为 1,如下:
由于 ifilter->format
一开始是设置为 -1,所以第一次 need_init
肯定会设置为 1。
need_reinit
为 1,就会用 AVFrame
对 ifilter
进行赋值,我把这个 ifilter_parameters_from_frame
调用成为 InputFilter
初始化。
if (need_reinit) {
ret = ifilter_parameters_from_frame(ifilter, frame);
if (ret < 0)
return ret;
}
注意一个滤镜容器(FilterGraph)是有多个 InputFilter
,这只是对其中一个进行初始化。
当 FilterGraph
里面还有 InputFilter
没有初始化的时候,就不能把 AVFrame
发送给滤镜,只能先写进去队列(ifilter->frame_queue
),如下:
InputFilter
的 format
不等于 -1 就代表初始化完成了。
当 FilterGraph
里面所有的 InputFilter
都初始化完成了,就会调 configure_filtergraph()
来配置滤镜链,里面会打开滤镜容器。如下:
configure_filtergraph()
执行完之后,滤镜容器就打开了,就可以调 av_buffersrc_add_frame_flags()
往滤镜发送 AVFrame
了。如下:
细心的读者可能会发现了,在未打开滤镜容器之前,写进去队列(ifilter->frame_queue
)的数据没处理么?
其实是有处理,就在 configure_filtergraph()
里面,它里面打开滤镜之后,就会把队列缓存的数据都往滤镜里面发送。
具体介绍,推荐阅读《configure_filtergraph配置滤镜容器》
做下小总结, ifilter_send_frame()
函数主要的职责是调 av_buffersrc_add_frame_flags()
把 AVFrame
往 滤镜里发送,如下:
ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, AV_BUFFERSRC_FLAG_PUSH);
但是,代码不一定就会跑到 av_buffersrc_add_frame_flags()
。前提是滤镜容器已经打开了。
如果没有打开,就会先初始化 InputFilter
,等所有 InputFilter
都初始化之后,再打开滤镜容器。
感谢 NETINT(镕铭微电子) 赞助《FFmpeg原理》免费版一书的服务器费用,下面是 VPU 产品介绍