EasyNVR摄像机网页直播中,推流组件EasyRTMP推送RTMP扩展支持HEVC(H.265)的方案
众所周知,RTMP标准协议实际是不支持HEVC(H.265)编码格式的,同样,现行的H5标准里面,也没有对H.265的描述,所以,在很大程度上,H5网页浏览器是无法接入HEVC(H.265)的,但是,在很多原生客户端中,对HEVC(H.265)的需求是非常大的,那么,像EasyNVR中,如果需要接入HEVC(H.265)流的时候,我们应该如何支持呢?
不久前刚实现EasyRTMP扩展支持h265推送,当时在网上也查找了很多资料,发现都不尽详细,而官方也没有更新对HEVC(H265,后文统称HEVC)tag的支持,反正是走了不少弯路,当然,在广大网友以及ffmpeg代码的帮助下我最终实现了通过EasyRTMP推送HEVC视频帧数据到EasyDSS,这里我将把实现过程详细的记录下来,供广大网友参考。
首先, RTMP头部信息封装并没有定义HEVC,我们采用CDN联盟的HEVC(H.265)扩展标准,将HEVC的VideoTagHeader定义为12,详见下图:
然后,我们在H.264封装的基础上进行改进,以支持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是TSINGSEE青犀开放平台(http://open.tsingsee.com)一套调用简单、功能完善、运行高效稳定的RTMP功能组件,经过多年实战和线上运行打造,支持RTMP推送断线重连、环形缓冲、智能丢帧、网络事件回调,支持Windows、Linux、arm(hisiv100/hisiv200/hisiv300/hisiv400/etc…)、Android、iOS平台,支持市面上绝大部分的RTMP流媒体服务器,包括Red5、Ngnix_rtmp、crtmpserver等主流RTMP服务器,能够完美应用于各种行业的直播需求,手机直播、桌面直播、摄像机直播、课堂直播等等方面!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
2017-04-27 C#调用EasyPusher推送到EasyDarwin实现视频流中转
2017-04-27 C#调用EasyPusher推送到EasyDarwin实现视频流中转
2017-04-27 C#调用EasyPusher推送到EasyDarwin流媒体服务器直播方案及示例代码整理
2017-04-27 C#调用EasyPusher推送到EasyDarwin流媒体服务器直播方案及示例代码整理