鉴于宽广码友对上一篇文章RTMP推送扩大反对HEVC(H265)的Metadata数据结构还存在不分明的中央,这里对RTMP推送Metadata的构造进行详解。
首先, 咱们先解说下 H.264/AVC metadata 语法,不便大家了解,这相干的文章大家在网上很容易找到,如果大家比拟相熟能够跳过;
参考:《ISO/IEC 14496-15 NAL unit structured video》AVCDecoderConfigurationRecord构造:(最小长度7字节)
阐明:
libSkeyeRTMPPusher咱们称之为Metadata,而在FFmpeg中,则称之为extradata,extradata解析,详见ff_h264_decode_extradata()
留神:
第5字节的最初2位,示意的就是NAL size的字节数。在AVCC格局中,每个NAL后面都会有NAL size字段。NAL size可能是1字节、2字节或4字节(4字节较常见),解析extradata重要目标就是确认这个值。(而Annex-B格局,要split NAL,只有去探测0x000001就能够了)
H.264 metadata 示例(AVCC格局)
metadata 如上
metasize 47
05| FF NAL size: 4字节
06| E1 SPS num: 1
07| 00 1F SPS size: 31字节
09| 67 NAL type: SPS
40| 01 PPS num: 1
41| 00 05 PPS size: 5字节
42| 68 NAL type: PPS
H.265/HEVC metadata语法
参照HEVCDecoderConfigurationRecord:(最小长度23字节)
HEVC metadata 示例
metadata 如上
metasize 111
24| 20 NAL type: VPS
25| 00 01 VPS num: 1
27| 00 19 VPS size: 25字节
54| 21 NAL type: SPS
55| 00 01 SPS num: 1
57| 00 29 SPS size: 41字节
100| 22 NAL type: PPS
hvcC extradata是一种头形容的格局。而annex-b格局中,则是将VPS, SPS和PPS等同于一般NAL,用start code分隔,非常简单。Annex-B格局的”extradata”:
start code+VPS+start code+SPS+start code+PPS
SkeyeRTMP中metadata填写VPS,SPS和PPS填写如下:
body[i++] = 0x03; // numOfArrays body[i++] = 0x20; // configurationVersion body[i++] = 0x00; // configurationVersion body[i++] = 0x01; // configurationVersion // vps data length body[i++] = lpMetaData->nVpsLen>>8&0xff; body[i++] = lpMetaData->nVpsLen&0xff; // vps data memcpy(&body[i],lpMetaData->Vps,lpMetaData->nVpsLen); i= i+lpMetaData->nVpsLen; body[i++] = 0x21; // configurationVersion body[i++] = 0x00; // configurationVersion body[i++] = 0x01; // configurationVersion // sps data length body[i++] = lpMetaData->nSpsLen>>8&0xff;; body[i++] = lpMetaData->nSpsLen&0xff; // sps data memcpy(&body[i],lpMetaData->Sps,lpMetaData->nSpsLen); i= i+lpMetaData->nSpsLen; body[i++] = 0x22; // configurationVersion body[i++] = 0x00; // configurationVersion body[i++] = 0x01; // configurationVersion // pps data length body[i++] = lpMetaData->nPpsLen>>8&0xff; body[i++] = lpMetaData->nPpsLen&0xff; // pps data memcpy(&body[i],lpMetaData->Pps,lpMetaData->nPpsLen); i= i+lpMetaData->nPpsLen;
从上一篇文章RTMP推送扩大反对HEVC(H265)咱们理解了HEVCDecoderConfigurationRecord构造:
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;
因为咱们能够不必要关怀其余的构造,所以咱们从numOfArrays填写起,这里是三个数据信息结构(vps,sps,pps),numOfArrays=3,而后HVCCNALUnitArray构造进行填写数据头信息:
typedef struct HVCCNALUnitArray { uint8_t array_completeness; uint8_t NAL_unit_type; uint16_t numNalus; uint16_t *nalUnitLength; uint8_t **nalUnit;} HVCCNALUnitArray;
如VPS填写如下:
body[i++] = 0x20; // configurationVersion body[i++] = 0x00; // configurationVersion body[i++] = 0x01; // configurationVersion // vps data length body[i++] = lpMetaData->nVpsLen>>8&0xff; body[i++] = lpMetaData->nVpsLen&0xff;
其余如SPS和PPS同理,见上文代码。这一点和H264 metadata构造填写是有很大的区别。
参考文章:
https://blog.csdn.net/yue_hua...
有相干的技术问题,欢送大家和我进行技术交换:
295222688@qq.com
大家也能够退出SkeyeRTMPPusher直播推流技术 QQ群进行探讨:
102644504