rtmp h264,h265包結構和推流組包

rtmp視頻包結構

類型 長度
FrameType 4bit 1表示關鍵幀,2表示非關鍵幀,3表示一次性幀,4爲服務器保留,5表示視頻信息或命令幀
CodecID 4bit 1表示JPG,2表示Sorenson H263,3表示屏幕錄像,4表示VP6 ON2,,5表示帶alphat通道的VP6 ON2,6表示版本2的屏幕錄像,7表示avc,即h264
VideoData 視頻數據,根據CodecID的不同,此處字段內容不同,例如CodecID爲2時,此處爲H263包結構,當CodecID爲7時,此處爲AVC視頻包結構

實際使用當中,經常用的是發送h264或者h265的包
對於h265, CodecID爲7,對於h265,一般擴展的CodecID都是12
因此,對於h264視頻包來說,第一個字節一般是0x17或0x27,
對於h265, 第一個字節一般是0x1c或0x2c

對於VideoData字段,當CodecID爲7時,結構是AVC視頻包

AVC視頻包結構

類型 長度
AVCPacketType 8bit 0表示AVC Sequence頭,1表示nalu, 2一般不支持較低level的h264
Composition time 3 byte 如果AVCPacketType爲1表示Composition time offset, 其他值是全爲0
Data n byte 如果AVCPacketType爲0,此處是AVCDecoderConfigurationRecord,如果AVCPacketType,此處是視頻數據,如果AVCPacketType爲2, 此處爲空

明顯的,前2個字段比較明確,Composition time一般都填0
下面看下AVCDecoderConfigurationRecord

h264 AVCDecoderConfigurationRecord

參數名 長度
configureVersion 1 byte 版本號,默認爲1
AVCProfileIndication 1 byte profile定義,sps信息裏面去除頭部信息和sps標誌後的第一個字節
profile_compatibility 1 byte profile支持級別,sps信息裏面去除頭部信息和sps標誌後的第二個字節
AVCLevelIndication 1 byte level級別 sps頭信息之後第3個字節
reserved 6 bit 保留,默認爲’111111’
lengthSizeMinusOne 2 bit nalu unit長度 - 1,一般爲3
reserved 3 bit 保留,默認爲’111’
numOfSequenceParameterSets 5 bit sps的個數,一般爲1,即後面只有1個sps,如果有多個則後面2個字段循環添加
sequenceParameterSetLength 2 byte sps長度,先填高8位,再填低8位
sequenceParameterSetNaluUnit n byte sps內容
numOfPictureParameterSets 1 byte pps個數,一般爲1,如果有多個,後面的2個字段循環添加
pictureParameterSetLength 2 byte pps長度
pictureParameterSetNaLuUnit n byte pps內容

這樣h264視頻包結構就比較明晰了
再看看h265的HEVCDecoderConfigurationRecord

參數名 長度
configureVersion 1 byte 版本號,默認爲1
general_profile_space 2 bit 0, 其他值留作備用
general_tier_flag 1 bit 2個值,main tier和high tier,level 4和4以上支持High Tier
general_profile_idc 5 bit 當general_profile_space等於0時,指示CVS符合的配置文件
附件A中規定
general_profile_compatibility_flags 4 byte 當general_profile_idc指定的profile不在
general_constraint_indicator_flags 1 byte
general_level_idc 1 byte
reserved1 4 bit 默認’1111’
min_spatial_segmentation_idc_L 4 bit
min_spatial_segmentation_idc_H 1 byte
reserved1 6 bit 默認’111111’
parallelismType 2 bit
reserved1 6 bit 默認’111111’
chromaFormat 2 bit
reserved1 5 bit 默認’11111’
bitDepthLumaMinus8 3 bit
reserved1 5 bit 默認’11111’
bitDepthChromaMinus8 3 bit
avgFrameRate 2 byte
constantFrameRate 2 bit
numTemporalLayers 3 bit
temporalIdNested 1 bit
lengthSizeMinusOne 2 bit
numOfArrays 1 byte vps,sps,pps個數,後續填充內容,與h264一樣

librtmp 推流h265, 最開始參考的是:
https://blog.csdn.net/qq_33795447/article/details/89457581
裏面的推流,用大牛那個播放器是可以播的,但是用金山修改的ffmpeg播不了
又分析了下,主要還是vps,sps,pps這些信息組包不對,
修改爲下面的內容:

unsigned char body[1024] = { 0 };
	int i = 0;
	body[i++] = 0x1C;

	body[i++] = 0x00;// AVC sequence header   1byte

	body[i++] = 0x00;//composition time 3 byte
	body[i++] = 0x00;
	body[i++] = 0x00;

	body[i++] = 0x01;

	body[i++] = m_metaData.m_sps[6];
	body[i++] = m_metaData.m_sps[7];
	body[i++] = m_metaData.m_sps[8];
	body[i++] = m_metaData.m_sps[9];

	body[i++] = m_metaData.m_sps[12];
	body[i++] = m_metaData.m_sps[13];
	body[i++] = m_metaData.m_sps[14];

	body[i++] = 0x00;
	body[i++] = 0x00;
	body[i++] = 0x00;
	body[i++] = 0x00;

	body[i++] = 0x00;
	body[i++] = 0x00;
	body[i++] = 0x00;

	body[i++] = 0x00;
	body[i++] = 0x00;
	body[i++] = 0x00;

	body[i++] = 0x00;
	body[i++] = 0x00;
	body[i++] = 0x00;

	body[i++] = 0x03;	//視頻數據nal長度字節數-1,只取低2位

	/* unsigned int(8) numOfArrays; 03 */
	body[i++] = 0x03;

	body[i++] = 0x20;  //vps 32
	body[i++] = 0x00;
	body[i++] = 0x01;
	body[i++] = (m_metaData.m_vpsLen >> 8) & 0xff;
	body[i++] = (m_metaData.m_vpsLen) & 0xff;
	memcpy(&body[i], m_metaData.m_vps, m_metaData.m_vpsLen);
	i += m_metaData.m_vpsLen;

	//sps
	body[i++] = 0x21; //sps 33
	body[i++] = 0x00;
	body[i++] = 0x01;
	body[i++] = (m_metaData.m_nSpsLen >> 8) & 0xff;
	body[i++] = m_metaData.m_nSpsLen & 0xff;
	memcpy(&body[i], m_metaData.m_sps, m_metaData.m_nSpsLen);
	i += m_metaData.m_nSpsLen;

	//pps
	body[i++] = 0x22; //pps 34 
	body[i++] = 0x00;
	body[i++] = 0x01;
	body[i++] = (m_metaData.m_nPpsLen >> 8) & 0xff;
	body[i++] = (m_metaData.m_nPpsLen) & 0xff;
	memcpy(&body[i], m_metaData.m_pps, m_metaData.m_nPpsLen);
	i += m_metaData.m_nPpsLen;

	memcpy(m_RTMPPacket.m_body, (unsigned char*)body, i);

下面是推流抓包獲取的十六進制數據樣式

1c
000000000101600000009000000000005af000fcfdf8f800000f
03
20
0001
0018
40010c01ffff01600000030090000003000003005a959809
21
0001
002f
42010101600000030090000003000003005aa006b201e1df96566924cafff0280027f0100000030010000003019080
22
0001
0007
4401c172b46240

視頻包推送修改爲下面的內容:

if (isKeyFrame)
	body[i++] = 0x1C;
else
	body[i++] = 0x2C;
	
body[i++] = 0x01;// AVC NALU

body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;

// NALU size
body[i++] = (size>>24) & 0xFF;
body[i++] = (size>>16) & 0xFF;
body[i++] = (size>>8) & 0xFF;
body[i++] = size&0xff;
	
	// NALU data
	memcpy(&(body[i]),packet.data,size);

下面是視頻幀包樣式:

1c
01
000050
00001bf9
2601ae505c889c6440bc72fcdfaa1a66cfbdb1

如果希望推流一個,多個播放,則需要在每個i幀前發送vps,sps,pps的組包
測試可以用大牛播放器,或者金山修改的ffmpeg,或者EasyPlayerPro

參考鏈接:
https://blog.csdn.net/SwordTwelve/article/details/89522984
https://blog.csdn.net/qq_33795447/article/details/89457581
https://blog.csdn.net/dqxiaoxiao/article/details/94820599
https://blog.csdn.net/Dillon2015/article/details/104311186
https://blog.csdn.net/yue_huang/article/details/75126155

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