hevc_parser: parse and export some stream parameters
authorAnton Khirnov <anton@khirnov.net>
Thu, 9 Jul 2015 17:34:51 +0000 (19:34 +0200)
committerAnton Khirnov <anton@khirnov.net>
Sun, 12 Jul 2015 16:15:40 +0000 (18:15 +0200)
Particularly those that will be needed by the QSV decoder.
More can be added later as necessary.

configure
libavcodec/Makefile
libavcodec/hevc_parser.c

index 9aa5135..28115d3 100755 (executable)
--- a/configure
+++ b/configure
@@ -2057,6 +2057,7 @@ wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel"
 
 # parsers
 h264_parser_select="h264_decoder"
+hevc_parser_select="golomb"
 mpegvideo_parser_select="mpegvideo"
 mpeg4video_parser_select="error_resilience h263dsp mpeg_er mpegvideo qpeldsp"
 vc1_parser_select="mpegvideo startcode vc1_decoder"
index 61024d0..2cb5368 100644 (file)
@@ -697,7 +697,7 @@ OBJS-$(CONFIG_GSM_PARSER)              += gsm_parser.o
 OBJS-$(CONFIG_H261_PARSER)             += h261_parser.o
 OBJS-$(CONFIG_H263_PARSER)             += h263_parser.o
 OBJS-$(CONFIG_H264_PARSER)             += h264_parser.o
-OBJS-$(CONFIG_HEVC_PARSER)             += hevc_parser.o
+OBJS-$(CONFIG_HEVC_PARSER)             += hevc_parser.o hevc_parse.o
 OBJS-$(CONFIG_MJPEG_PARSER)            += mjpeg_parser.o
 OBJS-$(CONFIG_MLP_PARSER)              += mlp_parser.o mlp.o
 OBJS-$(CONFIG_MPEG4VIDEO_PARSER)       += mpeg4video_parser.o h263.o \
index ac2c6f5..030163e 100644 (file)
 
 #include "libavutil/common.h"
 
-#include "parser.h"
+#include "golomb.h"
 #include "hevc.h"
+#include "parser.h"
 
 #define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
 
+#define IS_IRAP_NAL(nal) (nal->type >= 16 && nal->type <= 23)
+
+typedef struct HEVCParserContext {
+    ParseContext pc;
+
+    HEVCPacket pkt;
+    HEVCParamSets ps;
+
+    int parsed_extradata;
+} HEVCParserContext;
+
+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(&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: hevc_parse_slice_header(s, nal, avctx); break;
+        }
+    }
+
+    return 0;
+}
+
 /**
  * Find the end of the current frame in the bitstream.
  * @return the position of the first byte of the next frame, or END_NOT_FOUND
 static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
                                int buf_size)
 {
+    HEVCParserContext *ctx = s->priv_data;
+    ParseContext       *pc = &ctx->pc;
     int i;
-    ParseContext *pc = s->priv_data;
 
     for (i = 0; i < buf_size; i++) {
         int nut;
@@ -76,7 +165,14 @@ static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
                       const uint8_t *buf, int buf_size)
 {
     int next;
-    ParseContext *pc = s->priv_data;
+
+    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;
@@ -89,6 +185,8 @@ static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
         }
     }
 
+    parse_nal_units(s, buf, buf_size, avctx);
+
     *poutbuf      = buf;
     *poutbuf_size = buf_size;
     return next;
@@ -116,10 +214,30 @@ static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
     return 0;
 }
 
+static void hevc_parser_close(AVCodecParserContext *s)
+{
+    HEVCParserContext *ctx = s->priv_data;
+    int 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]);
+
+    for (i = 0; i < ctx->pkt.nals_allocated; i++)
+        av_freep(&ctx->pkt.nals[i].rbsp_buffer);
+    av_freep(&ctx->pkt.nals);
+    ctx->pkt.nals_allocated = 0;
+
+    av_freep(&ctx->pc.buffer);
+}
+
 AVCodecParser ff_hevc_parser = {
     .codec_ids      = { AV_CODEC_ID_HEVC },
-    .priv_data_size = sizeof(ParseContext),
+    .priv_data_size = sizeof(HEVCParserContext),
     .parser_parse   = hevc_parse,
-    .parser_close   = ff_parse_close,
+    .parser_close   = hevc_parser_close,
     .split          = hevc_split,
 };