鉴于宽广码友对上一篇文章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