From ad0571ed5fb4fbd751891f07f40c4e206ebbe0d1 Mon Sep 17 00:00:00 2001
From: Joshua Breeden <jbreeden@me.com>
Date: Wed, 1 Nov 2017 11:16:19 -0400
Subject: [PATCH 2/2] Add support for non-interleaved H.264/SVC over RTP

---
 Changelog                    |  2 +-
 libavformat/rtpdec.c         |  1 +
 libavformat/rtpdec_formats.h |  1 +
 libavformat/rtpdec_h264.c    | 80 +++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/Changelog b/Changelog
index 8c45b2946d..8c3a1683a2 100644
--- a/Changelog
+++ b/Changelog
@@ -7,7 +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:
 - deflicker video filter
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
index 4acb1ca629..1c5814749a 100644
--- a/libavformat/rtpdec.c
+++ b/libavformat/rtpdec.c
@@ -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);
diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h
index a436c9d62c..b67d1e338f 100644
--- a/libavformat/rtpdec_formats.h
+++ b/libavformat/rtpdec_formats.h
@@ -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;
diff --git a/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c
index 6f8148ab6d..485a494892 100644
--- a/libavformat/rtpdec_h264.c
+++ b/libavformat/rtpdec_h264.c
@@ -308,6 +308,69 @@ 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 y, t;
+    int opt_offset;
+
+    if (len < 5)
+        return AVERROR_INVALIDDATA;
+
+    // skip some NAL header info
+    src     += 4;
+    src_len -= 4;
+
+    // skip optional fields if present
+    y = (src[0] >> 6) & 1;
+    t = (src[0] >> 5) & 1;
+    // 3 bytes indicated by y, 2 bytes for t, and skip over current byte
+    opt_offset = y * 3 + t * 2 + 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, reset buffer to first NAL
+    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;
+
+    while (src_len > 2) {
+        uint16_t nal_size = AV_RB16(src);
+        src     += 2;
+        src_len -= 2;
+        // copying
+        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 +423,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 +485,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

