本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8
ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv
,分析其内部逻辑。
a.mp4下载链接:百度网盘,提取码:nl0s 。
本文主要分析 process_input_packet()
的内部逻辑,流程图如下:
process_input_packet()
的逻辑并不是特别复杂,下面贴上代码图,重点已用红笔标记出来。
从图中可以看到,process_input_packet() 的主要逻辑主要有 5 点。
1,对 ist->dts
,ist->next_dts
,ist->pts
,ist->next_pts
进行赋值。
saw_first_ts
那里利用 has_b_frame
对第一个 dts
赋值,这里计算出的 dts
在本文的命令下,是等于 pkt->dts
的,我也不知道这块代码在什么场景下 有用,应该是兼容性处理,在当前命令下 计算出的 dts
等于 pkt->dts
,第二个框框已经用了 pkt->dts
来赋值,所以第一个框框的代码是多余的。 这里的 next_dts
的计算,是根据上一个 pkt
的 dts
加上 pkt->duration
或者 帧率时间,推算得到的。
2,第二点主要就是调用了 decode_video() 跟 decode_audio() 来进行后续处理,这两个函数里面不单只会解码packet,还会把 解码出来的 farme
发送给 filter,如果 filter
还没有初始化,会初始化再发送。
3,第五个红色框框,如果解码出 第一个 frame ,ist->got_out
会设置成 1。
4,第六个红色框框,while 循环的最后,repeating = 1
,这里主要是用来实现,发送一个 packet ,调用多次 avcodec_receive_frame()
读取 frame,因为某个packet发给解码器之后,可能可以读取出多个Frame,这里 repeating 是控制多次读取,直到读不到。可以看到,decode_video() 函数的传参,如果repeating =1 ,就会传NULL。
5,最后一个 return !eof_reached
,这里 eof_reached
在什么情况会是 1?当文件读到末尾, av_read_frame()
已经 读不出 pakcet
,读不出 packet,就会往 process_input_packet()
,传递 NULL packet,就会导致 process_input_packet()
生成一个 packet.size = 0
的 pkt
,然后把这样一个pkt
丢给解码器,告诉解码器冲刷数据,解码器冲刷完数据,已经没有 frame可以刷出来了,eof_reached
才会是1。
这里有一点需要注意,文件已经没有pakcet
读出来,不代表解码器已经冲刷完数据,可能 packet.data = NULL
的 pkt
发送给解码器之后,还要循环几次才能读完后面刷出来的 frame。
process_input_packet()
的流程图如下。
©版权所属:知识星球:弦外之音,QQ:2338195090。
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1。