ffmpeg 源码分析-转码6

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8

ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑。

a.mp4下载链接:百度网盘,提取码:nl0s 。

本文主要分析reap_filter()的内部逻辑,流程图如下

在此贴上 reap_filter() 的代码图。红笔重点,绿笔不会执行或者不重要。

可以看到,reap_filters() 的逻辑比较简单。先 init_output_stream() 初始化 输出流,然后不断循环,调用 av_buffersink_get_frame_flags()不断从 buffersink 那里读取 经过 filter 转换后的 frame,知道读不到就会跳出 while。随后就是 do_video_out() 跟 do_audio_out() 的调用。

do_video_out() 的逻辑其实是比较复杂的,里面貌似实现了一个帧率转换算法之类的东西。但是如图,绿色框出来的duration,应该是根据不用场景计算duration,不用特别关注,还有delta0deltanb0_framesnb_framesost->last_nb0_frames,这些变量的赋值跟计算,会搞得你头晕目眩。不利于初学者理解。 所以这里我直接指名,这些变量都不用特别关注,看一遍就行了,看不懂也没事,这些算法应该需要结合一个具体的帧率变换命令才能更好的解释。 只需要关注 nb_frames ,因为他在后面的for循环里面用了,而且nb_frames 在本命令下经常是1。


do_video_out()里面还有个强制 I 帧算法,也不用特别关注,本命令没用到。因为代码量太大,这里只截图了很关键的段落。

重点已经用流程图,画笔画出来了。可以看到 do_video_out() 往编码器发一个 frame 就会不断地读取packet,直到读不到packet。也就是说,如果 buffersink 没有frame 出来了,编码器也就不会再有packet,缓存中的 packet 都不会有,因为上次已经循环读完了所有 pakcet,这个比较重要。所以不需要处理 avcodec_receive_packet() 的EOF。

还有一个output_packet()没有分析。本命令没有用 bitstream_filters ,所以output_packet()实际上是直接调用了 write_packet()。

write_packet() 的流程比较简单。主要的一点是写缓存 muxing_queue,这里解释一下什么情况会写缓存。

输出文件的所有流,包括音频,视频流,全部初始化完成就会调用 avformat_write_header(),然后设置 of->header_written 为 1 。

of->header_written 等于 0 就代表有输出流没有初始化,init_output_stream()函数没有调用。什么情况会没有调用呢?

视频还没解码出任何一帧,导致 ifilter_send_frame() 没有执行,之前说过 ifilter_send_frame() 里面会调用 configure_filtergraph()configure_filtergraph() 没调用就会导致 ost->filter->graph->graph 没有初始化。 然后在reap_filter()函数内部 大概1437行,判断 ost->filter->graph->graph 时候执行 continue 了,导致没有执行 init_output_stream ,没有初始化视频流,所以没有调用

avformat_write_header() 写入 header。

do_audio_out() 相对简单原理类似,这里不分析了。

原文 ffmpeg 源码分析-转码6 - 掘金

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

猜你喜欢

转载自blog.csdn.net/yinshipin007/article/details/131744306