关于ffmpeg的time_base的随笔及其他若干编程细节

time_base:

含义:时间基数,可以理解为刻度,或者时间轴上面的小格子,这个小格子具体是多少,要根据time_base在不同的结构中有不同的数值。

哪些结构中有time_base

1、AVFormatContext:中streams:当在解封装的时候,AVFormatContext的streams中的time_base是从rtsp流或者媒体文件流中获取,因为avformat_find_stream_info会填充AVFormatContext中的相相关信息。此时time_base可能是如下:

也就是1/90000秒,也就是此时time_base在时间轴上每个格子大小是1/90000.而此时音视频的数据的状态是AVPacket状态,也就是处于压缩状态。在此时packet的dts、pts就是以这个刻度(1/90000)来作为度量的,比如:

那么这个pts=42902和dts=42902是什么意思呢?

pts:present time stamp:显示时间戳  :42902代表,在音视频显示时间轴上42902*1/90000秒的时候显示这个packet的内容

dts:decode time stamp:解码时间戳:42902代表,在音视频解码时间轴上42902*1/90000秒的时候解码这个packet的内容

所以要正确的处理一帧数据,time_base、dts、pts三个缺一不可。而且这三个值在不同状态(解封装、解码、编码、封装)是不同的。三个值在不同的状态下是绑定出现的。

上面注意到packet结构中还有个duration字段,这个字段的意思是:两帧之间的间隔,也是以time_base为刻度的。是下一帧-当前帧的间隔,上图中duration=7500表示下一帧-当前帧的间隔占了7500个格子也就是7500个1/90000。转化为秒的话就是7500*1/90000

所以,在解封装的时候,必须将time_base保存下来,后面的解码、编码、封装、推流等操作都需要这个time_base

2、在解码时:

在解码阶段time_base:在AVCodecContext中。而这个时间基数是在我们自己在调用avcodec_alloc_context3这个函数创建AVCodeContext后自己设定的。我们比较下在解封装和解码两个阶段通过一个包的dts pts的变化,入下图:是解封装后packet中的pts和dts

而下面这张图是:解码后Frame中的pts:

关于拉流,解码,编码,推流不同阶段的pts、 dts、 durations的转换

问题1:不同阶段time_base是怎么产生的?

            * 在拉流阶段:time_base是从文件或者网络流中直接获取的,当打开文件或者网络流后,执行avformat_find_stream_info(),此函数会将相关参数,包括time_base字段内容填充到AVFormatContext中,在AVFormatContext的Strames中。

            * 解码阶段:time_base在AVCodecContext结构中,有开发者自己填写,具体填写多少,可以从拉流时AVFormatContext的streams[0]->codec->framerate的倒数作为初始化参数

            * 编码:同解码阶段

            * 推流:可以从拉流阶段的AVFormatContext的streams[0]->time_base获取

问题2:什么时候需要进行time_base转换

            * 解码之前:在调用avcodec_send_packet之前,需要将packet进行以不同事件基数转换,此时packet中国的pts,dts,durations都是以拉流阶段的AVFormatContext.Stream中的time_base为刻度的,需要转换为以解码上下文AVCodecContext.time_base为刻度的pts、dts、durations

            * 编码之后,av_interleaved_write_frame函数调用之前,此时需要将以AVCodecContext.time_base为刻度的pts、dts、duration转化为以封装器AVFormatContext.streams中的time_base为刻度的pts,dts、duration

问题3:使用什么函数转换

           调用av_packet_rescale_ts(packet,原来的time_base,将要转换的time_base),此函数会转化dts、duration如果B帧为0此时dts=pts

*封装格式的time_base

在封装的时候,调用avformat_alloc_output_context2这个函数的时候,需要指定封装格式,调用后,FFmpeg会自动填充time_base,此时time_base在AVFormatContext.streams中,不需要调用者,自己填写封装格式的time_base

对于拉流,解码,编码,推流过程中的pts\dts\duration的转换

*在执行avcodec_send_packet执行函数之前,需要将av_read_frame读取到的AVPacket进行转化,转换之前,AVPacket中的pts\dts\duration都是以解封装上下文AVFormatContext.streams[]中的time_base为刻度的。因为需要解码,所以要把AVPacket中的pts\dts\duration转为以解码上下文AVCodecContext.time_base为刻度的值。而AVCodecContext.time_base值的设定,需要程序员自己设置,那么设置多少合适呢?可以设置为解封转上下文AVFormatContext.stream[].avg_frame_rate.num/AVFormatContext.stream[].avg_frame_rate.den也就相当于输入流的fps.

*执行完上述步骤后,AVPaket中的pts\dts\duration就是以解码上下AVFormatContext.time_base为刻度的了。然后正常执行avcodec_receive_frame,得到解码后的AVFrame,可以进行二次创作,比如添加字体,缩放图像等操作,继而进行编码,编码后得到等待推流的AVPacket,这个过程中,pts\dts\duration不会发生改变。

*推流,在执行av_interleaved_write_frame之前,需要将编码后的AVPacket进行time_base转化,因为,封装器的time_base是根据封装格式确定,如上图。所以要将编码后的AVPacket转化为以封装器time_base为刻度的值。转换后在调用av_interleaved_write_frame,发送。

*特别需要注意,如果在转化过程中,time_base使用错误,将会导致播放时常,比如播放延迟越来越大等等。

*相关函数:av_packet_rescale_ts函数会同时转化pts\sts\duration

                  如果想分开转换,可以用av_rescale_q_rnd。

关于ffmpeg拉流延迟

关于ffmpeg编码延迟

关于FFmpeg编码质量

关于specified frame type (3) at 358 is not compatible with keyframe interval警告的解决方法

解决出现Could not find ref with POCXX问题解决方法

关于RTSP推流:

RTMP推流封装格式是FLV。RTMP官方FFmpeg不支持H265推流。

如果要用RTSP推流的话,封装格式设置为:rtsp,但是推流地址应该是rtp://ip:port格式,url不是rtsp://XXX,应该是rtp://XXX.如果使用rtsp://XXX ffmpeg将会提示 protocol not found.而且不会推流成功!

 关于推流GOP:

GOP:Group Of Picture:就是图片组,一般一个图片组的第一针是I帧(关键帧,帧内解码),后面跟随的是P帧(Prediction预测帧:该帧需要在前一帧(I或者P)解码出来的图像的基础上叠加差异图像,从而得出当前P帧的完成图像),GOP决定了每个多少帧有一个I帧。GOP将会影响编码速度。GOP越小,关键帧越多,编码速度越慢,因为关键帧越多,需要处理的编码数据量越大,编码速度越慢。反之,GOP越大,I帧越少,P帧越多,P帧是当前帧和前一帧的差异,所以编码时只要处理差异数据,编码数量就会小的多,编码速度就会越快。占用的cpu资源(软件码时),就越少。

                   

关于Could not find ref with POC XX

当输入跟不上编解码的时候就会打印这些,假如说你能控制输入,当你把输入速率调低,比如10p/s那么就会出现上述现象,当调为30p/s就不会出现,所以关键是输入,至于怎么解决这个问题,根据不同的情况解决就好

FFmepg:AVPacket源码完整解析

FFmepg:AVPacket源码完整解析_狂奔的鱼の博客-CSDN博客

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
AV_TIME_BASEFFmpeg中定义的一个宏,它表示时间单位的基准。具体地说,它表示每秒钟的时间单位数。在FFmpeg中,时间单位被表示为有理数,即分子和分母的形式。AV_TIME_BASE的值为1000000,表示每秒钟有1000000个时间单位。 中提到了不同的time_base。在FFmpeg中,每个AVStream(音视频流)都有一个time_base字段,用于表示该流中的时间单位。AVStream的time_base与AVCodecContext的time_base字段有关。AVStream的time_base比AVCodecContext的time_base精度更高,即分子的值更小。例如,AVStream的time_base为1/90000,而AVCodecContext的time_base为1/30(假设frame_rate为30)。在相同的pts和dts情况下,以AVStream的time_base为单位的数值会比以AVCodecContext的time_base为单位的数值大。 因此,AV_TIME_BASE是一个重要的宏,用于在FFmpeg中进行时间单位的换算和处理。了解AV_TIME_BASE的含义和使用方式对于阅读和理解FFmpeg的代码非常重要。 来源:ffmpeg存在多个时间基准(time_base),对应不同的阶段(结构体),每个time_base具体的值不一样,ffmpeg提供函数在各个time_base中进行切换。搞清楚各个time_base的来源,对于阅读ffmpeg的代码很重要。 来源:InputStream(AV_TIME_BASE) 到 AVPacket(AVStream->time_base) 来源:AVStream->time_base 比 AVCodecContext->time_base 精度要高(数值要小),比如AVStream->time_base为1/90000,而AVCodecContext->time_base为1/30(假设frame_rate为30);同样的pts和dts,以AVStream->time_base为单位,数值要比以AVCodecContext->time_base为单位要大。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值