乐趣区

关于go:RTMP推送扩展支持HEVCH265之Metadata结构填写详解

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

退出移动版