技术背景
一直以来,GB28181-2022之前的规范版本让人诟病的一点:没有明确针对H.265的说明,特别是监控摄像机,H.265已然成为标配,GB/T28181-2022规范,终于针对H.265做了明确的说明,让我们来一起解读下规范:
基于RTP的视音频数据PS封装
基于RTP的PS封装首先按照ISO/IEC 13818-1:2019将视音频流封装成PS包,再将PS包以负载的方式封装成RTP包。
进行PS封装时,应将母个悦team Map),系统头和PSM放置于PS包头之后、第一十 ti(System Header)和 PSM(Program Stream Map),系统头和PSM放置于PS包头之后、第一个PES包之前。
典型的视频关键帧PS包结构如图C.1所示,其中 PESV为视频PES包,PESA为音频PES包,视频非关键帧的PS包结构中一般不包含系统头和PSM。PS包中各部分的具体数据结构参见ISO/IEC13818-1 :2019中的相关描述。
系统头应包含对PS包中码流种类的描述,其中视频和音频的流ID(stream_id)取值如下: 视频流ID:0xEO;
针对本文件规定的几种视音频格式,PSM中流类型(stream_type)的取值如下: H.265视频流:0x24;
基于RTP的视音频封装
H.265视频流的RTP封装
H.265的RTP载荷格式应符合IETF RFC 7798的相关规定。
H.265视频流RTP包的负载类型(Payload Type)标识号选定:从IETF RFC3551协议表5的动态范围(96~~127)中选择,建议定为100,根据实际需要填充。
H.265视频编﹑解码技术要求
H.265的档次和水平
采用H.265标准的视频编码应至少支持ITU-T H.265(2019)视频标准的主档次(MainProfile),水平(Level)应至少支持到Level 2,标清应用宜扩展支持到Level 3,高清应用宜扩展支持到Level 4;视频解码所支持的档次和水平应不低于编码支持的最高档次和水平,至少应支持到H.265视频标准主档次的Level 4。视频解码宜扩展支持 H.265主档次(Main Profile)中的B帧工具,且相邻两Р帧间的B帧个数不大于2。
H.265主档次视频编码标准的具体描述详见ITU-T H.265(2019)的相关规定。
H.265主档次的选项和工具
H.265主档次支持的选项和工具主要有:
a)比特深度限制为8 bit;
b)采样限制为4∶ 2∶ 0;
c)CTB的大小从16×16到64×64;
d)在水平(Level)支持的最大分辨率下﹐解码图像的缓存容量限制为6幅图像﹐若水平(Level)下
分辨率变小,解码图像的缓存容量可大于6幅图像,但不应超过16幅图像;
e)允许选择波前和片划分方式,但是不能同时选择。
采用H.265编码标准的视频流应为H.265主档次视频流,编码应支持上述主档次选项和工具中的部分或全部;H.265的解码至少应支持上述全部选项和工具。
多参考帧编码时,P片的参考帧数一般不大于两帧,且不应超过15帧。
为了保证码流解析的效率,比特流中应当在每个Ⅰ帧之前都出现相应的视频参数集(Video Param-eter Set,VPS)、序列参数集(Sequence Parameter Set, SPS)和图像参数集(Picture Parameter Set,PPS)。
技术实现
实际上,我们在实现GB28181-2016的时候,就已经针对H.265做了设定:
设置如下:
//视频编码类型选择++++++++++videoEncodeTypeSelector= (Spinner)findViewById(R.id.videoEncodeTypeSelector); finalString[] videoEncodeTypes=newString[]{"软编(H.264)", "硬编(H.264)", "硬编(H.265)"}; ArrayAdapter<String>adapterVideoEncodeType=newArrayAdapter<String>(this, android.R.layout.simple_spinner_item, videoEncodeTypes); adapterVideoEncodeType.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); videoEncodeTypeSelector.setAdapter(adapterVideoEncodeType); videoEncodeTypeSelector.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener() { publicvoidonItemSelected(AdapterView<?>parent, Viewview, intposition, longid) { if (isRTSPPublisherRunning||isPushingRtmp||isGB28181StreamRunning||isRecording) { Log.e(TAG, "Could not switch video encoder type during publishing.."); return; } videoEncodeType=position; Log.i(TAG, "[视频编码类型]Currently choosing: "+videoEncodeTypes[position] +", videoEncodeType: "+videoEncodeType); } publicvoidonNothingSelected(AdapterView<?>parent) { } });
考虑到Android端设备编码性能,Android平台H.265编码,我们仅支持硬编码,如果需要H.265硬编,只需要调用SetSmartPublisherVideoHevcHWEncoder()接口即可,其中,第二个参数是针对编码码率的设定。
/*** Author: daniusdk.com* Set Video H.265(hevc) hardware encoder, if support H.265(hevc) hardware encoder, it will return 0(设置H.265硬编码)** @param kbps: the kbps of different resolution.** @return {0} if successful*/publicnativeintSetSmartPublisherVideoHevcHWEncoder(longhandle, intkbps);
当然也可以使用Native Media NDK硬编码,需要注意的是,Native Media NDK硬编码,需要Android 5.0以上系统,而且接口并不像原生那么全:
/*** 设置视频硬编码是否使用 Native Media NDK, 默认是不使用, 安卓5.0以下设备不支持* @param handle* @param is_native: 0表示不使用, 1表示使用, sdk默认是0.* @return {0} if successful*/publicnativeintSetNativeMediaNDK(longhandle, intis_native);
针对H.265硬编码,其他接口设计如下:
/** 设置视频硬编码码率控制模式* @param hw_bitrate_mode: -1表示使用默认值, 不设置也会使用默认值, 0:CQ, 1:VBR, 2:CBR, 3:CBR_FD, 请参考:android.media.MediaCodecInfo.EncoderCapabilities* 注意硬编码和手机硬件有关,多数手机只支持部分码率模式, 另外硬编码设备差异很大,不同设备同一码率控制模式效果可能不一样* @return {0} if successful*/publicnativeintSetVideoHWEncoderBitrateMode(longhandle, inthw_bitrate_mode); /** 设置视频硬编码复杂度, 安卓5.0及以上支持* @param hw_complexity: -1表示不设置, 请参考:android.media.MediaCodecInfo.EncoderCapabilities.getComplexityRange() 和 android.media.MediaFormat.KEY_COMPLEXITY* 注意硬编码和手机硬件有关,部分手机可能不支持此设置* @return {0} if successful*/publicnativeintSetVideoHWEncoderComplexity(longhandle, inthw_complexity); /** 设置视频硬编码质量, 安卓9及以上支持, 仅当硬编码器码率控制模式(BitrateMode)是CQ(constant-quality mode)时才有效* @param hw_quality: -1表示不设置, 请参考:android.media.MediaCodecInfo.EncoderCapabilities.getQualityRange() 和 android.media.MediaFormat.KEY_QUALITY* 注意硬编码和手机硬件有关,部分手机可能不支持此设置* @return {0} if successful*/publicnativeintSetVideoHWEncoderQuality(longhandle, inthw_quality); /** 设置视频硬编码最大码率, 安卓没有相关文档说明, 所以不建议设置,* @param hw_max_bitrate: 每秒最大码率, 单位bps* @return {0} if successful*/publicnativeintSetVideoHWEncoderMaxBitrate(longhandle, longhw_max_bitrate);
相关调用如下:
inthevcHWKbps=setHardwareEncoderKbps(false, video_width_, video_height_); hevcHWKbps=hevcHWKbps*fps/25; Log.i(TAG, "hevcHWKbps: "+hevcHWKbps); intisSupportHevcHWEncoder=libPublisher .SetSmartPublisherVideoHevcHWEncoder(publisherHandle, hevcHWKbps); if (isSupportHevcHWEncoder==0) { libPublisher.SetNativeMediaNDK(publisherHandle, 0); libPublisher.SetVideoHWEncoderBitrateMode(publisherHandle, 0); // 0:CQ, 1:VBR, 2:CBRlibPublisher.SetVideoHWEncoderQuality(publisherHandle, 39); // libPublisher.SetVideoHWEncoderMaxBitrate(publisherHandle, ((long)hevcHWKbps)*1200);Log.i(TAG, "Great, it supports hevc hardware encoder!"); }
总结
GB28181-2022针对H.265描述,是2016的补充,随着今年七月份开始针对2022的实施推广,相信GB28181这块会应用到各行各业,如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景。GB28181设备接入端支持H.265难度不大,平台侧如果需要web播放,一般来说是需要转H.264在播放,对国标平台侧的专门性能提高了要求,如果是cs架构,问题不大。