1. 程式人生 > >MP4檔案格式的解析,以及MP4檔案的分割演算法

MP4檔案格式的解析,以及MP4檔案的分割演算法

mp4應該算是一種比較複雜的媒體格式了,起源於QuickTime。以前研究的時候就花了一番的功夫,尤其是如何把它完美的融入到視訊點播應用中,更是費盡了心思,主要問題是處理mp4檔案龐大的“媒體頭”。當然,流媒體點播也可以採用flv格式來做,flv也可以封裝H.264視訊資料的,不過Adobe卻不推薦這麼做,人家說畢竟mp4才是H.264最佳的儲存格式嘛。

  這幾天整理並重構了一下mp4檔案的解析程式,融合了分解與合併的程式,以前是c語言寫的,應用在linux上執行的伺服器程式上,現在改成c++,方便我在其他專案中使用它,至於用不用移植一份c#的,暫時用不到,等有必要了再說吧。這篇文章先簡單介紹一下mp4檔案的大體結構,以及它的分割演算法,之後再寫文章介紹如何把mp4完美應用在點播專案中。

一、MP4格式分析                  

  MP4(MPEG-4 Part 14)是一種常見的多媒體容器格式,它是在“ISO/IEC 14496-14”標準檔案中定義的,屬於MPEG-4的一部分,是“ISO/IEC 14496-12(MPEG-4 Part 12 ISO base media file format)”標準中所定義的媒體格式的一種實現,後者定義了一種通用的媒體檔案結構標準。MP4是一種描述較為全面的容器格式,被認為可以在其中嵌入任何形式的資料,各種編碼的視訊、音訊等都不在話下,不過我們常見的大部分的MP4檔案存放的AVC(H.264)MPEG-4(Part 2)編碼的視訊和AAC

編碼的音訊。MP4格式的官方檔案字尾名是“.mp4”,還有其他的以mp4為基礎進行的擴充套件或者是縮水版本的格式,包括:M4V,  3GPF4V等。

  mp4是由一個個“box”組成的,大box中存放小box,一級巢狀一級來存放媒體資訊。box的基本結構是:

  

  其中,size指明瞭整個box所佔用的大小,包括header部分。如果box很大(例如存放具體視訊資料的mdat box),超過了uint32的最大數值,size就被設定為1,並用接下來的8位uint64來存放大小。

  一個mp4檔案有可能包含非常多的box,在很大程度上增加了解析的複雜性,這個網頁上http://mp4ra.org/atoms.html

記錄了一些當前註冊過的box型別。看到這麼多box,如果要全部支援,一個個解析,怕是頭都要爆了。還好,大部分mp4檔案沒有那麼多的box型別,下圖就是一個簡化了的,常見的mp4檔案結構:

  

  一般來說,解析媒體檔案,最關心的部分是視訊檔案的寬高、時長、位元速率、編碼格式、幀列表、關鍵幀列表,以及所對應的時戳和在檔案中的位置,這些資訊,在mp4中,是以特定的演算法分開存放在stbl box下屬的幾個box中的,需要解析stbl下面所有的box,來還原媒體資訊。下表是對於以上幾個重要的box存放資訊的說明:

  看吧,要獲取到mp4檔案的幀列表,還挺不容易的,需要一層層解析,然後綜合stts stsc stsz stss stco等這幾個box的資訊,才能還原出幀列表,每一幀的時戳和偏移量。而且,你要照顧可能出現或者可能不出現的那些box。。。可以看的出來,mp4把幀sample進行了分組,也就是chunk,需要間接的通過chunk來描述幀,這樣做的理由是可以壓縮儲存空間,縮小媒體資訊所佔用的檔案大小。這裡面,stsc box的解析相對來說比較複雜,它用了一種巧妙的方式來說明sample和chunk的對映關係,特別介紹一下。

  這是stsc box的結構,前幾項的意義就不解釋了,可以看到stsc box裡每個entry結構體都存有三項資料,它們的意思是:“從first_chunk這個chunk序號開始,每個chunk都有samples_per_chunk個數的sample,而且每個sample都可以通過sample_description_index這個索引,在stsd box中找到描述資訊”。也就是說,每個entry結構體描述的是一組chunk,它們有相同的特點,那就是每個chunk包含samples_per_chunk個sample,好,那你要問,這組相同特點的chunk有多少個?請通過下一個entry結構體來推算,用下一個entry的first_chunk減去本次的first_chunk,就得到了這組chunk的個數。最後一個entry結構體則表明從該first_chunk到最後一個chunk,每個chunk都有sampls_per_chunk個sample。很拗口吧,不過,就是這個意思:)。由於這種演算法無法得知檔案所有chunk的個數,所以你必須藉助於stco或co64。直接上程式碼可能會清楚些:

  1. 首先直接分析entry

  2. 然後,通過stco或co64獲知chunk總個數之後,開始還原對映表

  讀出stsc之後,就可以綜合stbl下的所有box,推算出視訊和音訊幀列表,時戳和偏移量等資料。下面截圖展示獲取到的關鍵幀列表:

     

  有了關鍵幀列表之後,就可以繼續我們一下個題目,就是mp4檔案的分割。實現mp4的分割,是把mp4應用到點播系統中最關鍵的技術環節,做不到這個,就無法實現點播播放mp4影片的“拖動”。

二、MP4檔案的分割演算法

  所謂“分割”,就是把大檔案切成小檔案,要實現mp4的分割,

  •   首先,需要獲取到關鍵幀列表
  •   然後,選擇要分割的時間段(比如從關鍵幀開始)
  •   接著,重新生成moov box(注意所有相關的box 以及 box size都需要改變)
  •   最後,拷貝對應的資料,生成新檔案

  第一點,上面已經介紹了,第二點,只需要遍歷關鍵幀列表,就能找到離你想要分割的時間段最接近的關鍵幀,第四點就是“copy-paste”的工作,關鍵在於第三點。因為這一步涉及到stbl下的所有box,必須重新生成entrys,同樣的,其他的box都還好,只需要保留關鍵幀所對應的sample和chunk,其餘的刪掉即可,只是stsc box的比較麻煩,說起來比較囉嗦,還是直接看程式碼吧:

  修改完box之後,需要重新生成moov box,由於moov box的大小以及時長等資訊都發生了改變,所以需要box的大小做相應的修改,這點千萬不能忘記,否則播放器會解析錯誤。重新生成box之後,還要計算一下分割後的資料的長度,由於資料長度也發生了改變,所以修改mdat box的大小的同時,要同時修改stbl下所有box的chunk offset,切記!

  以下是整個的邏輯過程:

  好了,所有這些都實現之後,就具備了做mp4點播系統的條件了。不過,要做mp4點播,還有一些其他的問題需要解決,我將在下一篇文章中介紹。

轉載於https://www.cnblogs.com/haibindev/archive/2011/10/17/2214518.html

相關推薦

MP4檔案格式解析MP4檔案分割演算法

MP4檔案格式的解析,以及MP4檔案的分割演算法   mp4應該算是一種比較複雜的媒體格式了,起源於QuickTime。以前研究的時候就花了一番的功夫,尤其是如何把它完美的融入到視訊點播應用中,更是費盡了心思,主要問題是處理mp4檔案龐大的“媒體頭”。當然,流媒體點播也可以

MP4檔案格式解析以及MP4檔案分割演算法

mp4應該算是一種比較複雜的媒體格式了,起源於QuickTime。以前研究的時候就花了一番的功夫,尤其是如何把它完美的融入到視訊點播應用中,更是費盡了心思,主要問題是處理mp4檔案龐大的“媒體頭”。當然,流媒體點播也可以採用flv格式來做,flv也可以封裝H.264視訊資料的

Spring Boot 單檔案檔案上傳以及檔案寫入響應中

單檔案上傳 配置檔案設定 @Component public class MultipartConfig { @Bean public MultipartConfigElement multipartConfigElement(){ Multipa

pcdobjmtl檔案格式解析

pcd,obj,mtl檔案格式解析 pcd檔案解析 PCD檔案格式並非白費力氣地做重複工作,現有的檔案結構因本身組成的原因不支援由PCL庫引進n維點型別機制處理過程中的某些擴充套件,而PCD檔案格式能夠很好地補足這一點。PCD不是第一個支援3D點雲資料的檔案型別,尤其是計算機圖形

web.xml檔案解析以及tomcat啟動常見錯誤總結一哈。

【1.在web.xml裡配置Listener】 xml 程式碼如下: <listener> <listener-class> org.springframework.web.context.ContextL

Windows快捷方式檔案格式解析

轉載自:https://blog.csdn.net/cosmoslife/article/details/51898534 大家知道通過IShellLink介面可以得到快捷方式的各種屬性。具體怎麼做,網上有很多文章,這裡就不介紹了。現在主要是分析一下快捷方式檔案的格式,並且自己寫一個解析程式。

Qt 指定目標檔案目錄以及拷貝檔案到指定路徑

# 拷貝生成檔案到指定目錄:   out_pwd 生成的target檔案的當前路徑(絕對路徑);pwd是 .pro檔案所在的當前路徑#QMAKE_POST_LINK = cp $$OUT_PWD/lib$$TARGET.a  $$PWD/../../lib/

Android安全/安全技術--21--基礎檔案格式解析

4-1、so檔案格式解析 1、ELF檔案格式 Android中的so檔案就是ELF檔案,瞭解so檔案首先需要了解ELF檔案的格式,使用工具為readelf,常用命令如下: 1、檢視so檔案的頭部資訊 readelf -h xxx.so //

利用jqueryFrom傳檔案到servlet以及兩個伺服器之間傳檔案和其他資料

專案背景:有兩個伺服器,一個是使用者操作的手機端伺服器,一個是後臺(響應前一個伺服器,並能訪問資料庫) 專案需求:使用者從手機端上傳身份證以及個人資訊,我們需要將資料傳給後臺,並且在資訊認證通過後將身份證照片存在後臺伺服器的D盤資料夾下。 jqueryForm上

mysql .par檔案格式解析

mysql 5.6版本分割槽表有一個檔案:表名.par, 該檔案在5.7.6版本後被移除。 在一個現場環境中,客戶端執行check table後報錯如下,原始碼跟蹤下來之後是缺失par檔案。   mysql解析par檔案的呼叫堆疊如下: (gdb) bt #0 &

封裝格式---FLV---檔案格式解析

轉自:https://wuyuans.com/2012/08/flv-format  flv檔案主要由兩部分組成:header和body。   1.header header部分記錄了flv的型別、版本等資訊,是flv的開頭,一般都差不多,佔9bytes。具體格式如下:

/proc/$pid/maps檔案格式解析

/proc/pid/maps檔案格式解析 以下內容摘錄在man手冊,可以通過執行命令(man 5 proc)獲得。 /proc/[pid]/maps A file containing the currently mapped memory regions a

建立資料庫有次要檔案的資料庫以及給現有資料庫新增次要資料庫

一、建立資料庫 create database mrkj on primary (  name=mrkj_data,  filename='D:\data2\mrkj.mdf',  size=5MB,  MAXSIZE=UNLIMITED,  FILEGROWTH=10%

對串列埠的讀寫將讀取的內容寫在檔案以及一些檔案的讀寫操作

串列埠讀寫操作(上) 隔了好多天,終於要來發布我的第二篇心得了。鑑於之前寫過的一些關於檔案讀寫的操作,這次我要寫的是對串列埠的讀寫以及一些操作。 以下是關於串列埠定義的一些函式。

如何在WebService接收一個XML檔案解析客戶端如何傳送這個XML檔案?急求簡單程式碼示例。。

客戶端 xmlHttp = null; if (window.XMLHttpRequest) { // If IE7, Mozilla, Safari, and so on: Use native object. xmlHtt

flask和flask-restful接收file請求處理以及壓縮檔案處理

import werkzeug from flask import Flask import tarfile from flask_restful import Resource, Api, reqparse from werkzeug.datastructures impo

Java向Mysql資料庫中儲存圖片等二進位制檔案的實現以及常見報錯的解決!

Mysql資料庫的功能很強大,除了能儲存字元等常見資料以外,它同樣可以儲存圖片等二進位制檔案,本文以儲存照片為例。 一、Mysql儲存二進位制檔案常見報錯有: 1.com.mysql.jdbc.PacketTooBigException: Packet for query

Java Class檔案格式解析及例項

JAVA無關性概述 Java語言從剛誕生開始曾提出一個非常著名的宣言:“一次編寫,到處執行(Write Once, Run Anywhere)”。Sun公司和其他虛擬機器公司釋出了許多可以執行在不同作業系統上的虛擬機器,這些虛擬機器都可以載入和執行同一種平臺無關的位元組碼,

EXCEL開啟csv檔案中文亂碼以及匯入資料庫中文亂碼

1.將csv檔案用notepad++開啟,選擇encoding列表,選擇encode in UTF-8-BOM編碼方式,點集儲存,再次用EXCEL開啟就可以正常顯示 2.將上述的csv檔案匯入SQL中,選址65001(UTF—8)編碼方式,並在高階那一項將帶有中文的那一列的

Android Dex檔案格式解析(第二篇)

1 .DEX檔案中使用的資料型別 u1,u2,u4,u8表示佔某固定位元組的無符號數 sleb128表示有符號的LEB128型別資料,uleb128表示無符號的LEB128,uleb128p1表示無符號的LEB128+1 , 關於LEB128: