diff mbox

[FFmpeg-devel] Support for h264/SVC over RTP and SVC base layer decoding in h264

Message ID 1509476048958.76834@harris.com
State Superseded
Headers show

Commit Message

Breeden, Joshua Oct. 31, 2017, 6:53 p.m. UTC
Hello,

First patch submission... hopefully I do all of this correctly.?

Added basic support for H264 Annex G (Scalable Video Coding) to RTP module. Implement splitting of PACSI NAL units (type 30).

Used existing H264 SPS decoder to parse Subset SPS NAL units (type 15) in h264 extradata.

As a result, FFmpeg can now parse SVC over RTP. The video? base layer, which is AVC compatible, can be decoded.


Signed-off-by: Joshua Breeden <jbreed05@harris.com>



Joshua Breeden

Software Engineer-Developer

SPACE AND INTELLIGENCE SYSTEMS / HARRIS CORPORATION

Office: +1-757-483-0226 x1008

Comments

Carl Eugen Hoyos Nov. 1, 2017, 12:56 a.m. UTC | #1
2017-10-31 19:53 GMT+01:00 Breeden, Joshua <JBREED05@harris.com>:
> Hello,
>
> First patch submission... hopefully I do all of this correctly.?

Your patches contain a lot of trailing whitespace (afaict...)
that cannot be committed to our repository, please remove it.

To find it you can use the script "tools/patcheck" in the
FFmpeg source.

The log message should start with "lavc/h264_parse: " and
"lavf/rtpdec_h264: " or similar, see the gitlog for the files.

Thank you, Carl Eugen
diff mbox

Patch

From a9b89e1568b164031506164c2efd5533be93a56e Mon Sep 17 00:00:00 2001
From: Joshua Breeden <jbreed05@harris.com>
Date: Tue, 31 Oct 2017 13:26:02 -0400
Subject: [PATCH 2/2] Add support for non-interleaved h264/SVC over RTP

---
 libavformat/rtpdec.c         |  1 +
 libavformat/rtpdec_formats.h |  1 +
 libavformat/rtpdec_h264.c    | 80 +++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 81 insertions(+), 1 deletion(-)

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..4c3f52be05 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,
+};
\ No newline at end of file
-- 
2.11.0