FFmpeg-4.0 的filter机制的架构与实现.之三 Filter实现的源码分析
回调函数的调用流程,以单滤镜设置(如 -vf "delogo")为例
init()
query_format(); // 输入输出的格式查询: 列出滤镜支持的格式列表
config_input();
config_output();
for (;;) {undefined
request_frame();
filter_frame();
uninit();
ffmpeg如何编码
当我们写了一个filter,把视频做处理后,ffmpeg是如何把它编码的呢?
通过研究,发现编码的源头函数是reap_filters(…),它会被transcode_step(…)函数调用。
- 5.4.1. reap_filters //ffmpeg.c
- static int reap_filters(int flush)
- {
- AVFrame *filtered_frame = NULL;//该指针将存储一个经过滤镜处理后的buffer,并送给encoder
- int i;
-
- /* Reap all buffers present in the buffer sinks */
- for (i = 0; i < nb_output_streams; i++) {//一路video,一路audio,那么nb_output_streams = 2
- OutputStream *ost = output_streams[i];
- OutputFile *of = output_files[ost->file_index];
- AVFilterContext *filter;
- AVCodecContext *enc = ost->enc_ctx;
- int ret = 0;
-
- if (!ost->filter)
- continue;
- filter = ost->filter->filter;//OutputStream的filter指针指向buffersink.c定义的AVFilterContext。也就是本文讨论的,最后一个AVFilterContext
-
- if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) {
- return AVERROR(ENOMEM);
- }
- filtered_frame = ost->filtered_frame;
-
- while (1) {
- double float_pts = AV_NOPTS_VALUE; // this is identical to filtered_frame.pts but with higher precision
- //av_buffersink_get_frame_flags定义在buffersink.c,用于从FIFO读出一帧
- ret = av_buffersink_get_frame_flags(filter, filtered_frame,
- AV_BUFFERSINK_FLAG_NO_REQUEST);
- if (ret < 0) {
- //省略,检查ret
- //如果ret<0,不是别的错误,那认为还没有数据,跳出循环
- break;
- }
- switch (filter->inputs[0]->type) {
- case AVMEDIA_TYPE_VIDEO:
- //do_video_out函数将会做video编码
- do_video_out(of->ctx, ost, filtered_frame, float_pts);
- break;
- case AVMEDIA_TYPE_AUDIO:
- //do_audio_out函数将会做audioo编码
- do_audio_out(of->ctx, ost, filtered_frame);
- break;
- default:
- // TODO support subtitle filters
- av_assert0(0);
- }
-
- av_frame_unref(filtered_frame);
- }
- }
-
- return 0;
- }
-
- 前一节说了,filter_frame(…)的最终结果是,把buffer存在了buffersink.c的FIFO里。
- 那么,这一节,说的其实就是一个从buffersink的FIFO读数据,并编码的过程。
- 从上面可知,av_buffersink_get_frame_flags函数,从buffersink读取一帧数据,放到filtered_frame。
-
- 5.4.2. do_video_out //ffmpeg.c
- static void do_video_out(AVFormatContext *s,
- OutputStream *ost,
- AVFrame *next_picture,
- double sync_ipts)
- {
- int ret;
- AVCodecContext *enc = ost->enc_ctx;
- int nb_frames, nb0_frames, i;
- //省略300字
- for (i = 0; i < nb_frames; i++) {
- AVFrame *in_picture;
- if (i < nb0_frames && ost->last_frame) {
- in_picture = ost->last_frame;
- } else
- in_picture = next_picture;
- //省略300字
- ost->frames_encoded++;
- //开始编码
- ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
- }
- ///省略300字
- }
-
- 该函数很长,做了很多杂事,但关键代码就是调用编码函数avcodec_encode_video2
http://blog.csdn.net/leixiaohua1020/
https://blog.csdn.net/newchenxf/article/details/51364105
