原文链接:https://blog.csdn.net/hiwubihe/article/details/84704046
本篇介绍一下H265怎么打包RTP,在H265中,每一个前缀码00000001后面跟随的前两个字节为NALU的语法元素,总体结构如下
这两个字节字段分布如下,F(forbidden_zero_bit)通常为0,LayId(nuh_layer_id)通常为0,Tid(nuh_temporal_id_plus1)通常为1,所以对一段码流来说第二字节通常都是1。
1. 当收到NALU单元长度小于MTU时,直接把00000001/000001前缀去掉,加上RTPHead即可
2.当收到NALU单元长度大于MTU时,需要做FU分包处理,先把00000001前缀+2B类型去掉,然后对剩下的数据分包处理。分包的每一段数据前加上FUHead,FUHead长度是3字节。FUHead[0],FUHead[1]的结构和H265NULU类型2B结构相同,只是Type取值49即可。FUHead[2]结构如下,S置1表示分包开始,E置1分包结束,中间包都不置1,后面6bit就是H265的类型字段。
H265类型定义如下
/*********************************************************************************
* NAL unit type codes
********************************************************************************/
enum HEVCNALUnitType {
HEVC_NAL_TRAIL_N = 0,
HEVC_NAL_TRAIL_R = 1,
HEVC_NAL_TSA_N = 2,
HEVC_NAL_TSA_R = 3,
HEVC_NAL_STSA_N = 4,
HEVC_NAL_STSA_R = 5,
HEVC_NAL_RADL_N = 6,
HEVC_NAL_RADL_R = 7,
HEVC_NAL_RASL_N = 8,
HEVC_NAL_RASL_R = 9,
HEVC_NAL_VCL_N10 = 10,
HEVC_NAL_VCL_R11 = 11,
HEVC_NAL_VCL_N12 = 12,
HEVC_NAL_VCL_R13 = 13,
HEVC_NAL_VCL_N14 = 14,
HEVC_NAL_VCL_R15 = 15,
HEVC_NAL_BLA_W_LP = 16,
HEVC_NAL_BLA_W_RADL = 17,
HEVC_NAL_BLA_N_LP = 18,
HEVC_NAL_IDR_W_RADL = 19,
HEVC_NAL_IDR_N_LP = 20,
HEVC_NAL_CRA_NUT = 21,
HEVC_NAL_IRAP_VCL22 = 22,
HEVC_NAL_IRAP_VCL23 = 23,
HEVC_NAL_RSV_VCL24 = 24,
HEVC_NAL_RSV_VCL25 = 25,
HEVC_NAL_RSV_VCL26 = 26,
HEVC_NAL_RSV_VCL27 = 27,
HEVC_NAL_RSV_VCL28 = 28,
HEVC_NAL_RSV_VCL29 = 29,
HEVC_NAL_RSV_VCL30 = 30,
HEVC_NAL_RSV_VCL31 = 31,
HEVC_NAL_VPS = 32,
HEVC_NAL_SPS = 33,
HEVC_NAL_PPS = 34,
HEVC_NAL_AUD = 35,
HEVC_NAL_EOS_NUT = 36,
HEVC_NAL_EOB_NUT = 37,
HEVC_NAL_FD_NUT = 38,
HEVC_NAL_SEI_PREFIX = 39,
HEVC_NAL_SEI_SUFFIX = 40,
};
附上一段FFMPEG代码理解
static void nal_send(AVFormatContext *ctx, const uint8_t *buf, int len, int last_packet_of_frame)
{
RTPMuxContext *rtp_ctx = ctx->priv_data;
int rtp_payload_size = rtp_ctx->max_payload_size - RTP_HEVC_HEADERS_SIZE;
int nal_type = (buf[0] >> 1) & 0x3F;
//长度<MTU直接打包RTP发送
/* send it as one single NAL unit? */
if (len <= rtp_ctx->max_payload_size) {
/* use the original NAL unit buffer and transmit it as RTP payload */
ff_rtp_send_data(ctx, buf, len, last_packet_of_frame);
} else {
/******************************************************************************
create the HEVC payload header and transmit the buffer as fragmentation units (FU)
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F| Type | LayerId | TID |
+-------------+-----------------+
F = 0
Type = 49 (fragmentation unit (FU))
LayerId = 0
TID = 1
*******************************************************************************/
//分包先赋值RTP头三个字节
//类型49表示该包是FU分包
rtp_ctx->buf[0] = 49 << 1;
//保持原来H265类型字段第二个字段 一般都是1
rtp_ctx->buf[1] = 1;
/*******************************************************************************
create the FU header
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|S|E| FuType |
+---------------+
S = variable
E = variable
FuType = NAL unit type
*******************************************************************************/
//保持原来H265类型字段类型字段
rtp_ctx->buf[2] = nal_type;
/* set the S bit: mark as start fragment */
//设置开始标志
rtp_ctx->buf[2] |= 1 << 7;
/* pass the original NAL header */
//去掉H265头类型长度
buf += 2;
len -= 2;
while (len > rtp_payload_size) {
/* complete and send current RTP packet */
memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, rtp_payload_size);
ff_rtp_send_data(ctx, rtp_ctx->buf, rtp_ctx->max_payload_size, 0);
buf += rtp_payload_size;
len -= rtp_payload_size;
/* reset the S bit */
//去掉开始结束标志
rtp_ctx->buf[2] &= ~(1 << 7);
}
/* set the E bit: mark as last fragment */
//设置结束标志
rtp_ctx->buf[2] |= 1 << 6;
/* complete and send last RTP packet */
memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, len);
ff_rtp_send_data(ctx, rtp_ctx->buf, len + 2, last_packet_of_frame);
}
}
H265类型分析