From a592febfab5d5a7c534f6d21a42bf23289ff3ffa Mon Sep 17 00:00:00 2001
From: Joshua Breeden <jbreeden@me.com>
Date: Wed, 1 Nov 2017 13:39:54 -0400
Subject: [PATCH 2/2] Add support for non-interleaved H.264 SVC over RTP
---
Changelog | 1 +
libavformat/rtpdec.c | 1 +
libavformat/rtpdec_formats.h | 1 +
libavformat/rtpdec_h264.c | 79 +++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 81 insertions(+), 1 deletion(-)
@@ -7,6 +7,7 @@ version <next>:
requires 2.1 (or later) and pkg-config.
- VDA dropped (use VideoToolbox instead)
- MagicYUV encoder
+- RTP depacketization of non-interleaved H.264/SVC (RFC 6190)
version 3.4:
@@ -96,6 +96,7 @@ void ff_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler(&ff_h263_2000_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_h263_rfc2190_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_h264_dynamic_handler);
+ ff_register_dynamic_payload_handler(&ff_h264_svc_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_hevc_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_ilbc_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_jpeg_dynamic_handler);
@@ -64,6 +64,7 @@ extern RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler;
extern RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler;
extern RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler;
extern RTPDynamicProtocolHandler ff_h264_dynamic_handler;
+extern RTPDynamicProtocolHandler ff_h264_svc_dynamic_handler;
extern RTPDynamicProtocolHandler ff_hevc_dynamic_handler;
extern RTPDynamicProtocolHandler ff_ilbc_dynamic_handler;
extern RTPDynamicProtocolHandler ff_jpeg_dynamic_handler;
@@ -308,6 +308,68 @@ static int h264_handle_packet_fu_a(AVFormatContext *ctx, PayloadContext *data, A
return ff_h264_handle_frag_packet(pkt, buf, len, start_bit, &nal, 1);
}
+static int h264_handle_packet_pacsi(AVFormatContext *ctx, PayloadContext *data, AVPacket *pkt,
+ const uint8_t *buf, int len,
+ int *nal_counters, int nal_mask)
+{
+ uint8_t *dst = NULL;
+ const uint8_t *src = buf;
+ int src_len = len;
+ int total_length = 0;
+ int ret;
+ int tl0_pic_idx_bytes, donc_bytes;
+ int opt_offset;
+
+ if (len < 5)
+ return AVERROR_INVALIDDATA;
+
+ src += 4;
+ src_len -= 4;
+
+ tl0_pic_idx_bytes = 3 * ((src[0] >> 6) & 1);
+ donc_bytes = 2 * ((src[0] >> 5) & 1);
+
+ opt_offset = tl0_pic_idx_bytes + donc_bytes + 1;
+ src += opt_offset;
+ src_len -= opt_offset;
+
+ // calculate size of NALs plus start codes
+ while (src_len > 2) {
+ uint16_t nal_size = AV_RB16(src);
+
+ total_length += sizeof(start_sequence) + nal_size;
+ src += 2 + nal_size;
+ src_len -= 2 + nal_size;
+ }
+
+ // create packet to hold NALs
+ if ((ret = av_new_packet(pkt, total_length)) < 0)
+ return ret;
+ dst = pkt->data;
+ src = buf + 4 + opt_offset;
+ src_len = len - 4 - opt_offset;
+
+ // copy NALs with start codes
+ while (src_len > 2) {
+ uint16_t nal_size = AV_RB16(src);
+ src += 2;
+ src_len -= 2;
+
+ memcpy(dst, start_sequence, sizeof(start_sequence));
+ dst += sizeof(start_sequence);
+ memcpy(dst, src, nal_size);
+ if (nal_counters)
+ nal_counters[(*src) & nal_mask]++;
+ dst += nal_size;
+
+ // eat what we handled
+ src += nal_size;
+ src_len -= nal_size;
+ }
+
+ return 0;
+}
+
// 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,
@@ -360,7 +422,11 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data,
NAL_COUNTERS, NAL_MASK);
break;
- case 30: // undefined
+ case 30: // PACSI (Annex G - SVC)
+ result = h264_handle_packet_pacsi(ctx, data, pkt, buf, len,
+ NAL_COUNTERS, NAL_MASK);
+ break;
+
case 31: // undefined
default:
av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)\n", type);
@@ -418,3 +484,14 @@ RTPDynamicProtocolHandler ff_h264_dynamic_handler = {
.close = h264_close_context,
.parse_packet = h264_handle_packet,
};
+
+RTPDynamicProtocolHandler ff_h264_svc_dynamic_handler = {
+ .enc_name = "H264-SVC",
+ .codec_type = AVMEDIA_TYPE_VIDEO,
+ .codec_id = AV_CODEC_ID_H264,
+ .need_parsing = AVSTREAM_PARSE_FULL,
+ .priv_data_size = sizeof(PayloadContext),
+ .parse_sdp_a_line = parse_h264_sdp_line,
+ .close = h264_close_context,
+ .parse_packet = h264_handle_packet,
+};
--
2.11.0