ffmpeg關於timebase的理解
一:ffmpeg的分層結構
寫這篇文章的時候先把ffmpeg分層問題大致說明一下,我們按照最常見的 "轉碼程式" 和 "網路攝影機採集" 以及 "播放器" 三個模型總結。
1:轉碼
轉碼基本流程:flv格式資料-->h264/aac資料-->yuv/pcm資料-->h264/aac資料-->mp4格式資料。
a:我們把flv格式資料或者mp4格式資料這一層叫做mux/demux層或者複用層有些人習慣於叫做封裝層,這裡叫做mux/demux層下面同理。
b:我們把h264/aac資料這一層叫做編解碼層或者codec/decode,這裡叫做codec/decode層下面同理。
c:我們把yuv/pcm資料這一層叫做未經處理資料層或者Raw data 層,這裡叫做Raw data層下面同理。
2:網路攝影機採集
網路攝影機採集基本流程:yuv/pcm資料-->h264/aac資料-->flv格式資料。
a:我們把yuv/pcm資料這一層叫做未經處理資料層或者Raw data 層,這裡叫做Raw data層下面同理。
b:我們把h264/aac資料這一層叫做編解碼層或者codec,這裡叫做codec層下面同理。
c:我們把flv格式資料這一層叫做mux層或者複用層有些人習慣於叫做封裝層,這裡叫做mux層下面同理。
3:播放器
播放器基本流程:flv格式資料-->h264/aac資料-->yuv/pcm資料。
a:我們把flv格式資料這一層叫做demux層或者複用層有些人習慣於叫做封裝層,這裡叫做demux層下面同理。
b:我們把h264/aac資料這一層叫做編解碼層或者decode,這裡叫做decode層下面同理。
c:我們把yuv/pcm資料這一層叫做未經處理資料層或者Raw data 層,這裡叫做Raw data層下面同理。
從上面的三個最常用模型不難看出也可以說總結出ffmpeg基本把資料或者說結構分為了 “mux/demux層”也就是ffmpeg中的AVStream
“codec/decode層” 也就是ffmpeg中的AVCodec “Raw data 層”這個也在AVStream 中存放著(如果是自己填寫的例如ios或者android擷取當前毫秒時間的可以單獨放置到一個timebse的結構體中),這個。各位看官對這個分層有了大致的瞭解之後我們再說分層對timebase的影響。
二:ffmpeg中的timebase是什麼
1:簡單來講ffmpeg的timebase是為瞭解決當時間戳記是小數的時候轉化為整數和為了更好的做分層結構而設定的一種機制。
2:ffmpeg的timebse我們可以理解為單位,比如米,毫秒,秒,千克這些都是單位,但這個timebse有時候不是我們日常中能見到的單位,舉個例子ffmpeg本身是以秒為基準的,1秒= 1000毫秒,那如果timebse是1:1很好理解是秒的單位,如果timebase是1:1000也很好理解是毫秒單位,但如果timebase是1:25呢,我們的常用單位就解釋不了了,這要是很多人的誤區。
三:ffmpeg中分層結構和timebase的關係
1:舉幾個常用的ffmpeg的timebase例子
a:mux/demux層的timebase,flv,MP4等一般是1:1000,ts一般是1:90*1000 。
b:codec/decode層timebase,h264隨著幀率變化例如1:25 aac根據採樣率變化例如1:44100。
c:Raw data 層的timebase有很多變化比如1:1000*1000 或1:1000等等
這個截圖是ffmpeg在windows平台的網路攝影機採集timebase,如果是ios或者android可以擷取系統的毫秒時間把timebase設定成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);
然後將decode層的timebase轉換成codec層(這兩個同層但也需要轉換)的timebase,這裡有個問題Raw data 層的timebase可以略過,可以直接從decode轉換為coedec,Raw data 層的timebse在網路攝影機採集和播放器的時候會用到。
picture->pts = av_rescale_q_rnd(picture->pts,streams->decodectext->time_base,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->time_base,AV_ROUND_NEAR_INF);
b:採集模型
首先擷取到Raw data 層的timebase如果是windows的可以從streams的timebase中讀取,ios和android可以自己單獨寫個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->time_base, 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);
這樣三個模型的ffmpeg分層和timebase的關係就解釋清楚了,如有問題還需交流互相學習。
ffmpeg的輸出截圖如下:
如有錯誤請指正:
交流請加QQ群:62054820
QQ:379969650.