网页直播中推流组件EasyRTM推送RTMP扩展支持HEVC(H265)

版权声明:本文为EasyNVR技术团队原创文章,未经博主允许不得转载。 https://blog.csdn.net/EasyNVR/article/details/90597942

需求分析

目前市面上大部分互联网直播都是基于H.264压缩方式,但是随着大屏时代和高清时代的到来,人们已经不再满足于VGA、CIF这种小分辨率了,取而代之的是720P、1080P、4K级的视频传输,虽然我们国家的基础带宽一直在上升,但普遍情况下,传输高清视频还是带宽流量不够用,而且存在一个流量费用偏高的情况。H.265时代的到来,既可以降低码率又可以支持边播边录像。

下面我们将详细介绍EasyRTMP是如何实现支持H265推送的。

虽然网上有很多EasyRTMP实现支持h265推送的资料,但都不尽详细,官方也没有更新对HEVC(H265,后文统称HEVC)tag的支持,于是在实现的过程中走了不少弯路。最终,在广大网友以及ffmpeg代码的帮助下,我实现了通过EasyRTMP推送 HEVC视频帧数据到EasyDSS,下面我将把实现过程详细的记录下来,供广大家参考:

首先,采用CDN联盟的HEVC扩展标准

之前, RTMP头部信息封装并没有定义HEVC,我们采用CDN联盟的HEVC扩展标准,将HEVC的VideoTagHeader定义为12,详见下图:
EasyRTMP

然后,在H264封装的基础上进行改进,以支持HEVC头部的封装

我们在H264封装的基础上进行改进,以支持HEVC头部的封装,而HEVC头有
SPS PPS VPS,我们参考ffmpeg的HEVCDecoderConfigurationRecord结构对metadata进行封装,该结构体代码如下:

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

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;

参考ffmeg对该结构进行初始化如下:

static void hvcc_init(HEVCDecoderConfigurationRecord *hvcc)
{
memset(hvcc, 0, sizeof(HEVCDecoderConfigurationRecord));
hvcc->configurationVersion = 1;
hvcc->lengthSizeMinusOne   = 3; // 4 bytes

/*
 * The following fields have all their valid bits set by default,
 * the ProfileTierLevel parsing code will unset them when needed.
 */
hvcc->general_profile_compatibility_flags = 0xffffffff;
hvcc->general_constraint_indicator_flags  = 0xffffffffffff;

/*
 * Initialize this field with an invalid value which can be used to detect
 * whether we didn't see any VUI (in which case it should be reset to zero).
 */
hvcc->min_spatial_segmentation_idc = MAX_SPATIAL_SEGMENTATION + 1;
}

需要注意的是: 该结构其他参数我们其实可以不特别关心,我们只需要在HVCCNALUnitArray数组中把HEVC的VPS,SPS和PPS信息填入即可。

最后,修改发送的帧数据

填写好Metadata信息后,我们还需要在发送帧数据的时候做一下修改,将I帧的tag头改成12,P帧tag不变,设置成1即可,如下代码所示:

int i = 0;
if(bIsKeyFrame)
{
	//body[i++] = 0x17;// 2:Pframe  7:AVC
	body[i++] = 	 (m_metadata.nVideoCodec  == FLV_CODECID_HEVC) ? 0x1C:0x17;// 1:Iframe  7:AVC 12:HEVC

	if (m_bWaitingKeyFrame)
	{
		m_bWaitingKeyFrame = false;
	}
}
else
{
	//body[i++] = 0x27;// 2:Pframe  7:AVC
	body[i++] = 	 (m_metadata.nVideoCodec  == FLV_CODECID_HEVC) ? 0x2C:0x27;// 1:Iframe  7:AVC 12:HEVC
}
body[i++] = 0x01;// AVC NALU
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;

// NALU size
body[i++] = size>>24;
body[i++] = size>>16;
body[i++] = size>>8;
body[i++] = size&0xff;

EasyRTMP推流

EasyRTMP是一套调用简单、功能完善、运行高效稳定的RTMP功能组件,经过多年实战和线上运行打造,支持RTMP推送断线重连、环形缓冲、智能丢帧、网络事件回调,支持Windows、Linux、arm(hisiv100/hisiv200/hisiv300/hisiv400/etc…)、Android、iOS平台,支持市面上绝大部分的RTMP流媒体服务器,包括Wowza、Red5、ngnix_rtmp、crtmpserver等主流RTMP服务器,能够完美应用于各种行业的直播需求,手机直播、桌面直播、摄像机直播、课堂直播等等方面!(详见青犀官网:http://open.tsingsee.com/ )
tsingsee

猜你喜欢

转载自blog.csdn.net/EasyNVR/article/details/90597942