不久前刚实现 SkeyeRTMPPusher 扩大反对 h265 推送,过后在网上也查找了很多材料,发现都不尽具体,而官网也没有更新对 HEVC(H265,后文统称 HEVC)tag 的反对,反正是走了不少弯路,当然,在宽广网友以及 ffmpeg 代码的帮忙下我最终实现了通过 SkeyeRTMPPusher 推送 HEVC 视频帧数据到 SkeyeSMS,这里我将把实现过程具体的记录下来,供宽广网友参考。
首先,RTMP 头部信息封装并没有定义 HEVC,咱们采纳 CDN 联盟的 HEVC 扩大规范,将 HEVC 的 VideoTagHeader 定义为 12,详见下图:![在这里插入图片形容](https://img-blog.csdnimg.cn/img_convert/3319b358ebe3b50efd59cb16cb18a292.png)
而后,咱们在 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