MP4文件格式的相關內容

參考鏈接

  • FFmpeg中mp4的demuxer(mov.c)代碼閱讀 - 簡書
  • mp4文件格式解析 - 簡書
  • mp4封裝格式各box類型講解及IBP幀計算_青丶空゛的博客-CSDN博客
  • 5分鐘入門MP4文件格式 - 程序猿小卡 - 博客園
  • ?關于M4A文件的隨機訪問 - 云+社區 - 騰訊云

MP4文件格式相關內容

  • MP4文件由許多box組成,每個box包含不同的信息, 這些box以樹形結構的方式組織。
  • 以下是主要box的簡要說明:

  • 根節點之下,主要包含三個節點:ftyp、moov、mdat。
    • ftyp:文件類型。描述遵從的規范的版本。
    • moov box:媒體的metadata信息,保存了音視頻數據的時空信息。
    • mdat:具體的媒體數據。
    • 說明:在 mp4 中默認寫入字節序是 Big-Endian的。

2. mp4文件基本信息

分析mp4文件的工具:

  • mp4box.js:一個在線解析mp4的工具。
  • bento4:包含mp4dump、mp4edit、mp4encrypt等工具。
  • MP4Box:類似于bento4,包含很全面的工具。
  • mp4info.exe: windows平臺圖形界面展示mp4基本信息的工具。

  • mvhd針對整個影片,tkhd針對單個track,mdhd針對媒體,vmhd針對視頻,smhd針對音頻,可以認為是從 寬泛 > 具體,前者一般是從后者推導出來的。?

mp4文件基本信息

  • audio信息:
    • smplrate:sample rate(采樣率)。
    • channel:通道個數。
    • bitrate:比特率。
    • audiosamplenum:音頻sample的個數。
  • video信息:
    • width、height:視頻的寬/高。
    • bitrate:比特率(碼率),秒為單位。等于視頻總的大小/時長。
    • frames:視頻幀數。
    • fps:幀率(frame per second)。
    • total_time:時間長度,ms為單位。等于duration/timescale。
    • timescale:時間的粒度,1000表示1000個單位為1s。
    • duration:時間粒度的個數。
    • videosamplenum:視頻sample的個數。

3. 封裝格式重要概念

box

  • mp4文件由若干個box組成。下面是box結構的一個示意圖。

  • box由header和body組成,header指明box的size和type。size是包含box header的整個box的大小。
  • box type,通常是4個ASCII碼的字符如“ftyp”、“moov”等,這些box type都是已經預定義好的,表示固定的含義。如果是“uuid”,表示該box為用戶自定義擴展類型,如果box type是未定義的,應該將其忽略。
  • 如果header中的size為1,則表示box長度需要更多的bits位來描述,在后面會有一個64bits位的largesize用來描述box的長度。如果size為0,表示該box為文件的最后一個box,文件結尾(同樣只存在于“mdat”類型的box中)。
  • 只有“mdat”類型的box才可能會用到large size
  • size后面緊跟著的32位為box type,一般是4個字符,如“ftyp”、“moov”等,這些box type都是預定義好的,分別表示固定的意義。如果是“uuid”,表示box為用戶的擴展類型,如果未定義box type 需要將其忽略
  • box中可以包含box,這種box稱為container box。
  • box分為兩種,Box和Fullbox。FullBox 是 Box 的擴展,Header 中增加了version 和 flags字段,分別定義如下:
aligned(8) class Box (unsigned int(32) boxtype,optional unsigned int(8)[16] extended_type) {unsigned int(32) size;unsigned int(32) type = boxtype;if (size==1) {unsigned int(64) largesize;} else if (size==0) {// box extends to end of file}if (boxtype==‘uuid’) {unsigned int(8)[16] usertype = extended_type;}
}
  • FullBox有version和flags字段,
aligned(8) class FullBox(unsigned int(32) boxtype, unsigned int(8) v, bit(24) f)
extends Box(boxtype) {unsigned int(8) version = v;bit(24) flags = f;
}

MP4box

ftyp box

  • 該box有且只有1個,并且只能被包含在文件層,而不能被其他box包含。該box應該被放在文件的最開始,指示該MP4文件應用的相關信息。
  • “ftyp” body依次包括1個32位的major brand(4個字符),1個32位的minor version(整數)和1個以32位(4個字符)為單位元素的數組compatible brands。這些都是用來指示文件應用級別的信息。
  • major_brand:比如常見的 isom、mp41、mp42、avc1、qt等。它表示“最好”基于哪種格式來解析當前的文件。舉例,major_brand 是 A,compatible_brands 是 A1,當解碼器同時支持 A、A1 規范時,最好使用A規范來解碼當前媒體文件,如果不支持A規范,但支持A1規范,那么,可以使用A1規范來解碼;
  • minor_version:提供 major_brand 的說明信息,比如版本號,不得用來判斷媒體文件是否符合某個標準/規范;
  • compatible_brands:文件兼容的brand列表。比如 mp41 的兼容 brand 為 isom。通過兼容列表里的 brand 規范,可以將文件 部分(或全部)解碼出來;
  • 在實際使用中,不能把 isom 做為 major_brand,而是需要使用具體的brand(比如mp41),因此,對于 isom,沒有定義具體的文件擴展名、mime type。

  • 下面是常見的幾種brand,以及對應的文件擴展名、mime type,更多brand可以參考?這里?。

  • MP4封裝格式介紹及解析_tiankong19999的博客-CSDN博客_mp4封裝

補充

關于AVC/AVC1

  • 在討論 MP4 規范時,提到AVC,有的時候指的是“AVC文件格式”,有的時候指的是"AVC壓縮標準(H.264)",這里簡單做下區分。
    • AVC文件格式:基于 ISO基礎文件格式 衍生的,使用的是AVC壓縮標準,可以認為是MP4的擴展格式,對應的brand 通常是 avc1,在MPEG-4 PART 15 中定義。
    • AVC壓縮標準(H.264):在MPEG-4 Part 10中定義。
    • ISO基礎文件格式(Base Media File Format) 在 MPEG-4 Part 12 中定義。

FREE(可選的)

  • free是可選的,如果存在,則通常出現在moov與mdat之間,即moov-free-mdat。
  • free中的數據通常為全0,其作用相當于占位符,在實時拍攝視頻,moov數據增多時分配給moov使用。
  • 因為設備錄制視頻時并不能預先知道視頻數據大小,如果moov在mdat之前,隨著拍攝mdat的數據會增加,moov數據也會增多,如果沒有free預留的空間,則要不停的向后移動mdat數據以騰出moov空間。
  • ???“free”中的內容是無關緊要的,可以被忽略。該box被刪除后,不會對播放產生任何影響。

moov box

  • moov box 是一個 container box 該box包含了文件媒體的元數據信息,具體內容信息由子box詮釋。同File Type Box一樣,該box有且只有一個,且只被包含在文件層。一般情況下,“moov”會緊隨“ftyp”出現。
  • 可以看到這個demo 中有 mvhd、trak、udta 三種 box 一般情況下 “moov”中會包含1個“mvhd”和若干個“trak”。其中“mvhd”為header box,一般作為“moov”的第一個子box出現。“trak”包含了一條音、視頻軌/流/track的相關信息,也是一個container box。
  • 該box是解析MP4文件里面最重要的一個box,它包含了音視頻數據的編碼格式、音視頻數據樣本,chunks的大小、存儲位置也即偏移offset、時間戳單位、DTS,CTS(PTS),解碼時間、顯示時間等等…
  • moov box中記錄的每幀音視頻數據位置信息,實際上都在mdat box中,通過解析moov box來獲取到每幀音視頻數據具體位置后,使得播放器能方便的拖拉進度條。

mvhd box (Movie Header Box)

  • mvhd 描述了與具體音頻或視頻流無關的文件整體信息,其中的duration/timescale的值即為單位為秒的媒體時長。
  • 創建時間、修改時間、時間度量標尺、可播放時長等信息

字段字節數意義
box size4box大小
box type4box類型
version1box版本,0或1,一般為0。(以下字節數均按version=0)
flags3
creation time4創建時間(相對于UTC時間1904-01-01零點的秒數)
modification time4修改時間
time scale4文件媒體在1秒時間內的刻度值,可以理解為1秒長度的時間單元數
duration4該 track的時間長度,用duration和time scale值可以計算track時長,比如audio track的time scale = 8000, duration = 560128,時長為70.016,video track的time scale = 600, duration = 42000,時長為70
rate4推薦播放速率,高16位和低16位分別為小數點整數部分和小數部分,即[16.16] 格式,該值為1.0(0x00010000)表示正常前向播放
volume2與rate類似,[8.8] 格式,1.0(0x0100)表示最大音量
reserved10保留位
matrix36視頻變換矩陣,一般忽略不計
pre-defined24
next track id4下一個track使用的id號

補充

  • ?timescale:一秒包含的時間單位(整數)。舉個例子,如果timescale等于1000,那么,一秒包含1000個時間單位(后面track等的時間,都要用這個來換算,比如track的duration為10,000,那么,track的實際時長為10,000/1000=10s);
  • next_track_ID:32位整數,非0,一般可以忽略不計。當要添加一個新的track到這個影片時,可以使用的track id,必須比當前已經使用的track id要大。也就是說,添加新的track時,需要遍歷所有track,確認可用的track id;

trak box (Track Box)

  • trak也是一個container box,其子box包含了該track的媒體數據引用和描述。一個MP4文件中的媒體可以包含多個track,且至少有一個track,這些track之間彼此獨立,有自己的時間和空間信息。“trak”必須包含一個“tkhd”和一個“mdia”,此外還有很多可選的box(略)
  • track表示一些sample集合,對于媒體數據來說,track表示一個視頻或者音頻序列
  • 一系列子box描述了每個媒體軌道的具體信息
  • hint track并不包含媒體數據,而是包含將一些其他數據track打包成流媒體的指示信息
  • sample對于非hint track來說,video sample 表示視頻幀,或者一組連續視頻幀,audio sample即為一段連續的壓縮音頻,統稱為sample,對于hint track,sample定義了一個或者多個流媒體的格式
  • sample table指明sample的時序和物理布局的表
  • chunk 一個track的幾個sample組成的單元
  • MP4文件中 媒體內容在moov的box中,一個moov包含多個track,每個track就是一個隨時間變化的媒體序列,track里每個時間單位是一個sample,sample是按照時間順序排列。注意,一幀音頻可以分解為多個音頻sample,所以音頻一般用sample作為單位,而不用幀

tkhd(track header box)

  • tkhd 描述的該track的,如果是視頻會有寬、高信息、 還有文件創建時間、修改時間等。

字段字節數意義
box size4box大小
box type4box類型
version1box版本,0或1,一般為0。(以下字節數均按version=0)
flags3按位或操作結果值,預定義如下:0x000001 track_enabled,否則該track不被播放;0x000002 track_in_movie,表示該track在播放中被引用;0x000004 track_in_preview,表示該track在預覽時被引用。一般該值為7,如果一個媒體所有track均未設置track_in_movie和track_in_preview,將被理解為所有track均設置了這兩項;對于hint track,該值為0
creation time4創建時間(相對于UTC時間1904-01-01零點的秒數)
modification time4修改時間
track id4id號,不能重復且不能為0
reserved4保留位
duration4track的時間長度;當前track的完整時長(需要除以timescale得到具體秒數)
reserved8保留位
layer2視頻層,默認為0,值小的在上層;視頻軌道的疊加順序,數字越小越靠近觀看者,比如1比2靠上,0比1靠上
alternate group2track分組信息,默認為0表示該track未與其他track有群組關系;當前track的分組ID,alternate_group值相同的track在同一個分組里面。同個分組里的track,同一時間只能有一個track處于播放狀態。當alternate_group為0時,表示當前track沒有跟其他track處于同個分組。一個分組里面,也可以只有一個track
volume2[8.8] 格式,如果為音頻track,1.0(0x0100)表示最大音量;否則為0
reserved2保留位
matrix36視頻變換矩陣
width4
height4高,均為 [16.16] 格式值,與sample描述中的實際畫面大小比值,用于播放時的展示寬高

補充

  • flags:按位或操作獲得,默認值是7(0x000001 | 0x000002 | 0x000004),表示這個track是啟用的、用于播放的 且 用于預覽的。
    • Track_enabled:值為0x000001,表示這個track是啟用的,當值為0x000000,表示這個track沒有啟用;
    • Track_in_movie:值為0x000002,表示當前track在播放時會用到;
    • Track_in_preview:值為0x000004,表示當前track用于預覽模式;

mdia (Track Media Structure)??

  • mdia box 描述了這條音視頻軌/流(trak)的媒體數據樣本的主要信息,對播放器來說是一個很重要的box
  • “mdia”也是個container box,其子box的結構和種類還是比較復雜的。先來看一個“mdia”的實例結構樹圖。

  • ?總 體來說,“mdia”定義了track媒體類型以及sample數據,描述sample信息。一般“mdia”包含一個“mdhd”,一個“hdlr”和 一個“minf”,其中“mdhd”為media header box,“hdlr”為handler reference box,“minf”為media information box。下面依次看一下這幾個box的結構。

mdhd (Media Header Box)

  • 當前音/視頻軌/流(trak)的總體信息, 該box中有duration字段和timescale字段,duration/timescale的值即為當前流的時長。
  • hdlr box用來指定該流的類型

字段字節數意義
box size4box大小
box type4box類型
version1box版本,0或1,一般為0。(以下字節數均按version=0)
flags3
creation time4創建時間(相對于UTC時間1904-01-01零點的秒數)
modification time4修改時間
time scale4同前表
duration4track的時間長度
language2媒體語言碼。最高位為0,后面15位為3個字符(見ISO 639-2/T標準中定義)
pre-defined2

?Handler Reference Box(hdlr)

  • “hdlr”解釋了媒體的播放過程信息,該box也可以被包含在meta box(meta)中。“hdlr”結構如下表。
字段字節數意義
box size4box大小
box type4box類型
version1box版本,0或1,一般為0。(以下字節數均按version=0)
flags3
pre-defined4
handler type4在media box中,該值為4個字符:“vide”— video track“soun”— audio track“hint”— hint track
reserved12
name不定track type name,以‘\0’結尾的字符串
  • handler_type的取值包括:
    • vide(0x76 69 64 65),video track;
    • soun(0x73 6f 75 6e),audio track;
    • hint(0x68 69 6e 74),hint track;
  • name為utf8字符串,對handler進行描述,比如 L-SMASH Video Handler(參考?這里)。
  • “hdlr”的字節實例如下圖,各字段已經用顏色區分開:

  • stsd box的子box用于保存該流的編碼類型

  • avcC box指定了該流的編碼類型為H264,儲了解碼所需的SPS、PPS信息。
  • stsc stsz stco三個box用于保存每幀視頻或音頻數據在文件中的保存位置。
  • stts stss ctts三個box用于保存媒體數據和時間戳的對應關系。
  • 在同級的stbl的樣本表box里面可以查到對應的樣本 描述信息(stsd),時序信息(stts),樣本的大小信息(stsz),樣本到chunk的映射信息(stsc),chunk的位置信息(stco)等等?

Media Information Box(minf)

  • ???“minf” 存儲了解釋track媒體數據的handler-specific信息,media handler用這些信息將媒體時間映射到媒體數據并進行處理。“minf”中的信息格式和內容與媒體類型以及解釋媒體數據的media handler密切相關,其他media handler不知道如何解釋這些信息。“minf”是一個container box,其實際內容由子box說明。
  • ???一 般情況下,“minf”包含一個header box,一個“dinf”和一個“stbl”,其中,header box根據track type(即media handler type)分為“vmhd”、“smhd”、“hmhd”和“nmhd”,“dinf”為data information box,“stbl”為sample table box。下面分別介紹。
  • ???下圖為“minf”部分字節實例,其中紅色為box header,藍色為“smhd”,綠色為“dinf”,黃色為一部分“stbl”。

Media Information Header Box(vmhd、smhd、hmhd、nmhd)

  • Video Media Header Box(vmhd)?
字段字節數意義
box size4box大小
box type4box類型
version1box版本,0或1,一般為0。(以下字節數均按version=0)
flags3
graphics mode4視頻合成模式,為0時拷貝原始圖像,否則與opcolor進行合成
opcolor2×3{red,green,blue}
  • Sound Media Header Box(smhd)?
字段字節數意義
box size4box大小
box type4box類型
version1box版本,0或1,一般為0。(以下字節數均按version=0)
flags3
balance2立體聲平衡,[8.8] 格式值,一般為0,-1.0表示全部左聲道,1.0表示全部右聲道
reserved2
  • Hint Media Header Box(hmhd)? 略
  • Null Media Header Box(nmhd)? 非視音頻媒體使用該box,略

Data Information Box(dinf)

  • ???“dinf”解釋如何定位媒體信息,是一個container box。“dinf”一般包含一個“dref”,即data reference box;“dref”下會包含若干個“url”或“urn”,這些box組成一個表,用來定位track數據。簡單的說,track可以被分成若干段,每 一段都可以根據“url”或“urn”指向的地址來獲取數據,sample描述中會用這些片段的序號將這些片段組成一個完整的track。一般情況下,當 數據被完全包含在文件中時,“url”或“urn”中的定位字符串是空的。
  • ?“dref”的字節結構如下表。?
字段字節數意義
box size4box大小
box type4box類型
version1box版本,0或1,一般為0。(以下字節數均按version=0)
flags3
entry count4“url”或“urn”表的元素個數
“url”或“urn”列表不定
  • ???“url”或“urn”都是box,“url”的內容為字符串(location string),“urn”的內容為一對字符串(name string and location string)。當“url”或“urn”的box flag為1時,字符串均為空。
  • ???下 面是一個“dinf”的字節實例圖。其中黃色為“dinf”的box header,由紅色部分我們知道包含的“url”或“urn”個數為1,紅色后面為“url”box的內容。紫色為“url”的box header(根據box type我們知道是個“url”),綠色為box flag,值為1,說明“url”中的字符串為空,表示track數據已包含在文件中。

Sample Table Box(stbl)

  • ???“stbl”幾乎是普通的MP4文件中最復雜的一個box了,首先需要回憶一下sample的概念。sample是媒體數據存儲的單位,存儲在media的chunk中,chunk和sample的長度均可互不相同,如下圖所示。

  • ???“stbl” 包含了關于track中sample所有時間和位置的信息,以及sample的編解碼等信息。利用這個表,可以解釋sample的時序、類型、大小以及在各自存儲容器中的位置。“stbl”是一個container box,其子box包括:sample description box(stsd)、time to sample box(stts)、sample size box(stsz或stz2)、sample to chunk box(stsc)、chunk offset box(stco或co64)、composition time to sample box(ctts)、sync sample box(stss)等。
  • ???“stsd”必不可少,且至少包含一個條目,該box包含了data reference box進行sample數據檢索的信息。沒有“stsd”就無法計算media sample的存儲位置。“stsd”包含了編碼的信息,其存儲的信息隨媒體類型不同而不同。

Sample Description Box(stsd)

  • 給出視頻、音頻的編碼、寬高、音量等信息,以及每個sample中包含多少個frame???
  • 存儲了編碼類型和初始化解碼器需要的信息。有與特定的track-type相關的信息,相同的track-type也會存在不同信息的情況如使用不一樣的編碼標準。
  • 結構如下:

  • box header和version字段后會有一個entry count字段,根據entry的個數,每個entry會有type信息,如“vide”、“sund”等,根據type不同sample description會提供不同的信息,例如對于video track,會有“VisualSampleEntry”類型信息,對于audio track會有“AudioSampleEntry”類型信息。
  • 視頻的編碼類型、寬高、長度,音頻的聲道、采樣等信息都會出現在這個box中。

Time To Sample Box(stts)

  • ???結構如下:

  • “stts” 存儲了sample的duration,描述了sample時序的映射方法,我們通過它可以找到任何時間的sample。“stts”可以包含一個壓縮的 表來映射時間和sample序號,用其他的表來提供每個sample的長度和指針。表中每個條目提供了在同一個時間偏移量里面連續的sample序號,以 及samples的偏移量。遞增這些偏移量,就可以建立一個完整的time to sample表。

Sample Size Box(stsz)

  • 每個sample的size(單位是字節)? ?,根據 sample_size 字段,可以知道當前track包含了多少個sample(或幀)。
  • 結構如下:

  • “stsz” 定義了每個sample的大小,包含了媒體中全部sample的數目和一張給出每個sample大小的表。這個box相對來說體積是比較大的。
  • 有兩種不同的box類型,stsz、stz2。

stsz:

  • sample_size:默認的sample大小(單位是byte),通常為0。如果sample_size不為0,那么,所有的sample都是同樣的大小。如果sample_size為0,那么,sample的大小可能不一樣。
  • sample_count:當前track里面的sample數目。如果 sample_size==0,那么,sample_count 等于下面entry的條目;
  • entry_size:單個sample的大小(如果sample_size==0的話)

stz2:

  • field_size:entry表中,每個entry_size占據的位數(bit),可選的值為4、8、16。4比較特殊,當field_size等于4時,一個字節上包含兩個entry,高4位為entry[i],低4位為entry[i+1];
  • sample_count:等于下面entry的條目;
  • entry_size:sample的大小。

Sample To Chunk Box(stsc)

  • ???結構如下:

  • 用chunk組織sample可以方便優化數據獲取,一個thunk包含一個或多個sample。“stsc”中用一個表描述了sample與chunk的映射關系,查看這張表就可以找到包含指定sample的thunk,從而找到這個sample。

Sync Sample Box(stss)

  • 結構如下:

??

  • “stss” 確定media中的關鍵幀。對于壓縮媒體數據,關鍵幀是一系列壓縮序列的開始幀,其解壓縮時不依賴以前的幀,而后續幀的解壓縮將依賴于這個關鍵幀。 “stss”可以非常緊湊的標記媒體內的隨機存取點,它包含一個sample序號表,表內的每一項嚴格按照sample的序號排列,說明了媒體中的哪一個 sample是關鍵幀。如果此表不存在,說明每一個sample都是一個關鍵幀,是一個隨機存取點。

Chunk Offset Box(stco)

  • thunk在文件中的偏移???
  • 結構如下:

  • “stco” 定義了每個thunk在媒體流中的位置。位置有兩種可能,32位的和64位的,后者對非常大的電影很有用。在一個表中只會有一種可能,這個位置是在整個文 件中的,而不是在任何box中的,這樣做就可以直接在文件中找到媒體數據,而不用解釋box。需要注意的是一旦前面的box有了任何改變,這張表都要重新 建立,因為位置信息已經改變了。
  • 針對小文件、大文件,有兩種不同的box類型,分別是stco、co64,它們的結構是一樣的,只是字段長度不同。
  • chunk_offset 指的是在文件本身中的 offset,而不是某個box內部的偏移。
  • 在構建mp4文件的時候,需要特別注意 moov 所處的位置,它對于chunk_offset 的值是有影響的。有一些MP4文件的 moov 在文件末尾,為了優化首幀速度,需要將 moov 移到文件前面,此時,需要對 chunk_offset 進行改寫。

PTS和DTS的計算

I P B 幀的概念

  • 在音視頻中,為了提高壓縮效率,會將每幀畫面壓縮為不同類型的視頻幀數據。
  • I幀表示關鍵幀,包含有一幀畫面的完整信息,解碼時只需要本幀數據就可以解碼出完整的一幀畫面。
  • P幀表示前向參考幀,它保存了本幀與上一幀的差異信息,它不能單獨解碼,需要根據上一幀的畫面加上本幀保存的差值來獲取本幀的完整畫面。
  • B幀為雙向參考幀,它解碼時需要依賴它之前和之后的幀來獲取最終的畫面
  • 因為B幀需要依賴它后面的幀來進行解碼,所以它的解碼順序就必然和顯示順序不能保持一致,這時就需要解碼時間戳(DTS)和顯示時間戳(PTS)來共同決定一幀視頻數據何時解碼,然后何時顯示了。
  • 舉個例子
  • 一小段視頻幀序列如下 :
    • type : I — B — B — P — B — B — P
    • PTS : 0.33 0.67 1.00 1.33 1.67 2.00 2.33
    • DTS : 0.00 0.67 1.00 0.33 1.67 2.00 1.33
    • PTS >= DTS
  • 根據mp4 stts和ctts 可以得到DTS和PTS

stts(Decoding Time to Sample Box)

  • stts 可以計算出每個sample的dts,其中sample_delta為該sample的dts相對于上一個smaple的差值,
  • stts包含了DTS到sample number的映射表,主要用來推導每個幀(sample)的時長。
  • 那么此樣本數據的dts為 :? ?0 ? 1000 2000 3000 4000 ···
  • entry_count:stts 中包含的entry條目數;
  • sample_count:單個entry中,具有相同時長(duration 或 sample_delta)的連續sample的個數。
  • sample_delta:sample的時長(以timescale為計量)

ctts(Composition Time to Sample Box)

  • Composition Time 構成時間目前我直接理解的PTS。。
  • ctts 有每個sample的構成時間(Composition Time)和解碼時間(DTS)之間的差值(CTTS)即圖中的composition_offset。
  • 如果不存在ctts,則代表該流不存在B幀,那么PTS就直接等于DTS。
  • 幀解碼到渲染的時間差值,通常用在B幀的場景,對于存在B幀的視頻來說,ctts就需要存在了。當PTS、DTS不相等時,就需要ctts了,公式為 CT(n) = DT(n) + CTTS(n) 。
  • 對于只有I幀、P幀的視頻來說,解碼順序、渲染順序是一致的,此時,ctts沒必要存在。

timescale

  • 最后就是關于單位,你可以看到圖中樣本的單位都是以1000為單位浮動,實際上真實DTS和PTS時間是需要除以mdia/mdhd中的timescale。這里是30000。
  • 有了這些,我們就可以在ctts里面計算出pts了 :
 else if (box_type_equa(uint32_to_str(bh.type, sbuffer), "ctts")) {uint32_t version = 0;read_net_bytes_to_host_uint32(&box[8], &version);if(version != 0) {LOG_E("ctts unsupport version :%d ", version)return;}uint32_t entry_cnt = 0;read_net_bytes_to_host_uint32(&box[12], &entry_cnt);char buf[128] = {0};tree_childs_insert_with_val(tree, "version", uint32_to_ascii(version, buf));tree_childs_insert_with_val(tree, "entry_cnt", uint32_to_ascii(entry_cnt, buf));uint32_t i = 0, j = 0, num = 0, pos = 16;for (i = 0; i < entry_cnt; i++) {uint32_t sample_cnt;read_net_bytes_to_host_uint32(&box[pos], &sample_cnt);pos += 4;uint32_t sample_offset;read_net_bytes_to_host_uint32(&box[pos], &sample_offset);pos += 4;for (j = 0; j < sample_cnt; j++) {PushBack_Array(pts_array, At_Array(dts_array, num++) + sample_offset);float dt, pt = 0.0;printf("dts : %9.3f ms | pts : %9.3f ms | \n", At_Array(dts_array, num - 1) / (mdhd_time_scale * 1.0), At_Array(pts_array, num - 1) / (mdhd_time_scale * 1.0));}

stss (Sync Sample Box)

  • stss 里面存放了關鍵幀的序號(I幀),跳轉時,需要從關鍵幀開始解碼,否則會花屏。
  • 哪些sample是關鍵幀
  • mp4文件中,關鍵幀所在的sample序號。如果沒有stss的話,所有的sample中都是關鍵幀。
  • entry_count:entry的條目數,可以認為是關鍵幀的數目;
  • sample_number:關鍵幀對應的sample的序號;(從1開始計算)


stsz (Sample Size Boxes):

  • 顧名思義,樣本大小.

?

?stsc (Sample To Chunk Box):

  • 媒體數據的樣本是被打包進chunks(塊)的,chunks和樣本(samples)的大小不固定,該box用于說明chunks關聯樣本的信息。
  • 每個thunk中包含幾個sample
  • entry_count:有多少個表項(每個表項,包含first_chunk、samples_per_chunk、sample_description_index信息);
    • first_chunk 該入口第一個chunks的索引(index).
    • samples_per_chunk 樣本數量/chunks.
    • sample_description_index:指向 stsd 中 sample description 的索引值(參考stsd小節);
  • sample 以 chunk 為單位分成多個組。chunk的size可以是不同的,chunk里面的sample的size也可以是不同的

前面描述比較抽象,這里看個例子,這里表示的是:

  • 序號1~15的chunk,每個chunk包含15個sample;
  • 序號16的chunk,包含30個sample;
  • 序號17以及之后的chunk,每個chunk包含28個sample;
  • 以上所有chunk中的sample,對應的sample description的索引都是1;
first_chunksamples_per_chunksample_description_index
1151
16301
17281

stco (Chunk Offset Box)

  • 描述每個chunks相對文件的偏移量。
  • 如圖 第一個chunks即前10個樣本(此例), samples.1起始地址為 423257, samples.1的地址則為 423257 + 140798 = 564055, 依此類推…
  • 有了這些即可計算出音視頻的時間和空間信息了


mdat box

  • Meida Data Box 媒體數據box 位于頂層,定義是一個字節數組,用來存儲媒體數據。該box數量可以為0個,也可以有多個(當媒體數據全部為外部文件引用時),數據直接跟在box type字段后面,具體數據結構的意義需要參考metadata(主要在sample table中描述)。
  • 實際媒體數據。我們最終解碼播放的數據都在這里面
  • 該box包含于文件層,可以有多個,也可以沒有(當媒體數據全部為外部文件引用時),用來存儲媒體數據。數據直接跟在box type字段后面,具體數據結構的意義需要參考metadata(主要在sample table中描述)。

?

mehd(Movie Extends Header Box)

  • mehd是可選的,用來聲明影片的完整時長(fragment_duration)。如果不存在,則需要遍歷所有的fragment,來獲得完整的時長。對于fmp4的場景,fragment_duration一般沒辦法提前預知。

trex(Track Extends Box)

  • 用來給 fMP4 的 sample 設置各種默認值,比如時長、大小等
  • 字段含義如下:

    • track_id:對應的 track 的 ID,比如video track、audio track 的ID;
    • default_sample_description_index:sample description 的默認 index(指向stsd);
    • default_sample_duration:sample 默認時長,一般為0;
    • default_sample_size:sample 默認大小,一般為0;
    • default_sample_flags:sample 的默認flag,一般為0;
    • 老版本規范里,前6位都是保留位,新版規范里,只有前4位是保留位。is_leading 含義不是很直觀,下一小節會專門講解下。
    • reserved:4 bits,保留位;
    • is_leading:2 bits,是否 leading sample,可能的取值包括:
      • 0:當前 sample 不確定是否 leading sample;(一般設為這個值)
      • 1:當前 sample 是 leading sample,并依賴于 referenced I frame 前面的 sample,因此無法被解碼;
      • 2:當前 sample 不是 leading sample;
      • 3:當前 sample 是 leading sample,不依賴于 referenced I frame 前面的 sample,因此可以被解碼;
    • sample_depends_on:2 bits,是否依賴其他sample,可能的取值包括:
      • 0:不清楚是否依賴其他sample;
      • 1:依賴其他sample(不是I幀);
      • 2:不依賴其他sample(I幀);
      • 3:保留值;
    • sample_is_depended_on:2 bits,是否被其他sample依賴,可能的取值包括:
      • 0:不清楚是否有其他sample依賴當前sample;
      • 1:其他sample可能依賴當前sample;
      • 2:其他sample不依賴當前sample;
      • 3:保留值;
    • sample_has_redundancy:2 bits,是否有冗余編碼,可能的取值包括:
      • 0:不清楚是否存在冗余編碼;
      • 1:存在冗余編碼;
      • 2:不存在冗余編碼;
      • 3:保留值;
    • sample_padding_value:3 bits,填充值;
    • sample_is_non_sync_sample:1 bits,不是關鍵幀;
    • sample_degradation_priority:16 bits,降級處理的優先級(一般針對如流傳過程中出現的問題);

is_leading

  • 為方便講解,下面的 leading frame 對應 leading sample,referenced frame 對應 referenced samle。
  • 以 H264編碼 為例,H264 中存在 I幀、P幀、B幀。由于 B幀 的存在,視頻幀的 解碼順序、渲染順序 可能不一致。
  • mp4文件的特點之一,就是支持隨機位置播放。比如,在視頻網站上,可以拖動進度條快進。
  • 很多時候,進度條定位的那個時刻,對應的不一定是 I幀。為了能夠順利播放,需要往前查找最近的一個 I幀,如果可能的話,從最近的 I幀 開始解碼播放(也就是說,不一定能從前面最近的I幀播放)。
  • 將上面描述的此刻定位到的幀,稱作 leading frame。leading frame 前面最近的一個 I 幀,叫做 referenced frame。
  • 回顧下 is_leading 為 1 或 3 的情況,同樣都是 leading frame,什么時候可以解碼(decodable),什么時候不能解碼(not decodable)?
  • 我沒看懂

1、is_leading 為 1 的例子: 如下所示,幀2(leading frame) 解碼依賴 幀1、幀3(referenced frame)。在視頻流里,從 幀2 往前查找,最近的 I幀 是 幀3。哪怕已經解碼了 幀3,幀2 也解不出來。

2、is_leading 為 3 的例子: 如下所示,此時,幀2(leading frame)可以解碼出來。

moof

  • moof是個container box,相關 metadata 在內嵌box里,比如 mfhd、 tfhd、trun 等。

mfhd(Movie Fragment Header Box)

  • 結構比較簡單,sequence_number 為 movie fragment 的序列號。根據 movie fragment 產生的順序,從1開始遞增。

traf(Track Fragment Box)

  • 對 fmp4 來說,數據被氛圍多個 movie fragment。一個 movie fragment 可包含多個track fragment(每個 track 包含0或多個 track fragment)。
  • 每個 track fragment 中,可以包含多個該 track 的 sample。 每個 track fragment 中,包含多個 track run,每個 track run 代表一組連續的 sample。

tfhd(Track Fragment Header Box)

  • tfhd 用來設置 track fragment 中 的 sample 的 metadata 的默認值。
  • sample_description_index、default_sample_duration、default_sample_size 沒什么好講的,這里只講解下 tf_flags、base_data_offset。
  • 首先是 tf_flags,不同 flag 的值如下(同樣是求按位求或) :
    • 0x000001 base‐data‐offset‐present:存在 base_data_offset 字段,表示 數據位置 相對于整個文件的 基礎偏移量。
    • 0x000002 sample‐description‐index‐present:存在 sample_description_index 字段;
    • 0x000008 default‐sample‐duration‐present:存在 default_sample_duration 字段;
    • 0x000010 default‐sample‐size‐present:存在 default_sample_size 字段;
    • 0x000020 default‐sample‐flags‐present:存在 default_sample_flags 字段;
    • 0x010000 duration‐is‐empty:表示當前時間段不存在sample,default_sample_duration 如果存在則為0 ,;
    • 0x020000 default‐base‐is‐moof:如果 base‐data‐offset‐present 為1,則忽略這個flag。如果 base‐data‐offset‐present 為0,則當前 track fragment 的 base_data_offset 是從 moof 的第一個字節開始計算;
    • sample 位置計算公式為 base_data_offset + data_offset,其中,data_offset 每個 sample 單獨定義。如果未顯式提供 base_data_offset,則 sample 的位置的通常是基于 moof 的相對位置。
    • 舉個例子,比如 tf_flags 等于 57,表示 存在 base_data_offset、default_sample_duration、default_sample_flags。

  • base_data_offset 為 1263 (ftyp、moov 的size 之和為 1263)。

?trun(Track Fragment Run Box)

  • 前面聽過,track run 表示一組連續的 sample,其中:
    • sample_count:sample 的數目;
    • data_offset:數據部分的偏移量;
    • first_sample_flags:可選,針對當前 track run中 第一個 sample 的設置;
  • tr_flags 如下,大同小異:
    • 0x000001 data‐offset‐present:存在 data_offset 字段;
    • 0x000004 first‐sample‐flags‐present:存在 first_sample_flags 字段,這個字段的值,只會覆蓋第一個 sample 的flag設置;當 first_sample_flags 存在時,sample_flags 則不存在;
    • 0x000100 sample‐duration‐present:每個 sample 都有自己的 sample_duration,否則使用默認值;
    • 0x000200 sample‐size‐present:每個 sample 都有自己的 sample_size,否則使用默認值;
    • 0x000400 sample‐flags‐present:每個 sample 都有自己的 sample_flags,否則使用默認值;
    • 0x000800 sample‐composition‐time‐offsets‐present:每個 sample 都有自己的 sample_composition_time_offset;
    • 0x000004 first‐sample‐flags‐present,覆蓋第一個sample的設置,這樣就可以把一組sample中的第一個幀設置為關鍵幀,其他的設置為非關鍵幀;
  • 舉例如下,tr_flags 為 2565。此時,存在 data_offset 、first_sample_flags、sample_size、sample_composition_time_offset。

補充

  • moofbox,這個box是視頻分片的描述信息。并不是MP4文件必須的部分,但在我們常見的可在線播放的MP4格式文件中(例如Silverlight Smooth Streaming中的ismv文件)確是重中之重
  • mfra box,一般在文件末尾,媒體的索引文件,可通過查詢直接定位所需時間點的媒體數據。
    • 附:Smooth Streaming中ismv文件結構,文件分為了多個Fragments,每個Fragment中包含moof和mdat。這樣的結構符合漸進式播放需求。(mdat及其描述信息逐步傳輸,收齊一個Fragment便可播放其中的mdat)。
  • mp4和fmp4的區別
  • fMP4 跟普通 mp4 基本文件結構是一樣的。普通mp4用于點播場景,fmp4通常用于直播場景。
    • 它們有以下差別:
      • 普通mp4的時長、內容通常是固定的。fMP4 時長、內容通常不固定,可以邊生成邊播放;
      • 普通mp4完整的metadata都在moov里,需要加載完moov box后,才能對mdat中的媒體數據進行解碼渲染;
      • fMP4中,媒體數據的metadata在moof box中,moof 跟 mdat (通常)結對出現。moof 中包含了sample duration、sample size等信息,因此,fMP4可以邊生成邊播放;
    • 怎么判斷mp4文件是普通mp4,還是fMP4呢?一般可以看下是否存在存在mvex(Movie Extends Box)。
      • 當存在mvex時,表示當前文件是fmp4(非嚴謹)。此時,sample相關的metadata不在moov里,需要通過解析moof box來獲得。
  • sample:
    • video sample 即為一幀或者一組連續的視頻幀
    • audio sample 即為一段連續的音頻
    • sample table 指明sample時序和物理布局的表

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446025.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446025.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446025.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

華三交換機如何進入配置_學校機房項目交換機的如何配置,理解這篇,交換機配置不再難...

弱電項目中&#xff0c;交換機的配置是無法避免的&#xff0c;大部分的項目都有可能會涉及到&#xff0c;尤其是機房等網絡項目&#xff0c;本期我們就通過一個實際項目案例來詳細了解交換機在項目中的應用配置&#xff0c;如果我們平時對交換機配置不熟&#xff0c;這個案例可…

百度地圖遷徙大數據_百度地圖大數據:五一高速擁堵不似預期,廣深成熱門遷出入地...

五一假期在即&#xff0c;你是否做好了“出行功課”&#xff1f;高速擁堵水平降低、公眾出門不出城、公園成踏青賞景熱門目的地……在全國疫情防控仍未松懈的時刻&#xff0c;2020年的五一或許注定與往年不同。近日&#xff0c;百度地圖發布2020五一假期安全出行大數據&#xf…

音視頻的基礎知識 視頻播放器原理/封裝格式/視頻音頻編碼數據/視頻像素數據/音頻采樣數據

參考鏈接 FFMpeg視頻播放器的制作-雷霄驊&#xff08;去除電流音版本&#xff09;_嗶哩嗶哩_bilibili 視頻播放器原理 播放視頻文件的流程YUV是一張屏幕中像素點的數值封裝格式 MP4 RMVB TS FLV AVI將視頻和音頻碼流按照一定的格式存儲在一個文件中封裝格式分析工具&#xf…

科立捷7代寫頻軟件_天大廈大“兩碩士論文雷同”通報,代寫買賣論文

澎湃新聞記者 薛莎莎天津大學、廈門大學7月10日晚就“兩碩士論文雷同”一事&#xff0c;分別發出調查處理通報。通報稱&#xff0c;涉事兩名學生存在由他人代寫、買賣論文的學術作假的行為&#xff0c;均撤銷其所獲碩士學位&#xff0c;收回、注銷碩士學位證書。澎湃新聞注意到…

FFMpeg命令行基礎

參考鏈接 FFMpeg視頻播放器的制作-雷霄驊&#xff08;去除電流音版本&#xff09;_嗶哩嗶哩_bilibili音視頻處理 ffmpeg初級開發 命令行工具-實用命令_MY CUP OF TEA的博客-CSDN博客 介紹 FFMpeg是視頻播放和轉碼的內核 使用 win中ffmpeg.exe用于視頻轉碼簡單命令&#xff1…

悲觀鎖和樂觀鎖_面試必備之樂觀鎖與悲觀鎖

何謂悲觀鎖與樂觀鎖樂觀鎖對應于生活中樂觀的人總是想著事情往好的方向發展&#xff0c;悲觀鎖對應于生活中悲觀的人總是想著事情往壞的方向發展。這兩種人各有優缺點&#xff0c;不能不以場景而定說一種人好于另外一種人。大家可以點擊加群【JAVA架構知識學習討論群】47398464…

Microsoft Visual Studio2019環境下搭建FFmpeg開發環境

參考鏈接 《基于 FFmpeg SDL 的視頻播放器的制作》課程的視頻_雷霄驊的博客-CSDN博客_雷霄驊ffmpeg視頻教程小學期課程資料 - 基于FFmpegSDL的視頻播放器的制作.zip_免費高速下載|百度網盤-分享無限制輔助參考鏈接使用VS2019創建項目&#xff0c;添加文件和庫地址_MY CUP OF …

vue process.env獲取不到_從文檔開始,重學vue(下)源碼級別

此篇文章主要是從應用及源碼層面講解vue部分常用api,閱讀起來可能略有難度,新手可以看《從文檔開始,重學vue(上)》示例代碼均在vue-cli3中完成Vue.extend()可以使用 extend 創建一個子類,該方法通常用于構建全局組件,如彈框組件等,下面我們就用它來制作個全局alert組件吧首先我…

Microsoft Visual Studio2019環境下搭建SDL開發環境

參考鏈接 《基于 FFmpeg SDL 的視頻播放器的制作》課程的視頻_雷霄驊的博客-CSDN博客_雷霄驊ffmpeg視頻教程小學期課程資料 - 基于FFmpegSDL的視頻播放器的制作.zip_免費高速下載|百度網盤-分享無限制輔助參考鏈接VS自動鏈接到Windows上隨vcpkg安裝的SDL2庫 | 碼農俱樂部 - G…

不關注公眾號可以獲取openid嗎_微信公眾號粉絲遷移

目錄 [toc] 微信公眾號遷移 正常的公眾號遷移直接通過微信操作就可以&#xff0c;如下圖。但是因為udb數據里面存的是遷移前公眾號的openid以及unionid,需要自行獲取新舊openid以及unionid。 舊的用戶信息要在遷移之前獲取&#xff0c;第三步點擊同意之后就公眾號的接口就調不通…

建筑專業規范大全 2020版_房屋建筑工程現行規范標準目錄匯編(2020版)—建筑電氣...

房屋建筑工程現行規范標準目錄匯編(2020版)建筑電氣規范編號規范名稱GB 50034-2013建筑照明設計標準GB 50052-2009供配電系統設計規范GB 50053-201320kV及以下變電所設計規范GB 50057-2010建筑物防雷設計規范GB 50147-2010電氣裝置安裝工程 高壓電器施工及驗收規范GB 50148-201…

基于Microsoft Visual Studio2019環境編寫ffmpeg視頻解碼代碼

舊代碼 舊代碼使用了很多過時的API&#xff0c;這些API使用后&#xff0c;vs會報編譯器警告 (級別 3) C4996的錯誤即 函數被聲明為已否決 報 C4996的錯誤 // test_ffmpeg.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。 // #define SDL_MAIN_HANDLED …

16進制轉double dotnet_終于把計算機進制弄明白了!

And theres one thing that I need from you我只需要你為我做一-件事Can you come through, through待在我的身邊就好Through, yeah你可以撫慰一切不滿And theres one thing that I need from you你可以過來Can you come through?待在我的身邊嗎-comethruJeremy Zucker進制進制…

FFmpeg源代碼簡單分析-架構圖-解碼

參考鏈接 FFmpeg源代碼結構圖 - 解碼_雷霄驊的博客-CSDN博客_ffmpeg雷霄驊函數背景色 函數在圖中以方框的形式表現出來。不同的背景色標志了該函數不同的作用&#xff1a; 粉紅色背景函數&#xff1a;FFmpeg的API函數。白色背景的函數&#xff1a;FFmpeg的內部函數。黃色背景…

JUnit單元測試筆記

#01 JUnit簡介 1.在項目工程中的Library,add 一個JUnit的Jar包&#xff0c;按需要添加JUnit 3 或 JUnit 4&#xff08;分為被測試類與測試類較佳&#xff09;。 2.單元測試是由程序員完成的。 3.Java 5 之前的版本只能 用JUnit 4前的版本&#xff08;因為JUnit 4用到Java 5的…

jqery獲取每個月天數_三年級《年、月、日》單元重要知識點整理匯總,以及難點題型解析...

昨天給大家分享了《計算經過的時間》問題&#xff0c;今天給大家分享的是《年、月、日》單元中重要的幾個知識點&#xff0c;以及難點題型解析。知識點1 感知年、月、日一、結合生活實際&#xff0c;看看下面事情需要經過多少時間。跑完100米大約需要經過十幾(秒)。2.打一場籃球…

FFmpeg源代碼簡單分析-架構圖-編碼

參考鏈接 FFmpeg源代碼結構圖 - 編碼_雷霄驊的博客-CSDN博客_ffmpeg 源碼函數背景色 函數在圖中以方框的形式表現出來。不同的背景色標志了該函數不同的作用&#xff1a; 粉紅色背景函數&#xff1a;FFmpeg的API函數。白色背景的函數&#xff1a;FFmpeg的內部函數。黃色背景的…

為革命,保護視力——為Eclipse更換暗黑皮膚及編輯頁面的字體顏色主題

1.在Eclipse中的菜單欄的Help -> Eclipse Market 的 Search欄中輸入 Eclipse Moonrise UI Theme &#xff0c;之后自己執生啦&#xff08;確保上網配置正確&#xff09;。 2.與上面操作類似&#xff0c;輸入 Eclipse Color Theme&#xff0c;選擇安裝。 3.選擇菜單欄的Win…

python函數可以作為容器對象嗎_正確理解Python函數是第一類對象

正確理解 Python函數&#xff0c;能夠幫助我們更好地理解 Python 裝飾器、匿名函數(lambda)、函數式編程等高階技術。函數(Function)作為程序語言中不可或缺的一部分&#xff0c;太稀松平常了。但函數作為第一類對象(First-Class Object)卻是 Python 函數的一大特性。那到底什么…

FFmpeg源代碼簡單分析-通用- av_register_all()

參考鏈接 ffmpeg 源代碼簡單分析 &#xff1a; av_register_all()_雷霄驊的博客-CSDN博客_av_register_all()從學齡前開始解讀FFMPEG代碼 之 avcodec_register_all函數_zzyincsdn的博客-CSDN博客