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(…)函数调用。

  1. 5.4.1. reap_filters //ffmpeg.c
  2. static int reap_filters(int flush)
  3. {
  4. AVFrame *filtered_frame = NULL;//该指针将存储一个经过滤镜处理后的buffer,并送给encoder
  5. int i;
  6. /* Reap all buffers present in the buffer sinks */
  7. for (i = 0; i < nb_output_streams; i++) {//一路video,一路audio,那么nb_output_streams = 2
  8. OutputStream *ost = output_streams[i];
  9. OutputFile *of = output_files[ost->file_index];
  10. AVFilterContext *filter;
  11. AVCodecContext *enc = ost->enc_ctx;
  12. int ret = 0;
  13. if (!ost->filter)
  14. continue;
  15. filter = ost->filter->filter;//OutputStream的filter指针指向buffersink.c定义的AVFilterContext。也就是本文讨论的,最后一个AVFilterContext
  16. if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) {
  17. return AVERROR(ENOMEM);
  18. }
  19. filtered_frame = ost->filtered_frame;
  20. while (1) {
  21. double float_pts = AV_NOPTS_VALUE; // this is identical to filtered_frame.pts but with higher precision
  22. //av_buffersink_get_frame_flags定义在buffersink.c,用于从FIFO读出一帧
  23. ret = av_buffersink_get_frame_flags(filter, filtered_frame,
  24. AV_BUFFERSINK_FLAG_NO_REQUEST);
  25. if (ret < 0) {
  26. //省略,检查ret
  27. //如果ret<0,不是别的错误,那认为还没有数据,跳出循环
  28. break;
  29. }
  30. switch (filter->inputs[0]->type) {
  31. case AVMEDIA_TYPE_VIDEO:
  32. //do_video_out函数将会做video编码
  33. do_video_out(of->ctx, ost, filtered_frame, float_pts);
  34. break;
  35. case AVMEDIA_TYPE_AUDIO:
  36. //do_audio_out函数将会做audioo编码
  37. do_audio_out(of->ctx, ost, filtered_frame);
  38. break;
  39. default:
  40. // TODO support subtitle filters
  41. av_assert0(0);
  42. }
  43. av_frame_unref(filtered_frame);
  44. }
  45. }
  46. return 0;
  47. }
  48. 前一节说了,filter_frame(…)的最终结果是,把buffer存在了buffersink.c的FIFO里。
  49. 那么,这一节,说的其实就是一个从buffersink的FIFO读数据,并编码的过程。
  50. 从上面可知,av_buffersink_get_frame_flags函数,从buffersink读取一帧数据,放到filtered_frame。
  51. 5.4.2. do_video_out //ffmpeg.c
  52. static void do_video_out(AVFormatContext *s,
  53. OutputStream *ost,
  54. AVFrame *next_picture,
  55. double sync_ipts)
  56. {
  57. int ret;
  58. AVCodecContext *enc = ost->enc_ctx;
  59. int nb_frames, nb0_frames, i;
  60. //省略300字
  61. for (i = 0; i < nb_frames; i++) {
  62. AVFrame *in_picture;
  63. if (i < nb0_frames && ost->last_frame) {
  64. in_picture = ost->last_frame;
  65. } else
  66. in_picture = next_picture;
  67. //省略300字
  68. ost->frames_encoded++;
  69. //开始编码
  70. ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
  71. }
  72. ///省略300字
  73. }
  74. 该函数很长,做了很多杂事,但关键代码就是调用编码函数avcodec_encode_video2

http://blog.csdn.net/leixiaohua1020/

https://blog.csdn.net/newchenxf/article/details/51364105

相关