]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/hevc_parser.c
avcodec: Template creation for AAC decoder (SBR-module)
[ffmpeg] / libavcodec / hevc_parser.c
index d6171b04724d1ea8b20fa647d9bd4dff7875acec..f970de54747b01742220a4b50187ea78fc2c3495 100644 (file)
 
 #include "libavutil/common.h"
 
-#include "parser.h"
-#include "hevc.h"
 #include "golomb.h"
+#include "hevc.h"
+#include "parser.h"
 
 #define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
 
-typedef struct HEVCParseContext {
-    HEVCContext  h;
+#define IS_IRAP_NAL(nal) (nal->type >= 16 && nal->type <= 23)
+
+#define ADVANCED_PARSER CONFIG_HEVC_DECODER
+
+typedef struct HEVCParserContext {
     ParseContext pc;
-} HEVCParseContext;
+
+    HEVCPacket pkt;
+    HEVCParamSets ps;
+
+    int parsed_extradata;
+
+#if ADVANCED_PARSER
+    HEVCContext h;
+#endif
+} HEVCParserContext;
+
+#if !ADVANCED_PARSER
+static int hevc_parse_slice_header(AVCodecParserContext *s, HEVCNAL *nal,
+                                   AVCodecContext *avctx)
+{
+    HEVCParserContext *ctx = s->priv_data;
+    GetBitContext *gb = &nal->gb;
+
+    HEVCPPS *pps;
+    HEVCSPS *sps;
+    unsigned int pps_id;
+
+    get_bits1(gb);          // first slice in pic
+    if (IS_IRAP_NAL(nal))
+        get_bits1(gb);      // no output of prior pics
+
+    pps_id = get_ue_golomb_long(gb);
+    if (pps_id >= MAX_PPS_COUNT || !ctx->ps.pps_list[pps_id]) {
+        av_log(avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id);
+        return AVERROR_INVALIDDATA;
+    }
+    pps = (HEVCPPS*)ctx->ps.pps_list[pps_id]->data;
+    sps = (HEVCSPS*)ctx->ps.sps_list[pps->sps_id]->data;
+
+    /* export the stream parameters */
+    s->coded_width  = sps->width;
+    s->coded_height = sps->height;
+    s->width        = sps->output_width;
+    s->height       = sps->output_height;
+    s->format       = sps->pix_fmt;
+    avctx->profile  = sps->ptl.general_ptl.profile_idc;
+    avctx->level    = sps->ptl.general_ptl.level_idc;
+
+    /* ignore the rest for now*/
+
+    return 0;
+}
+
+static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf,
+                           int buf_size, AVCodecContext *avctx)
+{
+    HEVCParserContext *ctx = s->priv_data;
+    int ret, i;
+
+    ret = ff_hevc_split_packet(NULL, &ctx->pkt, buf, buf_size, avctx, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < ctx->pkt.nb_nals; i++) {
+        HEVCNAL *nal = &ctx->pkt.nals[i];
+
+        /* ignore everything except parameter sets and VCL NALUs */
+        switch (nal->type) {
+        case NAL_VPS: ff_hevc_decode_nal_vps(&nal->gb, avctx, &ctx->ps);    break;
+        case NAL_SPS: ff_hevc_decode_nal_sps(&nal->gb, avctx, &ctx->ps, 1); break;
+        case NAL_PPS: ff_hevc_decode_nal_pps(&nal->gb, avctx, &ctx->ps);    break;
+        case NAL_TRAIL_R:
+        case NAL_TRAIL_N:
+        case NAL_TSA_N:
+        case NAL_TSA_R:
+        case NAL_STSA_N:
+        case NAL_STSA_R:
+        case NAL_BLA_W_LP:
+        case NAL_BLA_W_RADL:
+        case NAL_BLA_N_LP:
+        case NAL_IDR_W_RADL:
+        case NAL_IDR_N_LP:
+        case NAL_CRA_NUT:
+        case NAL_RADL_N:
+        case NAL_RADL_R:
+        case NAL_RASL_N:
+        case NAL_RASL_R:
+            if (buf == avctx->extradata) {
+                av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit: %d\n", nal->type);
+                return AVERROR_INVALIDDATA;
+            }
+            hevc_parse_slice_header(s, nal, avctx);
+            break;
+        }
+    }
+
+    return 0;
+}
+#endif
 
 /**
  * Find the end of the current frame in the bitstream.
@@ -41,7 +137,7 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
                                int buf_size)
 {
     int i;
-    ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
+    ParseContext *pc = s->priv_data;
 
     for (i = 0; i < buf_size; i++) {
         int nut;
@@ -76,6 +172,7 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
     return END_NOT_FOUND;
 }
 
+#if ADVANCED_PARSER
 /**
  * Parse NAL units of found picture and decode some basic information.
  *
@@ -84,17 +181,26 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
  * @param buf buffer with field/frame data.
  * @param buf_size size of the buffer.
  */
-static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx,
-                      const uint8_t *buf, int buf_size)
+static inline int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf,
+                           int buf_size, AVCodecContext *avctx)
 {
-    HEVCContext   *h  = &((HEVCParseContext *)s->priv_data)->h;
-    GetBitContext *gb = &h->HEVClc->gb;
-    SliceHeader   *sh = &h->sh;
+    HEVCParserContext *ctx = s->priv_data;
+    HEVCContext       *h   = &ctx->h;
+    GetBitContext      *gb;
+    SliceHeader        *sh = &h->sh;
     HEVCParamSets *ps = &h->ps;
-    HEVCPacket   *pkt = &h->pkt;
+    HEVCPacket   *pkt = &ctx->pkt;
     const uint8_t *buf_end = buf + buf_size;
     int state = -1, i;
     HEVCNAL *nal;
+    int is_global = buf == avctx->extradata;
+
+    if (!h->HEVClc)
+        h->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
+    if (!h->HEVClc)
+        return AVERROR(ENOMEM);
+
+    gb = &h->HEVClc->gb;
 
     /* set some sane default values */
     s->pict_type         = AV_PICTURE_TYPE_I;
@@ -132,7 +238,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx
                 src_length = 20;
         }
 
-        consumed = ff_hevc_extract_rbsp(h, buf, src_length, nal);
+        consumed = ff_hevc_extract_rbsp(NULL, buf, src_length, nal);
         if (consumed < 0)
             return consumed;
 
@@ -142,7 +248,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx
             ff_hevc_decode_nal_vps(gb, avctx, ps);
             break;
         case NAL_SPS:
-            ff_hevc_decode_nal_sps(gb, avctx, ps, h->apply_defdispwin);
+            ff_hevc_decode_nal_sps(gb, avctx, ps, 1);
             break;
         case NAL_PPS:
             ff_hevc_decode_nal_pps(gb, avctx, ps);
@@ -167,6 +273,12 @@ static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx
         case NAL_IDR_W_RADL:
         case NAL_IDR_N_LP:
         case NAL_CRA_NUT:
+
+            if (is_global) {
+                av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit: %d\n", h->nal_unit_type);
+                return AVERROR_INVALIDDATA;
+            }
+
             sh->first_slice_in_pic_flag = get_bits1(gb);
             s->picture_structure = h->picture_struct;
             s->field_order = h->picture_struct;
@@ -178,13 +290,13 @@ static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx
 
             sh->pps_id = get_ue_golomb(gb);
             if (sh->pps_id >= MAX_PPS_COUNT || !ps->pps_list[sh->pps_id]) {
-                av_log(h->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id);
+                av_log(avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id);
                 return AVERROR_INVALIDDATA;
             }
             ps->pps = (HEVCPPS*)ps->pps_list[sh->pps_id]->data;
 
             if (ps->pps->sps_id >= MAX_SPS_COUNT || !ps->sps_list[ps->pps->sps_id]) {
-                av_log(h->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", ps->pps->sps_id);
+                av_log(avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", ps->pps->sps_id);
                 return AVERROR_INVALIDDATA;
             }
             if (ps->sps != (HEVCSPS*)ps->sps_list[ps->pps->sps_id]->data) {
@@ -204,7 +316,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx
                                                       ps->sps->ctb_height);
                 sh->slice_segment_addr = slice_address_length ? get_bits(gb, slice_address_length) : 0;
                 if (sh->slice_segment_addr >= ps->sps->ctb_width * ps->sps->ctb_height) {
-                    av_log(h->avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n",
+                    av_log(avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n",
                            sh->slice_segment_addr);
                     return AVERROR_INVALIDDATA;
                 }
@@ -220,7 +332,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx
             sh->slice_type = get_ue_golomb(gb);
             if (!(sh->slice_type == I_SLICE || sh->slice_type == P_SLICE ||
                   sh->slice_type == B_SLICE)) {
-                av_log(h->avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n",
+                av_log(avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n",
                        sh->slice_type);
                 return AVERROR_INVALIDDATA;
             }
@@ -255,9 +367,11 @@ static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx
         buf += consumed;
     }
     /* didn't find a picture! */
-    av_log(h->avctx, AV_LOG_ERROR, "missing picture in access unit\n");
+    if (!is_global)
+        av_log(h->avctx, AV_LOG_ERROR, "missing picture in access unit\n");
     return -1;
 }
+#endif
 
 static int hevc_parse(AVCodecParserContext *s,
                       AVCodecContext *avctx,
@@ -265,7 +379,13 @@ static int hevc_parse(AVCodecParserContext *s,
                       const uint8_t *buf, int buf_size)
 {
     int next;
-    ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
+    HEVCParserContext *ctx = s->priv_data;
+    ParseContext *pc = &ctx->pc;
+
+    if (avctx->extradata && !ctx->parsed_extradata) {
+        parse_nal_units(s, avctx->extradata, avctx->extradata_size, avctx);
+        ctx->parsed_extradata = 1;
+    }
 
     if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
         next = buf_size;
@@ -278,7 +398,7 @@ static int hevc_parse(AVCodecParserContext *s,
         }
     }
 
-    parse_nal_units(s, avctx, buf, buf_size);
+    parse_nal_units(s, buf, buf_size, avctx);
 
     *poutbuf      = buf;
     *poutbuf_size = buf_size;
@@ -307,49 +427,49 @@ static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
     return 0;
 }
 
-static int hevc_init(AVCodecParserContext *s)
+static void hevc_parser_close(AVCodecParserContext *s)
 {
-    HEVCContext  *h  = &((HEVCParseContext *)s->priv_data)->h;
-    h->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
-    if (!h->HEVClc)
-        return AVERROR(ENOMEM);
-    h->skipped_bytes_pos_size = INT_MAX;
+    HEVCParserContext *ctx = s->priv_data;
+    int i;
 
-    return 0;
-}
+#if ADVANCED_PARSER
+    HEVCContext  *h  = &ctx->h;
 
-static void hevc_close(AVCodecParserContext *s)
-{
-    int i;
-    HEVCContext  *h  = &((HEVCParseContext *)s->priv_data)->h;
-    ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
-    HEVCParamSets *ps = &h->ps;
-    HEVCPacket   *pkt = &h->pkt;
+    for (i = 0; i < FF_ARRAY_ELEMS(h->ps.vps_list); i++)
+        av_buffer_unref(&h->ps.vps_list[i]);
+    for (i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++)
+        av_buffer_unref(&h->ps.sps_list[i]);
+    for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++)
+        av_buffer_unref(&h->ps.pps_list[i]);
+
+    h->ps.sps = NULL;
 
-    av_freep(&h->skipped_bytes_pos);
     av_freep(&h->HEVClc);
-    av_freep(&pc->buffer);
+#endif
 
-    for (i = 0; i < FF_ARRAY_ELEMS(ps->vps_list); i++)
-        av_buffer_unref(&ps->vps_list[i]);
-    for (i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++)
-        av_buffer_unref(&ps->sps_list[i]);
-    for (i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++)
-        av_buffer_unref(&ps->pps_list[i]);
+    for (i = 0; i < FF_ARRAY_ELEMS(ctx->ps.vps_list); i++)
+        av_buffer_unref(&ctx->ps.vps_list[i]);
+    for (i = 0; i < FF_ARRAY_ELEMS(ctx->ps.sps_list); i++)
+        av_buffer_unref(&ctx->ps.sps_list[i]);
+    for (i = 0; i < FF_ARRAY_ELEMS(ctx->ps.pps_list); i++)
+        av_buffer_unref(&ctx->ps.pps_list[i]);
 
-    ps->sps = NULL;
+    ctx->ps.sps = NULL;
+
+    for (i = 0; i < ctx->pkt.nals_allocated; i++) {
+        av_freep(&ctx->pkt.nals[i].rbsp_buffer);
+        av_freep(&ctx->pkt.nals[i].skipped_bytes_pos);
+    }
+    av_freep(&ctx->pkt.nals);
+    ctx->pkt.nals_allocated = 0;
 
-    for (i = 0; i < pkt->nals_allocated; i++)
-        av_freep(&pkt->nals[i].rbsp_buffer);
-    av_freep(&pkt->nals);
-    pkt->nals_allocated = 0;
+    av_freep(&ctx->pc.buffer);
 }
 
 AVCodecParser ff_hevc_parser = {
     .codec_ids      = { AV_CODEC_ID_HEVC },
-    .priv_data_size = sizeof(HEVCParseContext),
-    .parser_init    = hevc_init,
+    .priv_data_size = sizeof(HEVCParserContext),
     .parser_parse   = hevc_parse,
-    .parser_close   = hevc_close,
+    .parser_close   = hevc_parser_close,
     .split          = hevc_split,
 };