zl程序教程

您现在的位置是:首页 >  后端

当前栏目

RTMP推送扩展支持HEVC(H265)之Metadata结构填写详解

扩展 详解 支持 结构 推送 metadata RTMP 填写
2023-06-13 09:18:30 时间

鉴于广大码友对上一篇文章RTMP推送扩展支持HEVC(H265)的Metadata数据结构还存在不清楚的地方,这里对RTMP推送Metadata的结构进行详解。

首先, 我们先讲解下 H.264/AVC metadata 语法,方便大家理解,这相关的文章大家在网上很容易找到,如果大家比较熟悉可以跳过;

	参考:《ISO/IEC 14496-15 NAL unit structured video》AVCDecoderConfigurationRecord结构:(最小长度7字节) 

说明:

libSkeyeRTMPPusher我们称之为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

SkeyeRTMP中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

有相关的技术问题,欢迎大家和我进行技术交流:

295222688@qq.com

大家也可以加入SkeyeRTMPPusher直播推流技术 QQ群进行讨论:

102644504