OSDN Git Service

Merge commit '5956f489d0452ff6dea6b6b81b4fa8e596fc5684'
[android-x86/external-ffmpeg.git] / libavformat / rtpdec_hevc.c
index 13df942..b374e09 100644 (file)
@@ -2,35 +2,39 @@
  * RTP parser for HEVC/H.265 payload format (draft version 6)
  * Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  *
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
 #include "libavutil/base64.h"
+#include "libavcodec/get_bits.h"
 
 #include "avformat.h"
 #include "rtpdec.h"
 #include "rtpdec_formats.h"
 
-#define RTP_HEVC_PAYLOAD_HEADER_SIZE  2
-#define RTP_HEVC_FU_HEADER_SIZE       1
-#define RTP_HEVC_DONL_FIELD_SIZE      2
-#define HEVC_SPECIFIED_NAL_UNIT_TYPES 48
+#define RTP_HEVC_PAYLOAD_HEADER_SIZE       2
+#define RTP_HEVC_FU_HEADER_SIZE            1
+#define RTP_HEVC_DONL_FIELD_SIZE           2
+#define RTP_HEVC_DOND_FIELD_SIZE           1
+#define RTP_HEVC_AP_NALU_LENGTH_FIELD_SIZE 2
+#define HEVC_SPECIFIED_NAL_UNIT_TYPES      48
 
 /* SDP out-of-band signaling data */
 struct PayloadContext {
@@ -42,29 +46,6 @@ struct PayloadContext {
 
 static const uint8_t start_sequence[] = { 0x00, 0x00, 0x00, 0x01 };
 
-static av_cold PayloadContext *hevc_new_context(void)
-{
-    return av_mallocz(sizeof(PayloadContext));
-}
-
-static av_cold void hevc_free_context(PayloadContext *data)
-{
-    av_free(data);
-}
-
-static av_cold int hevc_init(AVFormatContext *ctx, int st_index,
-                             PayloadContext *data)
-{
-    av_dlog(ctx, "hevc_init() for stream %d\n", st_index);
-
-    if (st_index < 0)
-        return 0;
-
-    ctx->streams[st_index]->need_parsing = AVSTREAM_PARSE_FULL;
-
-    return 0;
-}
-
 static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s,
                                               AVStream *stream,
                                               PayloadContext *hevc_data,
@@ -91,8 +72,8 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s,
     /* sprop-sei: [base64] */
     if (!strcmp(attr, "sprop-vps") || !strcmp(attr, "sprop-sps") ||
         !strcmp(attr, "sprop-pps") || !strcmp(attr, "sprop-sei")) {
-        uint8_t **data_ptr;
-        int *size_ptr;
+        uint8_t **data_ptr = NULL;
+        int *size_ptr = NULL;
         if (!strcmp(attr, "sprop-vps")) {
             data_ptr = &hevc_data->vps;
             size_ptr = &hevc_data->vps_size;
@@ -105,7 +86,8 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s,
         } else if (!strcmp(attr, "sprop-sei")) {
             data_ptr = &hevc_data->sei;
             size_ptr = &hevc_data->sei_size;
-        }
+        } else
+            av_assert0(0);
 
         ff_h264_parse_sprop_parameter_sets(s, data_ptr,
                                            size_ptr, value);
@@ -246,19 +228,19 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
     }
 
     /*
-      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
-    */
+     * 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;
@@ -283,19 +265,6 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
     }
 
     switch (nal_type) {
-    /* aggregated packets (AP) */
-    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;
-        }
-
-        /* fall-through */
     /* video parameter set (VPS) */
     case 32:
     /* sequence parameter set (SPS) */
@@ -323,6 +292,25 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
         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 */
@@ -330,17 +318,17 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
         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
-        */
+         *    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;
@@ -357,6 +345,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
 
         av_dlog(ctx, " 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) {
             new_nal_header[0] = (rtp_pl[0] & 0x81) | (fu_type << 1);
             new_nal_header[1] = rtp_pl[1];
@@ -385,11 +374,14 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
                 memcpy(pkt->data, buf, len);
             }
         } else {
-            /* sanity check for size of input packet: 1 byte payload at least */
-            av_log(ctx, AV_LOG_ERROR,
-                   "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
-                   len, nal_type);
-            res = AVERROR_INVALIDDATA;
+            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);
+                res = AVERROR_INVALIDDATA;
+            } else {
+                res = AVERROR(EAGAIN);
+            }
         }
 
         break;
@@ -410,9 +402,8 @@ RTPDynamicProtocolHandler ff_hevc_dynamic_handler = {
     .enc_name         = "H265",
     .codec_type       = AVMEDIA_TYPE_VIDEO,
     .codec_id         = AV_CODEC_ID_HEVC,
-    .init             = hevc_init,
+    .need_parsing     = AVSTREAM_PARSE_FULL,
+    .priv_data_size   = sizeof(PayloadContext),
     .parse_sdp_a_line = hevc_parse_sdp_line,
-    .alloc            = hevc_new_context,
-    .free             = hevc_free_context,
-    .parse_packet     = hevc_handle_packet
+    .parse_packet     = hevc_handle_packet,
 };