欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > 流媒体服务器SMS--ANNEXB转换为AVCC/HVCC的简易方法

流媒体服务器SMS--ANNEXB转换为AVCC/HVCC的简易方法

2024/10/24 14:26:27 来源:https://blog.csdn.net/yingyemin/article/details/141280517  浏览:    关键词:流媒体服务器SMS--ANNEXB转换为AVCC/HVCC的简易方法

1.简介

        众所周知,h264/h265的码流封装的时候有两种模式:ANNEXB和AVCC/HVCC。h264裸流、ps、ts等格式下是annexb;flv、MP4等格式下是avcc/hvcc。

        如果完全按照标准进行封装,是一件比较麻烦的事情,本文介绍一种懒人办法,亲测有效。

        介绍一下本人的开源流媒体,点个star,有兴趣一起开发的朋友也可以联系本人:SimpleMediaServer(流媒体): 旨在开发一个可商用的,功能丰富、高性能、高可扩展的流媒体服务。支持RTSP、RTMP、WEBRTC、GB28181、HTTP-FLV、HLS、JT1078等协议。各个协议可以单独剥离出来,相互独立;也可以互相转换协议。有兴趣一起开发开源项目的朋友可以联系本人(qq 1084855601),包括且不限于音视频后端、信令开发、控制台,前端等。icon-default.png?t=N7T8https://gitee.com/inyeme/simple-media-server

2.AVCC

        h264的annexb转为avcc还是比较简单的,按照标准走就行

    *data++ = 0x01;   //configurationversion*data++ = spsBuffer[spsSize + 1]; //avcprofileindication*data++ = spsBuffer[spsSize + 2]; //profilecompatibilty*data++ = spsBuffer[spsSize + 3]; //avclevelindication*data++ = 0xff;   //reserved + lengthsizeminusone*data++ = 0xe1;   //num of sps*data++ = (uint8_t)(spsLen >> 8); //sequence parameter set length high 8 bits*data++ = (uint8_t)(spsLen); //sequence parameter set  length low 8 bits// data length 13memcpy(data, spsBuffer.data() + spsSize, spsLen); //H264 sequence parameter setdata += spsLen; // 13 + spsLen*data++ = 0x01; //num of pps*data++ = (uint8_t)(ppsLen >> 8); //picture parameter set length high 8 bits*data++ = (uint8_t)(ppsLen); //picture parameter set length low 8 bits// 16 + spsLen + ppsLenmemcpy(data, ppsBuffer.data() + ppsSize, ppsLen); //H264 picture parameter set

        avcc的第2、3、4个字节就是sps的第2、3、4个字节

3.HVCC

        h265的annexb转hvcc比较复杂,想要完全按照标准去封装,需要对sps做比较全的解析,太麻烦了,在开发项目的时候,突发灵感,既然hvcc里的字段都是vps或sps里的字段,解码器应该不会真的去解析hvcc的字段,而是直接会去解析vps,sps,pps。那hvcc那些难搞的字段是不是可以随便填呢,抱着试一试的态度,写下代码:

string H265Track::getConfig()
{if (!_vps || !_sps || !_pps) {return "";}string config;auto spsSize = _sps->startSize();auto vpsSize = _vps->startSize();auto ppsSize = _pps->startSize();auto vpsBuffer = _vps->_buffer;int vpsLen = _vps->size() - vpsSize;auto spsBuffer = _sps->_buffer;int spsLen = _sps->size() - spsSize;auto ppsBuffer = _pps->_buffer;int ppsLen = _pps->size() - ppsSize;config.resize(38  + vpsLen + spsLen + ppsLen);auto data = (char*)config.data();// *data++ = 0x1c; //key frame, AVC// *data++ = 0x00; //avc sequence header// *data++ = 0x00; //composit time // *data++ = 0x00; //composit time// *data++ = 0x00; //composit time*data++ = 0x01;   //configurationversion// 6 byte*data++ = spsBuffer[spsSize + 5];  //general_profile_space(2), general_tier_flag(1), general_profile_idc(5)*data++ = spsBuffer[spsSize + 6]; //general_profile_compatibility_flags*data++ = spsBuffer[spsSize + 7]; *data++ = spsBuffer[spsSize + 8]; *data++ = spsBuffer[spsSize + 9]; *data++ = spsBuffer[spsSize + 10]; //general_constraint_indicator_flags*data++ = spsBuffer[spsSize + 11]; *data++ = spsBuffer[spsSize + 12]; *data++ = spsBuffer[spsSize + 13]; *data++ = spsBuffer[spsSize + 14]; *data++ = spsBuffer[spsSize + 15]; *data++ = spsBuffer[spsSize + 16]; // general_level_idc*data++ = spsBuffer[spsSize + 17]; // reserved(4),min_spatial_segmentation_idc(12)*data++ = spsBuffer[spsSize + 18]; *data++ = spsBuffer[spsSize + 19]; // reserved(6),parallelismType(2)*data++ = spsBuffer[spsSize + 20]; // reserved(6),chromaFormat(2)// 22 byte // 下面几个0xff乱填的,貌似不影响播放*data++ = 0xf << 4 | 0xf;  reserved(5),bitDepthLumaMinus8(3)*data++ = 0xff; // reserved(5),bitDepthChromaMinus8(3)*data++ = 0xff; //avgFrameRate*data++ = 0xff;*data++ = 0xff; //constantFrameRate(2),numTemporalLayers(3),temporalIdNested(1),lengthSizeMinusOne(2)// *data++ = 0xff;// *data++ = 0xff;// *data++ = 0xff;// *data++ = 0xff;// 默认vps,sps,pps 各一个*data++ = 3; //numOfArrays//28 byte*data++ = 1 << 7 | H265NalType::H265_VPS & 0x3f; //array_completeness(1),reserved(1),NAL_unit_type(6)// 一个vps*data++ = 0; //numNalus*data++ = 1;*data++ = (uint8_t)(vpsLen >> 8); //sequence parameter set length high 8 bits*data++ = (uint8_t)(vpsLen); //sequence parameter set  length low 8 bitsmemcpy(data, vpsBuffer.data() + vpsSize, vpsLen); //H264 sequence parameter setdata += vpsLen; // 37 + vpsLen*data++ = 1 << 7 | H265NalType::H265_SPS & 0x3f;// 一个sps*data++ = 0;*data++ = 1;*data++ = (uint8_t)(spsLen >> 8); //sequence parameter set length high 8 bits*data++ = (uint8_t)(spsLen); //sequence parameter set  length low 8 bitsmemcpy(data, spsBuffer.data() + spsSize, spsLen); //H264 sequence parameter setdata += spsLen; // 38 + vpsLen + spsLen*data++ = 1 << 7 | H265NalType::H265_PPS & 0x3f;// 一个pps*data++ = 0;*data++ = 1;*data++ = (uint8_t)(ppsLen >> 8); //sequence parameter set length high 8 bits*data++ = (uint8_t)(ppsLen); //sequence parameter set  length low 8 bitsmemcpy(data, ppsBuffer.data() + ppsSize, ppsLen); //H264 sequence parameter setdata += ppsLen; // 43  + vpsLen + spsLen + ppsLenreturn config;
}

        经实测,rtmp协议可以正常播放。

结束语

        本文介绍的方法,在开发过程中可以省下点时间,但是想学习hvcc和sps结构的,还是仔细地按照标准进行封装。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com