From db877e015da92c137a0db3d022fe1226dab2c55f Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Fri, 6 Nov 2015 15:12:51 +0200 Subject: [PATCH] VP9: libgstvaapi: Add VP9 decoder --- gst-libs/gst/vaapi/Makefile.am | 9 + gst-libs/gst/vaapi/gstvaapidecoder_vp9.c | 679 +++++++++++++++++++++++++++++++ gst-libs/gst/vaapi/gstvaapidecoder_vp9.h | 37 ++ 3 files changed, 725 insertions(+) create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_vp9.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_vp9.h diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index c6f845c..107ef2a 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -175,6 +175,13 @@ libgstvaapi_source_h += $(libgstvaapi_hevcdec_source_h) libgstvaapi_source_priv_h += $(libgstvaapi_hevcdec_source_priv_h) endif +libgstvaapi_vp9dec_source_c = gstvaapidecoder_vp9.c +libgstvaapi_vp9dec_source_h = gstvaapidecoder_vp9.h +if USE_VP9_DECODER +libgstvaapi_source_c += $(libgstvaapi_vp9dec_source_c) +libgstvaapi_source_h += $(libgstvaapi_vp9dec_source_h) +endif + libgstvaapi_enc_source_c = \ gstvaapicodedbuffer.c \ gstvaapicodedbufferpool.c \ @@ -594,6 +601,8 @@ EXTRA_DIST += \ $(libgstvaapi_hevcdec_source_c) \ $(libgstvaapi_hevcdec_source_h) \ $(libgstvaapi_hevcdec_source_priv_h) \ + $(libgstvaapi_vp9dec_source_c) \ + $(libgstvaapi_vp9dec_source_h) \ $(libgstvaapi_jpegenc_source_h) \ $(libgstvaapi_jpegenc_source_c) \ $(libgstvaapi_vp8enc_source_h) \ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c new file mode 100644 index 0000000..c3ec964 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c @@ -0,0 +1,679 @@ +/* + * gstvaapidecoder_vp9.c - VP9 decoder + * + * Copyright (C) 2014-2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library 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. + * + * This library 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 this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder_vp9 + * @short_description: VP9 decoder + */ + +#include "sysdeps.h" +#include +#include "gstvaapidecoder_vp9.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiobject_priv.h" + +#include "gstvaapicompat.h" +#ifdef HAVE_VA_VA_DEC_VP9_H +#include +#endif + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GST_VAAPI_DECODER_VP9_CAST(decoder) \ + ((GstVaapiDecoderVp9 *)(decoder)) + +typedef struct _GstVaapiDecoderVp9Private GstVaapiDecoderVp9Private; +typedef struct _GstVaapiDecoderVp9Class GstVaapiDecoderVp9Class; + +struct _GstVaapiDecoderVp9Private +{ + GstVaapiProfile profile; + guint width; + guint height; + GstVp9Parser *parser; + GstVp9FrameHdr frame_hdr; + GstVaapiPicture *current_picture; + GstVaapiPicture *ref_frames[GST_VP9_REF_FRAMES]; /* reference frames in ref_slots[max_ref] */ + + guint num_frames; /* number of frames in a super frame */ + guint frame_sizes[8]; /* size of frames in a super frame */ + guint frame_cnt; /* frame count variable for super frame */ + guint total_idx_size; /* super frame index size (full block size) */ + guint had_superframe_hdr:1; /* indicate the presense of super frame */ + + guint size_changed:1; +}; + +/** + * GstVaapiDecoderVp9: + * + * A decoder based on Vp9. + */ +struct _GstVaapiDecoderVp9 +{ + /*< private > */ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderVp9Private priv; +}; + +/** + * GstVaapiDecoderVp9Class: + * + * A decoder class based on Vp9. + */ +struct _GstVaapiDecoderVp9Class +{ + /*< private > */ + GstVaapiDecoderClass parent_class; +}; + +static GstVaapiDecoderStatus +get_status (GstVp9ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_VP9_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_VP9_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_vp9_close (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + guint i; + + for (i = 0; i < GST_VP9_REF_FRAMES; i++) + gst_vaapi_picture_replace (&priv->ref_frames[i], NULL); + + if (priv->parser) + gst_vp9_parser_free (priv->parser); +} + +static gboolean +gst_vaapi_decoder_vp9_open (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + + gst_vaapi_decoder_vp9_close (decoder); + priv->parser = gst_vp9_parser_new (); + return TRUE; +} + +static void +gst_vaapi_decoder_vp9_destroy (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + + gst_vaapi_decoder_vp9_close (decoder); +} + +static gboolean +gst_vaapi_decoder_vp9_create (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + + if (!gst_vaapi_decoder_vp9_open (decoder)) + return FALSE; + + priv->profile = GST_VAAPI_PROFILE_UNKNOWN; + return TRUE; +} + +static GstVaapiDecoderStatus +ensure_context (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + const GstVaapiProfile profile = GST_VAAPI_PROFILE_VP9; + const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + gboolean reset_context = FALSE; + + if (priv->profile != profile) { + if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder), + profile, entrypoint)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + + priv->profile = profile; + reset_context = TRUE; + } + + if (priv->size_changed) { + GST_DEBUG ("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + GstVaapiContextInfo info; + + info.profile = priv->profile; + info.entrypoint = entrypoint; + info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + info.width = priv->width; + info.height = priv->height; + info.ref_frames = 8; + reset_context = + gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info); + + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +init_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr; + + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + picture->type = + (frame_hdr->frame_type == + GST_VP9_KEY_FRAME) ? GST_VAAPI_PICTURE_TYPE_I : GST_VAAPI_PICTURE_TYPE_P; + picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts; + + if (!frame_hdr->show_frame) + GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); +} + +static void +vaapi_fill_ref_frames (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture, + GstVp9FrameHdr * frame_hdr, VADecPictureParameterBufferVP9 * pic_param) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + guint i; + + if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) { + for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++) + pic_param->reference_frames[i] = picture->surface_id; + + } else { + pic_param->pic_fields.bits.last_ref_frame = + frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_LAST - 1]; + pic_param->pic_fields.bits.last_ref_frame_sign_bias = + frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_LAST - 1]; + + if (frame_hdr->ref_frame_indices[1]) { + pic_param->pic_fields.bits.golden_ref_frame = + frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_GOLDEN - 1]; + pic_param->pic_fields.bits.golden_ref_frame_sign_bias = + frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_GOLDEN - 1]; + pic_param->pic_fields.bits.alt_ref_frame = + frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_ALTREF - 1]; + pic_param->pic_fields.bits.alt_ref_frame_sign_bias = + frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_ALTREF - 1]; + } + } + for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++) { + pic_param->reference_frames[i] = + priv->ref_frames[i] ? priv-> + ref_frames[i]->surface_id : VA_INVALID_SURFACE; + } +} + +static gboolean +fill_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture) +{ + GstVaapiDecoderVp9Private *priv = &decoder->priv; + VADecPictureParameterBufferVP9 *pic_param = picture->param; + GstVp9Parser *parser = priv->parser; + GstVp9FrameHdr *frame_hdr = &priv->frame_hdr; + gint i; + + /* Fill in VAPictureParameterBufferVP9 */ + pic_param->frame_width = priv->width; + pic_param->frame_height = priv->height; + + /* Fill in ReferenceFrames */ + vaapi_fill_ref_frames (decoder, picture, frame_hdr, pic_param); + +#define COPY_FIELD(s, f) \ + pic_param->f = (s)->f +#define COPY_BFM(a, s, f) \ + pic_param->a.bits.f = (s)->f + + COPY_BFM (pic_fields, frame_hdr, subsampling_x); + COPY_BFM (pic_fields, frame_hdr, subsampling_y); + COPY_BFM (pic_fields, frame_hdr, frame_type); + COPY_BFM (pic_fields, frame_hdr, show_frame); + COPY_BFM (pic_fields, frame_hdr, error_resilient_mode); + COPY_BFM (pic_fields, frame_hdr, intra_only); + COPY_BFM (pic_fields, frame_hdr, allow_high_precision_mv); + COPY_BFM (pic_fields, frame_hdr, mcomp_filter_type); + COPY_BFM (pic_fields, frame_hdr, frame_parallel_decoding_mode); + COPY_BFM (pic_fields, frame_hdr, reset_frame_context); + COPY_BFM (pic_fields, frame_hdr, refresh_frame_context); + COPY_BFM (pic_fields, frame_hdr, frame_context_idx); + COPY_BFM (pic_fields, parser, lossless_flag); + + pic_param->pic_fields.bits.segmentation_enabled = + frame_hdr->segmentation.enabled; + pic_param->pic_fields.bits.segmentation_temporal_update = + frame_hdr->segmentation.temporal_update; + pic_param->pic_fields.bits.segmentation_update_map = + frame_hdr->segmentation.update_map; + + COPY_FIELD (&frame_hdr->loopfilter, filter_level); + COPY_FIELD (&frame_hdr->loopfilter, sharpness_level); + COPY_FIELD (frame_hdr, log2_tile_rows); + COPY_FIELD (frame_hdr, log2_tile_columns); + COPY_FIELD (frame_hdr, frame_header_length_in_bytes); + COPY_FIELD (frame_hdr, first_partition_size); + + g_assert (G_N_ELEMENTS (pic_param->mb_segment_tree_probs) == + G_N_ELEMENTS (parser->mb_segment_tree_probs)); + g_assert (G_N_ELEMENTS (pic_param->segment_pred_probs) == + G_N_ELEMENTS (parser->segment_pred_probs)); + + memcpy (pic_param->mb_segment_tree_probs, parser->mb_segment_tree_probs, + sizeof (parser->mb_segment_tree_probs)); + memcpy (pic_param->segment_pred_probs, parser->segment_pred_probs, + sizeof (parser->segment_pred_probs)); + + return TRUE; +} + +static gboolean +fill_slice (GstVaapiDecoderVp9 * decoder, GstVaapiSlice * slice) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9Parser *parser = priv->parser; + VASliceParameterBufferVP9 *const slice_param = slice->param; + GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr; + guint i; + +#define COPY_SEG_FIELD(s, f) \ + seg_param->f = (s)->f + + /* Fill in VASliceParameterBufferVP9 */ + for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) { + VASegmentParameterVP9 *seg_param = &slice_param->seg_param[i]; + GstVp9Segmentation *seg = &parser->segmentation[i]; + + memcpy (seg_param->filter_level, seg->filter_level, + sizeof (seg->filter_level)); + COPY_SEG_FIELD (seg, luma_ac_quant_scale); + COPY_SEG_FIELD (seg, luma_dc_quant_scale); + COPY_SEG_FIELD (seg, chroma_ac_quant_scale); + COPY_SEG_FIELD (seg, chroma_dc_quant_scale); + + seg_param->segment_flags.fields.segment_reference_skipped = + seg->reference_skip; + seg_param->segment_flags.fields.segment_reference_enabled = + seg->reference_frame_enabled; + seg_param->segment_flags.fields.segment_reference = seg->reference_frame; + + } + /* Fixme: When segmentation is disabled, only seg_param[0] has valid values, + * all other entries should be populated with 0 ? */ + + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture, + const guchar * buf, guint buf_size) +{ + GstVaapiSlice *slice; + + slice = GST_VAAPI_SLICE_NEW (VP9, decoder, buf, buf_size); + if (!slice) { + GST_ERROR ("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + if (!fill_slice (decoder, slice)) { + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice)); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +update_ref_frames (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVaapiPicture *picture = priv->current_picture; + GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr; + guint8 refresh_frame_flags, mask, i = 0; + + if (frame_hdr->frame_type == GST_VP9_KEY_FRAME) + refresh_frame_flags = (1 << GST_VP9_REF_FRAMES) - 1; + else + refresh_frame_flags = frame_hdr->refresh_frame_flags; + + for (mask = refresh_frame_flags; mask; mask >>= 1, ++i) { + if (mask & 1) + gst_vaapi_picture_replace (&priv->ref_frames[i], picture); + } +} + +#ifdef GST_VAAPI_PICTURE_NEW +#undef GST_VAAPI_PICTURE_NEW +#endif + +#define GST_VAAPI_PICTURE_NEW(codec, decoder) \ + gst_vaapi_picture_new (GST_VAAPI_DECODER_CAST (decoder), \ + NULL, sizeof (G_PASTE (VADecPictureParameterBuffer, codec))) + +static GstVaapiDecoderStatus +decode_picture (GstVaapiDecoderVp9 * decoder, const guchar * buf, + guint buf_size) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + + status = ensure_context (decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + /* Fixme: handle show_existing_frame */ + + /* Create new picture */ + picture = GST_VAAPI_PICTURE_NEW (VP9, decoder); + if (!picture) { + GST_ERROR ("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_replace (&priv->current_picture, picture); + gst_vaapi_picture_unref (picture); + + init_picture (decoder, picture); + if (!fill_picture (decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + return decode_slice (decoder, picture, buf, buf_size); +} + + +static GstVaapiDecoderStatus +decode_current_picture (GstVaapiDecoderVp9 * decoder) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVaapiPicture *const picture = priv->current_picture; + GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr; + + if (!picture) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (!gst_vaapi_picture_decode (picture)) + goto error; + + update_ref_frames (decoder); + + if (frame_hdr->show_frame) + if (!gst_vaapi_picture_output (picture)) + goto error; + + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_SUCCESS; + +error: + /* XXX: fix for cases where first field failed to be decoded */ + gst_vaapi_picture_replace (&priv->current_picture, NULL); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; +} + +static gboolean +parse_super_frame (const guchar * data, guint data_size, + guint * frame_sizes, guint * frame_count, guint * total_idx_size) +{ + guint8 marker; + guint32 num_frames = 1, frame_size_length, total_index_size; + guint i, j; + + if (data_size <= 0) + return FALSE; + + marker = data[data_size - 1]; + + if ((marker & 0xe0) == 0xc0) { + + GST_DEBUG ("Got VP9-Super Frame, size %d", data_size); + + num_frames = (marker & 0x7) + 1; + frame_size_length = ((marker >> 3) & 0x3) + 1; + total_index_size = 2 + num_frames * frame_size_length; + + if ((data_size >= total_index_size) + && (data[data_size - total_index_size] == marker)) { + const guint8 *x = &data[data_size - total_index_size + 1]; + + for (i = 0; i < num_frames; i++) { + guint32 cur_frame_size = 0; + + for (j = 0; j < frame_size_length; j++) + cur_frame_size |= (*x++) << (j * 8); + + frame_sizes[i] = cur_frame_size; + } + + *frame_count = num_frames; + *total_idx_size = total_index_size; + } else { + GST_ERROR ("Failed to parse Super-frame"); + return FALSE; + } + } else { + *frame_count = num_frames; + frame_sizes[0] = data_size; + *total_idx_size = 0; + } + + return TRUE; +} + +static GstVaapiDecoderStatus +parse_frame_header (GstVaapiDecoderVp9 * decoder, const guchar * buf, + guint buf_size, GstVp9FrameHdr * frame_hdr) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVp9ParserResult result; + + result = gst_vp9_parser_parse_frame_header (priv->parser, frame_hdr, + buf, buf_size); + if (result != GST_VP9_PARSER_OK) + return get_status (result); + + if ((frame_hdr->frame_type == GST_VP9_KEY_FRAME) && + (frame_hdr->width != priv->width || frame_hdr->height != priv->height)) { + priv->width = frame_hdr->width; + priv->height = frame_hdr->height; + priv->size_changed = TRUE; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_parse (GstVaapiDecoder * base_decoder, + GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + guchar *buf; + guint buf_size, flags = 0; + static guint cnt = 0; + + buf_size = gst_adapter_available (adapter); + if (!buf_size) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + buf = (guchar *) gst_adapter_map (adapter, buf_size); + if (!buf) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + if (!priv->had_superframe_hdr) { + if (!parse_super_frame (buf, buf_size, priv->frame_sizes, &priv->num_frames, + &priv->total_idx_size)) + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + + if (priv->num_frames > 1) + priv->had_superframe_hdr = TRUE; + } + + unit->size = priv->frame_sizes[priv->frame_cnt++]; + + if (priv->frame_cnt == priv->num_frames) { + priv->num_frames = 0; + priv->frame_cnt = 0; + priv->had_superframe_hdr = FALSE; + unit->size += priv->total_idx_size; + } + + /* The whole frame is available */ + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; + flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; + +set_flags: + GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_buffer (GstVaapiDecoderVp9 * decoder, const guchar * buf, guint buf_size) +{ + GstVaapiDecoderVp9Private *const priv = &decoder->priv; + GstVaapiDecoderStatus status; + guint size = buf_size; + + if (priv->total_idx_size && !priv->had_superframe_hdr) { + size -= priv->total_idx_size; + priv->total_idx_size = 0; + } + + status = parse_frame_header (decoder, buf, size, &priv->frame_hdr); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + return decode_picture (decoder, buf, size); +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_decode (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * unit) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + GstVaapiDecoderStatus status; + GstBuffer *const buffer = + GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer; + GstMapInfo map_info; + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + GST_ERROR ("failed to map buffer"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + status = decode_buffer (decoder, map_info.data + unit->offset, unit->size); + gst_buffer_unmap (buffer, &map_info); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_start_frame (GstVaapiDecoder * base_decoder, + GstVaapiDecoderUnit * base_unit) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_end_frame (GstVaapiDecoder * base_decoder) +{ + GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder); + + return decode_current_picture (decoder); +} + +static GstVaapiDecoderStatus +gst_vaapi_decoder_vp9_flush (GstVaapiDecoder * base_decoder) +{ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static void +gst_vaapi_decoder_vp9_class_init (GstVaapiDecoderVp9Class * klass) +{ + GstVaapiMiniObjectClass *const object_class = + GST_VAAPI_MINI_OBJECT_CLASS (klass); + GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass); + + object_class->size = sizeof (GstVaapiDecoderVp9); + object_class->finalize = (GDestroyNotify) gst_vaapi_decoder_finalize; + + decoder_class->create = gst_vaapi_decoder_vp9_create; + decoder_class->destroy = gst_vaapi_decoder_vp9_destroy; + decoder_class->parse = gst_vaapi_decoder_vp9_parse; + decoder_class->decode = gst_vaapi_decoder_vp9_decode; + decoder_class->start_frame = gst_vaapi_decoder_vp9_start_frame; + decoder_class->end_frame = gst_vaapi_decoder_vp9_end_frame; + decoder_class->flush = gst_vaapi_decoder_vp9_flush; +} + +static inline const GstVaapiDecoderClass * +gst_vaapi_decoder_vp9_class (void) +{ + static GstVaapiDecoderVp9Class g_class; + static gsize g_class_init = FALSE; + + if (g_once_init_enter (&g_class_init)) { + gst_vaapi_decoder_vp9_class_init (&g_class); + g_once_init_leave (&g_class_init, TRUE); + } + return GST_VAAPI_DECODER_CLASS (&g_class); +} + +/** + * gst_vaapi_decoder_vp9_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for VP9 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_vp9_new (GstVaapiDisplay * display, GstCaps * caps) +{ + return gst_vaapi_decoder_new (gst_vaapi_decoder_vp9_class (), display, caps); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h new file mode 100644 index 0000000..9d28c5e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h @@ -0,0 +1,37 @@ +/* + * gstvaapidecoder_vp9.h - VP9 decoder + * + * Copyright (C) 2015-2016 Intel Corporation + * Author: Sreerenj Balachandran + * + * This library 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. + * + * This library 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 this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_VP9_H +#define GST_VAAPI_DECODER_VP9_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiDecoderVp9 GstVaapiDecoderVp9; + +GstVaapiDecoder * +gst_vaapi_decoder_vp9_new (GstVaapiDisplay * display, GstCaps * caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_VP9_H */ -- 2.7.4