马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
在编码时 video 的环境如下:
1. 在 yuv 数据 阶段,和时间相关参数如下:
yuv数据我们在设置的时候要 设置参数,此中和时间相关的是 yuvfps 和 timebase,yuvfps一般是每秒25帧,yuvfps=25;timebase 一般设置为 1000,000 这样 我们就能盘算出来再yuv数据阶段一张图片泯灭时间为: 1/25 * 1000000 = 40,000
整理:也就是说:我们在yuv阶段,yuv的timebase 是1000000,yuv的pts 的盘算是每次读取一张图片,就给pts+= 1.0 / yuvfps * videotimebase
这两个值都是开辟者设定的。
2. 当yuv数据在变成AVFrame时的过程中,时间相关
在从yuv 变成 avframe的过程中,肯定要弄一个AVCodecContext,这时候要设置AVCodecContext 的相关参数,除了video的三要素外,还需要设置 AVCodecContext.timebase 为 1000000。
在将yuv数据变成AVFrame的代码中,我们需要重新盘算并设置 AVFrame的pts。如何设置呢?
yuv的pts * yuv的timebase = 这张图片显示的时间 = avframe阶段的 pts * avframe阶段的 timebase
avframe阶段的 pts = yuv的pts * yuv的timebase/avframe阶段的 timebase
整理:
avframe阶段的 timebase就是avcodeContext 中的timebase,对于video 来说:avcodeContext 中的timebase也是开辟者手动设自动的。
在盘算出来avframe的pts 后,记得设置avframe的pts的值。
3.当从avframe变成avpacket的过程中。时间相关
在前面,我们盘算了avframe的pts,并设置了avframe的pts,也知道avframe的timebase 就是avcodecContext的timebase。
那么avpacket 的pts 也要重新盘算。
AVFrame pts * avFrame timebase = 这张图片的显示时间 = avpacket pts * avpacket timebase
也就是:
avpacket pts = AVFrame pts * avFrame timebase / avpacket timebase
AVFrame pts 和 avFrame timebase 的值我们在前面已经知道了,
关键题目是 avpacket timebase 是怎么来的呢?
实际上是,avpacket timebase 使用的是 AVStream中的timebase,那么AVStream 的timebase又是怎么来的呢?当我们使用
- avformat_write_header(this->_avformatContext,nullptr);
复制代码 发送头部的后,AVStream的timebase就有值了,差别的格式,AVStream的timebase差别,对于video来说,许多都是1,90000.
值的注意的是,我们在将avframe变成avpacket的时候,这时候还没有调用 avformat_write_header这个方法,因此这时候avpacket 中的pts,dts ,duration是和avframe的pts,dts,duration一样的值。
4. 终极将avpacket 变成 MP4大概flv,时间相关
上述第三步,更加准确的说:在avframe 变成 avpacket后,avpacket的pts和 avframe的pts 是一样的。
一般环境下,我们在调用了 是当 调用了 avformat_write_header 方法后,才会将 avpacket->pts重新盘算,使用的 avpacket的pts会是 avstream中的pts
而且在这个时候 会将 avpacket 的dts,duration,pts都盘算完成。
- dst_timebase = this->_video_avstream->time_base;
- avpacket->pts = av_rescale_q(avpacket->pts, src_timebase,dst_timebase);
- avpacket->dts = av_rescale_q(avpacket->dts, src_timebase,dst_timebase);
- avpacket->duration = av_rescale_q(avpacket->duration, src_timebase,dst_timebase);
复制代码
在编码时 audio 的环境如下:
1. 在 pcm 数据 阶段,和时间相关参数如下:
我们以 44100 的pcm 转换成 aac 的例子说明:
- 我们在还是pcm数据的时候,会计算出来1024个样本帧的花费的时间,具体的计算公式为 1024/44100 * 1000,000。这里1000000 是转化为微秒的时间基。
复制代码
2 avframe阶段的盘算,和时间相关参数如下:
/// 当我们将读取的数据要存储到avframe中的时候,就需要重新盘算avframe的pts,使用avframe对应的时间基
/// 首先要明白的是的 对于avframe 对应的时间基用的是avcodec中的timebase,那么avcodec中的timebase是怎么知道的呢?观察源码会发现,音频编码器上下文的timebase 是在 avcodec_open2方法中 设置的,且设置的值的为 avcodecContext中的 sample_rate 的倒数,也就是1/44100
/// 注意,avcodecContext中的 sample_rate实际上是需要user 手动的设定的,因此你就明白了为什么在 编码的时候肯定要设置 编码器上下文的 sample_rate了
/// 那么现在我们有了三个值了,一个是 pcm的pts,一个是pcm的时间基,一个是avframe的时间基,求avframe的pts?
/// pcm的pts * pcm 的时间基 = avframe 的pts * avframe的时间基(也就是avcodecContext的timebase)
/// 结论为 :avframe 的pts = pcm的pts * pcm 的时间基 / avframe的时间基(avcodecContext的timebase)
/// 为了防止内存溢出等题目,使用ffmpeg给我们提供的方法 :av_rescale_q(pts, AVRational{1, (int)time_base}, this->_avcodecContext->time_base)
/// 可以观察 :av_rescale_q方法的本质,就是第一个参数乘以第二个参数,末了除以第三个参数
3 avpacket阶段的盘算
/// 到这里,我们终极生成的avpacket的 pts,dts,duration的值又是多少呢?
/// 实际上,在我们这个阶段,avpacket的 pts,dts,duration的值会直接 copy avframe中的pts,dts,duration(都是通过avcodec_receive_packet(this->_avcodecContext, avpacket) 方法传递的)
/// 这明显是不合理的。我们可以回首一下 avframe 和avpacket 的本质,avframe装的是未压缩的pcm数据,avpacket装的是压缩过的pcm数据(也就是类似aac这样的数据)
/// 那么依然存在着 avframe的pts(当前已经存储在avpacket的pts) 转化成 真正的avpacket的pts的题目,那么avframe的时间基我们是知道的--是avcodec中的timebase,那么 这个真正的avpacket的时间基是什么呢?是avstream中的timebase
/// 那么avstream中的timebase怎么知道呢?实际上差别的编码器,它的avstream中的timebase是差别的,ffmpeg在你调用 avformat_write_header(fmt_ctx_, NULL);函数的时候就确定了您的timebase 是多少了,这也很容易想到,对于差别的编码器,它的头部信息肯定就含有了 timebase这样重要的信息
/// avframe 的pts(当前旧的avpacket的pts) * avframe的时间基(avcodec的时间基) = 真正的avpacket的pts * 真正的avpacket的时间基(也就是avstream的时间基)
/// 结论为 :真正的avpacket的pts = avframe 的pts(当前旧的avpacket的pts) * avframe的时间基(avcodec的时间基) / 真正的avpacket的时间基(也就是avstream的时间基)
/// 对应代码在 muxer.cpp的sendPacket中。
在解码时 video 的环境如下:
在解码时 audio 的环境如下:
/// 关于时间题目,看了网上的资料,大抵结论如下,
- ///1、AVStream的time_base的单位是秒。每种格式的time_base的值不一样,根据采样来计算,比如mpeg的pts、dts都是以90kHz来采样的,所以采样间隔就是1/900000秒。
复制代码- ///2、AVCodecContext的time_base单位同样为秒,不过精度没有AVStream->time_base高,大小为1/framerate。
复制代码- ///3、AVPacket下的pts和dts以AVStream->time_base为单位(数值比较大),时间间隔就是AVStream->time_base。
复制代码- ///4、AVFrame里面的pkt_pts和pkt_dts是拷贝自AVPacket,同样以AVStream->time_base为单位;而pts是为输出(显示)准备的,以AVCodecContex->time_base为单位。
复制代码- ///5、输入流InputStream下的pts和dts以AV_TIME_BASE为单位(微秒),至于为什么要转化为微秒,可能是为了避免使用浮点数。
复制代码- ///6、输出流OutputStream涉及音视频同步,结构和InputStream不同,暂时只作记录,不分析
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |