——:ffmpeg的分层结构
写这篇文章的时候先把ffmpeg分层问题大致说明一下,我们按照最常见的”转码程序”和”摄像头采集”以及”播放器”三个模型总结
1:转码
转码基本流程:flv格式数据->h264/aac数据->yuv/pcm数据->h264/aac数据->mp4格式数据
a:我们把flv格式数据或者mp4格式数据这一层叫做mux/demux层或者是复用层有些人习惯于叫做封装层,这里叫做mux/demux层下面同理
b.我们把h264/aac数据这一层叫做编解码层或者codec/decode,这里叫做codec/decodec层下面同理
c.我们把yuv/pcm数据这一层叫做原始数据层或者Raw data层,这里叫做Raw data 层下面同理
2.摄像头采集
摄像头采集基本流程:yuv/pcm数据->h264/aac数据–>flv格式数据
a.我们把yuv/pcm数据这一层叫做原始数据层或者Raw data层,这里叫做Raw data 层下面同理
b.我们把h264/aac数据这一层叫做编解码层或者codec/decode,这里叫做codec/decodec层下面同理
c.我们把flv格式数据或者mp4格式数据这一层叫做mux/demux层或者是复用层有些人习惯于叫做封装层,这里叫做mux/demux层下面同理
3.播放器
播放器基本流程:flv格式数据->h264/aac数据–>yuv/pcm数据
a.我们把flv格式数据或者mp4格式数据这一层叫做mux/demux层或者是复用层有些人习惯于叫做封装层,这里叫做mux/demux层下面同理
b.我们把h264/aac数据这一层叫做编解码层或者codec/decode,这里叫做codec/decodec层下面同理
c.我们把yuv/pcm数据这一层叫做原始数据层或者Raw data层,这里叫做Raw data 层下面同理
从上面的三个最常用模型不难看出也可以说总结出ffmpeg基本把数据或者结构分成了”mux/demux层”也就是ffmpeg中的AVStream
“codec/decodec层”也就是ffmpeg中的AVCodec ,”Raw data层”这个也在AVStream中存放着(如果是自己写的获取当前毫秒时间的可以单独放置到一个timebse的结构体),
来聊聊分层对timebase的影响
二 :ffmpeg中的timebase是什么
1:简单来讲ffmpeg的timebase是为了解决当时间戳是小数的时候转化成整数和为了更好的做分层结构而设置的一种机制
2:ffmpeg的timebase我们可以理解为单位,比如米,毫秒,秒,千克这些都是单位,但是这个timebase有时候不是我们日常中能见到的单位,举个例子ffmpeg本身是以秒为基准的,1秒是1000毫秒,那如果timebase是1:1很好理解是秒的单位,如果timebase是1:1000也很好理解是毫秒的单位,但是如果timebase是1:25,我们的常用单位就解释不了了
a:mux/demux层的timebase,flv,mp4等一般是1:1000,ts一般是1:90*1000
b:codec/decodec层的timebase,h264随着帧率变化例如1:25aac根据采样率变化例如1:44100
c:Raw data层的timebase有很多变化比如1:1000*1000或1:1000等等
2:ffmpeg关于分层结果timebase的转换过程
a:转码模型
首先按照分层结构获取到demux层的timebase将flv数据也就是demux层的timebase转换为codec层的timebase
picture->pts=av_rescale_q_rnd(picture->pts,streams->time_base,streams->decodectext->time_base,AV_ROUND_NEAR_INF);
//最后一个参数是枚举类型 舍入方法 AVRounding
然后将decode层的timebase转换成codec层(这两个同层但也需要准换)的timebase,这里有个问题Raw data层的timebase可以略过,可以直接从decode转换成为codec,Raw data层的timebase 在摄像头采集和播放器的时候会用到
picture->pts=av_rescale_q_rnd(picyure->pts,streams->decodectext->timebase,streams->codectext->time_base,AV_ROUIND_NEAR_INF);
最后将codec层的timebase转换为mux层的timebase
picture->pts=av_rescale_q_rnd(picture->pts,streams->codectext->time_base,streams->time_base,AV_ROUND_NEAR_INF);
b.采集模型
首先获取到Raw data层的timebase如果是windows的可以从streams的timebase中读取 ios和安卓可以自己单独写个timebase结构体用于转换,将获取到的timebase转换为codec层的timebase
picture->pts=av_rescale_q_rnd(picture->pts,timebase_in,streams->codectext->time_base,AV_ROUND_NEAR_INF);
然后将codec层的timebase转换为mux层的timebase
picture->pts=av_rescale_q_rnd(picture->pts,streams->codectext->time_base,streams->timebase,AV_ROUND_NEAR_INF);
c:播放器模型
首先将demux层的timebase转换为decode层的timebase
picture->pts=av_rescale_q_rnd(picture->pts,streams->time_base,streams->decodectext->timebase,AV_ROUND_NEAR_INF);
然后将decode层的timebase转换为播放器用的Raw data层的timebase一般设置为1:1000为了将时间戳转换成毫秒
picture->pts=av_rescale_q_rnd(picture->pts,streams->decodectext->time_base,1:1000,AV_ROUND_NEAR_INF);