RTMP推送擴展支持HEVC(H265)之Metadata結構填寫詳解

鑑於廣大碼友對上一篇文章RTMP推送擴展支持HEVC(H265)的Metadata數據結構還存在不清楚的地方,這裏對RTMP推送Metadata的結構進行詳解。

首先, 我們先講解下 H.264/AVC metadata 語法,方便大家理解,這相關的文章大家在網上很容易找到,如果大家比較熟悉可以跳過;
參考:《ISO/IEC 14496-15 NAL unit structured video》AVCDecoderConfigurationRecord結構:(最小長度7字節)
在這裏插入圖片描述

說明:
libEasyRTMP我們稱之爲Metadata,而在FFmpeg中,則稱之爲extradata,extradata解析,詳見ff_h264_decode_extradata()

注意:
第5字節的最後2位,表示的就是NAL size的字節數。在AVCC格式中,每個NAL前面都會有NAL size字段。NAL size可能是1字節、2字節或4字節(4字節較常見),解析extradata重要目的就是確認這個值。(而Annex-B格式,要split NAL,只要去探測0x000001就可以了)

H.264 metadata 示例(AVCC格式)

在這裏插入圖片描述
metadata 如上
metasize 47
05| FF NAL size: 4字節
06| E1 SPS num: 1
07| 00 1F SPS size: 31字節
09| 67 NAL type: SPS
40| 01 PPS num: 1
41| 00 05 PPS size: 5字節
42| 68 NAL type: PPS

H.265/HEVC metadata語法

參照HEVCDecoderConfigurationRecord:(最小長度23字節)
在這裏插入圖片描述
HEVC metadata 示例在這裏插入圖片描述

metadata 如上
metasize 111
24| 20 NAL type: VPS
25| 00 01 VPS num: 1
27| 00 19 VPS size: 25字節
54| 21 NAL type: SPS
55| 00 01 SPS num: 1
57| 00 29 SPS size: 41字節
100| 22 NAL type: PPS

hvcC extradata是一種頭描述的格式。而annex-b格式中,則是將VPS, SPS和PPS等同於普通NAL,用start code分隔,非常簡單。Annex-B格式的”extradata”:
start code+VPS+start code+SPS+start code+PPS

EasyRTMP中metadata填寫VPS,SPS和PPS填寫如下:

		body[i++] = 0x03; // numOfArrays
		body[i++] = 0x20; // configurationVersion
		body[i++] = 0x00; // configurationVersion
		body[i++] = 0x01; // configurationVersion
		// vps data length 
		body[i++] = lpMetaData->nVpsLen>>8&0xff;
		body[i++] = lpMetaData->nVpsLen&0xff;
		// vps data
		memcpy(&body[i],lpMetaData->Vps,lpMetaData->nVpsLen);
		i= i+lpMetaData->nVpsLen;
		body[i++] = 0x21; // configurationVersion
		body[i++] = 0x00; // configurationVersion
		body[i++] = 0x01; // configurationVersion
		// sps data length
		body[i++] = lpMetaData->nSpsLen>>8&0xff;;
		body[i++] = lpMetaData->nSpsLen&0xff;
		// sps data
		memcpy(&body[i],lpMetaData->Sps,lpMetaData->nSpsLen);
		i= i+lpMetaData->nSpsLen;
		body[i++] = 0x22; // configurationVersion
		body[i++] = 0x00; // configurationVersion
		body[i++] = 0x01; // configurationVersion
		// pps data length 
		body[i++] = lpMetaData->nPpsLen>>8&0xff;
		body[i++] = lpMetaData->nPpsLen&0xff;
		// pps data
		memcpy(&body[i],lpMetaData->Pps,lpMetaData->nPpsLen);
		i= i+lpMetaData->nPpsLen;

從上一篇文章RTMP推送擴展支持HEVC(H265)我們瞭解了HEVCDecoderConfigurationRecord結構:

typedef struct HEVCDecoderConfigurationRecord {
	uint8_t  configurationVersion;
	uint8_t  general_profile_space;
	uint8_t  general_tier_flag;
	uint8_t  general_profile_idc;
	uint32_t general_profile_compatibility_flags;
	uint64_t general_constraint_indicator_flags;
	uint8_t  general_level_idc;
	uint16_t min_spatial_segmentation_idc;
	uint8_t  parallelismType;
	uint8_t  chromaFormat;
	uint8_t  bitDepthLumaMinus8;
	uint8_t  bitDepthChromaMinus8;
	uint16_t avgFrameRate;
	uint8_t  constantFrameRate;
	uint8_t  numTemporalLayers;
	uint8_t  temporalIdNested;
	uint8_t  lengthSizeMinusOne;
	uint8_t  numOfArrays;
	HVCCNALUnitArray *array;
} HEVCDecoderConfigurationRecord;

由於我們可以不必要關心其他的結構,所以我們從numOfArrays填寫起,這裏是三個數據信息結構(vps,sps,pps),numOfArrays=3,然後HVCCNALUnitArray結構進行填寫數據頭信息:

typedef struct HVCCNALUnitArray {
	uint8_t  array_completeness;
	uint8_t  NAL_unit_type;
	uint16_t numNalus;
	uint16_t *nalUnitLength;
	uint8_t  **nalUnit;
} HVCCNALUnitArray;

如VPS填寫如下:

		body[i++] = 0x20; // configurationVersion
		body[i++] = 0x00; // configurationVersion
		body[i++] = 0x01; // configurationVersion
		// vps data length 
		body[i++] = lpMetaData->nVpsLen>>8&0xff;
		body[i++] = lpMetaData->nVpsLen&0xff;

其他如SPS和PPS同理,見上文代碼。這一點和H264 metadata結構填寫是有很大的區別。

參考文章:
https://blog.csdn.net/yue_huang/article/details/75126155

有相關的技術問題,歡迎大家和我進行技術交流:
[email protected]
大家也可以加入EasyRTMP直播推流技術 QQ羣進行討論:
587254841

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