muxer mp4

簡單描述h264文件結構:

0001+sei+0001+sps+0001+pps+001/0001+IDR+0001+p1+0001+p2...+0001+sps+0001+pps+0001+IDR+0001+p1+0001+p2...
av_read_frame  一個avpacket
第一個avpacket 的data =  sei+sps+pps+IDR 幀(都包含起始碼)  avpacket.size = 三者的和
第二個avpacket 的data = h264的第一個non-IDR 幀,size=h264的第一個non-IDR 幀的size
第三個avpacket 的data = h264的第二個non-IDR 幀,size=h264的第二個non-IDR 幀的size

如果h264中間還有IDR幀,它生成的avpacket依然是  sei+sps+pps+IDR 幀(都包含起始碼)
*(avpacket.data+4)==0x67,表示這一個avpacket是一個攜帶IDR幀的數據。
一般來說,視頻參數不變化,參數集就不會變,所以一般來說每次出現的sps pps 都相同
h264的sps 和pps起始碼肯定是0001,其他的sei, IDR,no-IDR可能是001 也可能是0001
avpacket都是以起始碼開頭的

sei出現的位置在sps的前面或pps後面,也可以沒有

 把h264作爲輸入文件,h264的extradata=起始碼+sps+起始碼+pps,extradata_size=起始碼+sps++起始碼+pps

 

===============================================================

 

flv的文件格式簡易描述:

flv文件頭+previousTagSize 0 +srcipt tag + previousTagSize 1 + tag 2 + previousTagSize 2 + tag 3 + previousTagSize 3+ ...

其中flv文件頭佔9字節,previousTagSize 0 的值就是0

srcipt tag寫入的是metadata數據, metadata和sei沒有關係

音視頻通用的tag結構:11字節tag header(1B TagType+3B DataSize+3B Timestamp+1B TimestampExtended+3B StreamID)+(videodata/audiodata)

這裏的DataSize是tag data的總size, 故previousTagSize=11+DataSize

videodata=5字節VideoDataHeader(FrameType( 4bit) +CodecID (4bit)++AVPacketType(1Byte)+Composition Time(3Bytes)) +VideoTagBoby

VideoTagBody可以是AVCDecorderConfigurationRecord(佔11+spslen+ppslen字節)或 One or more NALUs (nal len+nal +nal len +nal +...)

如果AVCPacketType=0x00,爲AVCDecorderConfigurationRecord;

如果AVCPacketType=0x01,爲NALUs;

 

sps pps存儲在AVCDecorderConfigurationRecord(對應就是ffmpeg裏面的extradata)中,且AVCDecorderConfigurationRecord是全局的,在flv文件中只出現一次。

 nal在video 的tag data裏面,且不再以0001作爲起始碼,而是nal length, nal length採用大端字節序計算值,nal可能包含多個

 

audiodata=2字節AudioTagheader(=1B(4bit fmt+2bit 採樣率+1bit 採樣精度+1bit 聲道類型)+1B AACPacketType)+AudioTagBoby

AudioTagBoby可以是AudioSpecificConfig (佔2字節)或 AAC raw data(被剖離了7字節的ADTS的ES)

如果AACPacketType=0x00,爲AudioSpecificConfig;

如果AACPacketType=0x01,爲AAC raw data;

每一幀的ADTS的頭文件都包含了音頻的採樣率,聲道,幀長度等信息,所以每一個aac幀的adts不是固定的

ADTS都是以0xFFF開頭

如果沒有ADTS,aac將無法播放

AudioSpecificConfig也是全局的。在flv文件中只出現一次

 

 

av_read_frame  一個video avpacket

第一個avpacket 的data =  sei len+sei+nal len+IDR    avpacket.size = 和  (此時pkt.flags&AV_PKT_FLAG_KEY==1)

第二個avpacket 的data =  nal len+non-IDR    avpacket.size = 和(此時pkt.flags&AV_PKT_FLAG_KEY==0)

...

中途的IDR avpacket data= nal len+ IDR 

...

讀取出來的IDR avpacket ,不包含sps pps 

這裏也可以看到,直接分離flv裏面的h264碼流,因爲非標準起始碼,所以不可播。

需要我們把nal len轉換成0001起始碼,h264_mp4toannexb就是來幹這件事的,同時還會在每個關鍵幀前面增加0001+SPS+0001+PPS

 

 

flv的aac tag data:

av_read_frame  讀取一個audio avpacket ,avpacket 的data = flv裏面的AAC raw data(被剖離了7字節的ADTS的ES)

 

這裏可以看到,直接分離flv裏面的aac幀,得到的aac是無法播放的。需要加ADTS頭部。

反之,一個aac封裝成flv,需要先將ADTS頭轉換爲MPEG-4 AudioSpecficConfig,然後去掉ADTS頭部,

aac_adtstoasc就是來幹這件事的。

和flv具有相同特點的還有MP4、MOV等格式。

 

 

 

av_encode_video出來的avpacket:
001sei0001IDR + 0001P幀+...+0001IDR

 

用ffmpeg(版本2.8.1)命令:

ffmpeg -i test.mp4 -codec copy -bsf:v h264_mp4toannexb -f h264 test.264

ffmpeg -i test.mp4 -codec copy test.aac

ffmpeg -i test.aac -i test.h264 -acodec copy  -bsf:a aac_adtstoasc -vcodec cop y -f mp4 new.mp4 

 

mp4分離h264,必須加h264_mp4toannexb。h264文件轉mp4,起始碼變成nal length,ffmepg內部會自動處理。

mp4分離aac,adts頭部ffmepg內部會自動添加。aac合成mp4,必須加aac_adtstoasc

上面說了這麼多,其實全部是基礎知識鋪墊,重點是爲了描述下面的問題。

1.爲什麼網上很多人寫的轉碼程序,比如轉mp4,有的人把起始碼轉了nal length,有的人沒有,是依據什麼?

2.上面命令行已經驗證了h264文件轉mp4,也可以用雷霄驊的程序驗證https://blog.csdn.net/leixiaohua1020/article/details/39802913,根據我上面的描述,雷霄驊程序中(h264+aac->mp4)應當不要使用h264_mp4toannexb,需要使用aac_adtstoasc,也就說其實我們並沒有做h264的起始碼的nal length轉換.但是實際得到的mp4是可以播放的,且用001editor查看文件16進制內容,在nal前面其實是nal length,非0001起始碼。也就是說ffmepg在write frame的時候確實自行處理了。問題來了,是不是h264封裝mp4,ffmepg都會幫我們自行轉換起始碼->nal length. (nal length一般等於packet.size-4),如果ffmepg都會幫我們轉,爲什麼還有人多此一舉手動去轉換nal length,大家平時做muxer mp4的時候是否出現過無法播放的情況。(關於是否正常播放,以mac的quicktime player能播放爲標準,且能正常顯示視頻預覽圖,因爲vlc播放器都很強大,即使是mp4裏面是起始碼,也能播放)

我直接給出結論

(1) ffmepg自動轉nal length,需要滿足output 的extradata是0001sps0001pps形式(extradata可以包含sei),不能是AVCDecorderConfigurationRecord形式
(2) 如果設置了output 的extradata是AVCDecorderConfigurationRecord形式,nal起始碼必須我們自己手動轉換爲nal length
(3) 如果手動設置了nal起始碼轉換爲nal length,output 的extradata也必須是AVCDecorderConfigurationRecord形式

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章