1、H264/H265封包
代码位置:FFmpeg的文件rtpenc_h264_hevc.c(4.0.5版本)
static void nal_send(AVFormatContext *s1, const uint8_t *buf, int size, int last)
{
RTPMuxContext *s = s1->priv_data;
enum AVCodecID codec = s1->streams[0]->codecpar->codec_id;
av_log(s1, AV_LOG_DEBUG, "Sending NAL %x of len %d M=%d\n", buf[0] & 0x1F, size, last);
if (size <= s->max_payload_size) {
int buffered_size = s->buf_ptr - s->buf;
int header_size;
int skip_aggregate = 0;
if (codec == AV_CODEC_ID_H264) {
// H264的NAL头为1个字节
header_size = 1;
skip_aggregate = s->flags & FF_RTP_FLAG_H264_MODE0;
} else {
// H265的NAL头为1个字节
header_size = 2;
}
// Flush buffered NAL units if the current unit doesn't fit
//max_payload_size一般为1500,有些会去掉tcp或者udp协议头,取1460或者1400
if (buffered_size + 2 + size > s->max_payload_size) {
flush_buffered(s1, 0);
buffered_size = 0;
}
// If we aren't using mode 0, and the NAL unit fits including the
// framing (2 bytes length, plus 1/2 bytes for the STAP-A/AP marker),
// write the unit to the buffer as a STAP-A/AP packet, otherwise flush
// and send as single NAL.
if (buffered_size + 2 + header_size + size <= s->max_payload_size &&
!skip_aggregate) {
//聚合包处理
if (buffered_size == 0) {
if (codec == AV_CODEC_ID_H264) {
*s->buf_ptr++ = 24;
} else {
*s->buf_ptr++ = 48 << 1;
*s->buf_ptr++ = 1;
}
}
AV_WB16(s->buf_ptr, size);
s->buf_ptr += 2;
memcpy(s->buf_ptr, buf, size);
s->buf_ptr += size;
s->buffered_nals++;
} else {
flush_buffered(s1, 0);
ff_rtp_send_data(s1, buf, size, last);
}
} else {//NALU分片处理
int flag_byte, header_size;
flush_buffered(s1, 0);
if (codec == AV_CODEC_ID_H264 && (s->flags & FF_RTP_FLAG_H264_MODE0)) {
av_log(s1, AV_LOG_ERROR,
"NAL size %d > %d, try -slice-max-size %d\n", size,
s->max_payload_size, s->max_payload_size);
return;
}
av_log(s1, AV_LOG_DEBUG, "NAL size %d > %d\n", size, s->max_payload_size);
if (codec == AV_CODEC_ID_H264) {
uint8_t type = buf[0] & 0x1F;
uint8_t nri = buf[0] & 0x60;
s->buf[0] = 28; /* FU Indicator; Type = 28 ---> FU-A */
s->buf[0] |= nri;
s->buf[1] = type;
s->buf[1] |= 1 << 7;
buf += 1;
size -= 1;
flag_byte = 1;
header_size = 2;
} else {
uint8_t nal_type = (buf[0] >> 1) & 0x3F;
/*
* 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
*/
s->buf[0] = 49 << 1;
s->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
*/
s->buf[2] = nal_type;
/* set the S bit: mark as start fragment */
s->buf[2] |= 1 << 7;
/* pass the original NAL header */
buf += 2;
size -= 2;
flag_byte = 2;
header_size = 3;
}
while (size + header_size > s->max_payload_size) {
memcpy(&s->buf[header_size], buf, s->max_payload_size - header_size);
ff_rtp_send_data(s1, s->buf, s->max_payload_size, 0);
buf += s->max_payload_size - header_size;
size -= s->max_payload_size - header_size;
s->buf[flag_byte] &= ~(1 << 7);
}
s->buf[flag_byte] |= 1 << 6;
memcpy(&s->buf[header_size], buf, size);
ff_rtp_send_data(s1, s->buf, size + header_size, last);
}
}
2、H264解包
代码位置:FFmpeg的文件rtpdec_h264.c(4.0.5版本)
// return 0 on packet, no more left, 1 on packet, 1 on partial packet
static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data,
AVStream *st, AVPacket *pkt, uint32_t *timestamp,
const uint8_t *buf, int len, uint16_t seq,
int flags)
{
uint8_t nal;
uint8_t type;
int result = 0;
if (!len) {
av_log(ctx, AV_LOG_ERROR, "Empty H.264 RTP packet\n");
return AVERROR_INVALIDDATA;
}
nal = buf[0];
type = nal & 0x1f;
/* Simplify the case (these are all the NAL types used internally by
* the H.264 codec). */
if (type >= 1 && type <= 23)
type = 1;
switch (type) {
case 0: // undefined, but pass them through
case 1:
if ((result = av_new_packet(pkt, len + sizeof(start_sequence))) < 0)
return result;
memcpy(pkt->data, start_sequence, sizeof(start_sequence));
memcpy(pkt->data + sizeof(start_sequence), buf, len);
COUNT_NAL_TYPE(data, nal);
break;
case 24: // STAP-A (one packet, multiple nals)
// consume the STAP-A NAL
buf++;
len--;
result = ff_h264_handle_aggregated_packet(ctx, data, pkt, buf, len, 0,
NAL_COUNTERS, NAL_MASK);
break;
case 25: // STAP-B
case 26: // MTAP-16
case 27: // MTAP-24
case 29: // FU-B
avpriv_report_missing_feature(ctx, "RTP H.264 NAL unit type %d", type);
result = AVERROR_PATCHWELCOME;
break;
case 28: // FU-A (fragmented nal)
result = h264_handle_packet_fu_a(ctx, data, pkt, buf, len,
NAL_COUNTERS, NAL_MASK);
break;
case 30: // undefined
case 31: // undefined
default:
av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)\n", type);
result = AVERROR_INVALIDDATA;
break;
}
pkt->stream_index = st->index;
return result;
}
3、H265解包
代码位置:FFmpeg的文件rtpdec_hevc.c(4.0.5版本)
static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx,
AVStream *st, AVPacket *pkt, uint32_t *timestamp,
const uint8_t *buf, int len, uint16_t seq,
int flags)
{
const uint8_t *rtp_pl = buf;
int tid, lid, nal_type;
int first_fragment, last_fragment, fu_type;
uint8_t new_nal_header[2];
int res = 0;
/* sanity check for size of input packet: 1 byte payload at least */
if (len < RTP_HEVC_PAYLOAD_HEADER_SIZE + 1) {
av_log(ctx, AV_LOG_ERROR, "Too short RTP/HEVC packet, got %d bytes\n", len);
return AVERROR_INVALIDDATA;
}
/*
* decode the HEVC payload header according to section 4 of draft version 6:
*
* 0 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |F| Type | LayerId | TID |
* +-------------+-----------------+
*
* Forbidden zero (F): 1 bit
* NAL unit type (Type): 6 bits
* NUH layer ID (LayerId): 6 bits
* NUH temporal ID plus 1 (TID): 3 bits
*/
nal_type = (buf[0] >> 1) & 0x3f;
lid = ((buf[0] << 5) & 0x20) | ((buf[1] >> 3) & 0x1f);
tid = buf[1] & 0x07;
/* sanity check for correct layer ID */
if (lid) {
/* future scalable or 3D video coding extensions */
avpriv_report_missing_feature(ctx, "Multi-layer HEVC coding");
return AVERROR_PATCHWELCOME;
}
/* sanity check for correct temporal ID */
if (!tid) {
av_log(ctx, AV_LOG_ERROR, "Illegal temporal ID in RTP/HEVC packet\n");
return AVERROR_INVALIDDATA;
}
/* sanity check for correct NAL unit type */
if (nal_type > 50) {
av_log(ctx, AV_LOG_ERROR, "Unsupported (HEVC) NAL type (%d)\n", nal_type);
return AVERROR_INVALIDDATA;
}
switch (nal_type) {
/* video parameter set (VPS) */
case 32:
/* sequence parameter set (SPS) */
case 33:
/* picture parameter set (PPS) */
case 34:
/* supplemental enhancement information (SEI) */
case 39:
/* single NAL unit packet */
default:
/* create A/V packet */
if ((res = av_new_packet(pkt, sizeof(start_sequence) + len)) < 0)
return res;
/* A/V packet: copy start sequence */
memcpy(pkt->data, start_sequence, sizeof(start_sequence));
/* A/V packet: copy NAL unit data */
memcpy(pkt->data + sizeof(start_sequence), buf, len);
break;
/* aggregated packet (AP) - with two or more NAL units */
case 48:
/* pass the HEVC payload header */
buf += RTP_HEVC_PAYLOAD_HEADER_SIZE;
len -= RTP_HEVC_PAYLOAD_HEADER_SIZE;
/* pass the HEVC DONL field */
if (rtp_hevc_ctx->using_donl_field) {
buf += RTP_HEVC_DONL_FIELD_SIZE;
len -= RTP_HEVC_DONL_FIELD_SIZE;
}
res = ff_h264_handle_aggregated_packet(ctx, rtp_hevc_ctx, pkt, buf, len,
rtp_hevc_ctx->using_donl_field ?
RTP_HEVC_DOND_FIELD_SIZE : 0,
NULL, 0);
if (res < 0)
return res;
break;
/* fragmentation unit (FU) */
case 49:
/* pass the HEVC payload header */
buf += RTP_HEVC_PAYLOAD_HEADER_SIZE;
len -= RTP_HEVC_PAYLOAD_HEADER_SIZE;
/*
* decode the FU header
*
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* |S|E| FuType |
* +---------------+
*
* Start fragment (S): 1 bit
* End fragment (E): 1 bit
* FuType: 6 bits
*/
first_fragment = buf[0] & 0x80;
last_fragment = buf[0] & 0x40;
fu_type = buf[0] & 0x3f;
/* pass the HEVC FU header */
buf += RTP_HEVC_FU_HEADER_SIZE;
len -= RTP_HEVC_FU_HEADER_SIZE;
/* pass the HEVC DONL field */
if (rtp_hevc_ctx->using_donl_field) {
buf += RTP_HEVC_DONL_FIELD_SIZE;
len -= RTP_HEVC_DONL_FIELD_SIZE;
}
av_log(ctx, AV_LOG_TRACE, " FU type %d with %d bytes\n", fu_type, len);
/* sanity check for size of input packet: 1 byte payload at least */
if (len <= 0) {
if (len < 0) {
av_log(ctx, AV_LOG_ERROR,
"Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
len, nal_type);
return AVERROR_INVALIDDATA;
} else {
return AVERROR(EAGAIN);
}
}
if (first_fragment && last_fragment) {
av_log(ctx, AV_LOG_ERROR, "Illegal combination of S and E bit in RTP/HEVC packet\n");
return AVERROR_INVALIDDATA;
}
new_nal_header[0] = (rtp_pl[0] & 0x81) | (fu_type << 1);
new_nal_header[1] = rtp_pl[1];
res = ff_h264_handle_frag_packet(pkt, buf, len, first_fragment,
new_nal_header, sizeof(new_nal_header));
break;
/* PACI packet */
case 50:
/* Temporal scalability control information (TSCI) */
avpriv_report_missing_feature(ctx, "PACI packets for RTP/HEVC");
res = AVERROR_PATCHWELCOME;
break;
}
pkt->stream_index = st->index;
return res;
}