http://www.cnblogs.com/wangqiguo/archive/2013/03/29/2987949.htmlhtml
因爲要在crtmpserver中實現Http Live Streaming ,本人花了接近3個星期的時間,研究將H264與AAC打包爲TS流並能在Ipad上經過HTML5播放,因爲沒有任何現成代碼可供參考,打包代碼所有手寫,打包格式主要參考ISO/ICE 18318-1.pdf。期間碰到不少問題,走了很多彎路,符合標準的TS不必定能在Ipad上播放,可是Ipad上播放的TS必定是符合標準的,能夠說是TS標準中的特例。現將遇到的主要問題以及要點總結以下:ios
【打包流程以及相關圖:】
【視頻H264到TS注意要點:】
<1>. 若是h264的包大於 65535 的話,能夠設置PES_packet_length爲0 ,具體參見ISO/ICE 13818-1.pdf 49 / 174 中關於PES_packet_length的描述
打包PES, 直接讀取一幀h264的內容, 此時咱們設置PES_packet_length的值爲0000
表示不指定PES包的長度,ISO/ICE 13818-1.pdf 49 / 174 有說明,這主要是方便
當一幀H264的長度大於PES_packet_length(2個字節)能表示的最大長度65535
的時候分包的問題, 這裏咱們設置PES_packet_length的長度爲0000以後 , 那麼即便該H264視頻幀的長度
大於65535個字節也不須要分多個PES包存放, 事實證實這樣作是能夠的, ipad可播放
-----------------
<2>. PES頭中的stream_id 好像是無所謂,隨便改了幾個均可以。 不過找到的幾個能夠ipad播放的樣本文件中都設置的是0xe0
而在蘋果的http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/HTTP_Live_Streaming_Metadata_Spec/2/2.html
裏面的2.4 PES Stream Format 提供的表裏面,使用的是0xbd 表示的是private_stream_id_1,不知道這個說明是否專門針對ID3,可是建議設置爲0xeo,我看到的幾個TS樣本文件都是這麼設置的。
-----------------
<3>. 對於視頻來講PTS和DTS都須要,能夠設置爲同樣的,若是隻有PTS,沒有DTS是不行的。能夠將pts的值賦值給dts,pts_dts_flag的值應該設置爲0x03,也就是二進制的'11'
-----------------
<4>. pmt中的 stream_type = 0x1b 表示 H264 , stream_type = 0x0f 表示AAC
-----------------
<5>. ipad不須要pcr均可以播放,能夠將pmt頭中的 PCR_PID設置爲0x1fff 表示沒有PCR ,參考ISO/ICE 13818-1.pdf 65 / 174, 在以後的全部關於adaptation_field中設置PCR_flag: 00 就能夠了,而且在adaptation_field中也不須要寫入pcr部分的值
-----------------
<6>. 在每一幀的視頻幀被打包到pes的時候,其開頭必定要加上 00 00 00 01 09 xx 這個nal。不然就有問題
蘋果官網有以下說明:
https://developer.apple.com/library/ios/#documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
10.These settings are the current recommendations. There are also certain requirements.
The current mediastreamsegmenter tool works only with MPEG-2 Transport Streams as defined in ISO/IEC 13818.
The transport stream must contain H.264 (MPEG-4, part 10) video and AAC or MPEG audio.
If AAC audio is used, it must have ADTS headers. H.264 video access units must use Access Unit Delimiter NALs,
and must be in unique PES packets.
其中 H.264 video access units must use Access Unit Delimiter NALs 中的 Access Unit Delimiter NAL 在H264的文檔中是09 ,可是有什麼用,我也不太清楚。根據個人實驗09後面的一個字節好像設置成什麼均可以,可是不能設置爲00
-----------------
<7>. 關於pts的計算方法
// 1s = 90000 time scale , 一幀就應該是 90000/video_frame_rate 個timescale
static uint32_t video_frame_rate = 30;
static uint32_t video_pts_increment = 90000 / video_frame_rate; //用一秒鐘除以幀率,獲得每一幀應該耗時是多少,單位是 timescale單位
static uint64_t video_pts = 0;
在之後的計算中,每生成一幀的ts,該幀的pts值應該是 video_pts += video_pts_increment; 僞代碼以下:
while(..)
{
ReadH264(h264_buffer)
PacketTS(h264_buffer,out_ts_buffer,video_pts);
video_pts += video_pts_increment;
}
<8>. 音頻應該是隻須要pts,不須要dts。
音頻pts的計算方法同上,只不過不是經過幀率,而是經過採樣率。
uint32_t audio_pts_increment = (90000 * audio_samples_per_frame) / audio_sample_rate;
上面的僞代碼就不貼了。
<9>. 關於pat,pmt的插入時間,實際上pat,pmt是要連續插入到ts流中的,並非開始插入以後就完了。由於ts要保證從任什麼時候候均可以開始播放。目前我是每4幀視頻(這4幀H264可能被打包成不少的ts包,而不止4包)插入一次pat,pmt包。
<10>. PES音視頻數據包的ts頭中的continuity_counter 必須是連續的,從小到大的,當增加到15以後再從0開始循環。第一包能夠不從0開始。可是以後的continuity_counter 必須是連續的,而且是按照步長1增加的。continuity_counter的增加相對於全部PID相同的包他們的增加是獨立的,例如第一個PAT包其continuity_counter值是0,那麼第二個PAT包的continuity_counter是1。 第一個PMT包其continuity_counter值是2,第二個PMT包其continuity_counter值是3。
【音頻AAC到TS注意要點:】
aac不須要設置DTS,只要PTS就能夠了,加上DTS可能還播放不了
aac打包成PES的時候,要想在ipad上播放必須設置PES_packet_length的長度,而視頻能夠設置爲0,可是音頻必須設置爲正確的長度值,aac的長度不可能超過65535,因此也不可能致使PES_packet_length溢出。
不然ipad播放不了。可是QQ影音能夠播放。這也許是ipad的特性。
//data_len:AAC音頻裸流的長度
// 3:PES頭
//5: 若是是音頻的話會有5個字節的PTS
_ts_packet_pes_header.PES_packet_length_16bit = data_len + 3 + 5 ;
【關於CRC32校驗算法:】
static uint32_t crc32table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
uint32_t CRC32(const uint8_t *data, int len)
{
int i;
uint32_t crc = 0xFFFFFFFF;
for(i = 0; i < len; i++)
crc = (crc << 8) ^ crc32table[((crc >> 24) ^ *data++) & 0xFF];
return crc;
}
【關於TS流中的填充字節】
TS流中有2中不一樣的填充形式,由於TS每一包要求是188個字節,當不足188個字節的時候, 必需要補充到188個字節,這就涉及到填充的問題。
<1>. 若是TS包中承載的是PSI數據(PAT,PMT等),那麼其填充是在該包的最後一個有效字節的後面填充0xFF直到知足188個字節爲止。
解碼器會丟棄這些字節,具體說明參考 ISO_IEC 13818-1.pdf 60 / 174
<2>. 若是TS包中承載的是PES數據,那麼當不足188個字節的時候,須要使用adaptation_field 這個域,也就是指定TS包中的adaptation_field_control的值來控制payload與adaptation_field的承載關係,同時指定PES中的adaptation_field_length指定填充多少字節,具體的填充字節值應該是隨意的建議使用FF,而且此adaptation_field的使用好像只能在PES中使用。 ISO_IEC 13818-1.pdf 39 / 174算法