不久前刚实现SkeyeRTMPPusher扩大反对h265推送,过后在网上也查找了很多材料,发现都不尽具体,而官网也没有更新对HEVC(H265,后文统称HEVC)tag的反对,反正是走了不少弯路,当然,在宽广网友以及ffmpeg代码的帮忙下我最终实现了通过SkeyeRTMPPusher推送HEVC视频帧数据到SkeyeSMS,这里我将把实现过程具体的记录下来,供宽广网友参考。
首先, RTMP头部信息封装并没有定义HEVC,咱们采纳CDN联盟的HEVC扩大规范,将HEVC的VideoTagHeader定义为12,详见下图:而后,咱们在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;
有相干的技术问题,欢送大家和我进行技术交换:
295222688@qq.com
大家也能够退出SkeyeRTMP直播推流技术 QQ群进行探讨:
102644504