Add initial VP8 decoder.
authorZhao, Halley <halley.zhao@intel.com>
Thu, 26 Dec 2013 23:18:24 +0000 (07:18 +0800)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Fri, 18 Apr 2014 18:03:44 +0000 (20:03 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=722761

[complete overhaul, fixed support for resolution changes]
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
13 files changed:
configure.ac
ext/Makefile.am
gst-libs/gst/codecparsers/Makefile.am
gst-libs/gst/vaapi/Makefile.am
gst-libs/gst/vaapi/gstvaapicodec_objects.c
gst-libs/gst/vaapi/gstvaapicodec_objects.h
gst-libs/gst/vaapi/gstvaapidecoder_objects.c
gst-libs/gst/vaapi/gstvaapidecoder_objects.h
gst-libs/gst/vaapi/gstvaapidecoder_vp8.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapidecoder_vp8.h [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapiprofile.c
gst-libs/gst/vaapi/gstvaapiprofile.h
gst/vaapi/gstvaapidecode.c

index bb194aa..52d268d 100644 (file)
@@ -335,6 +335,7 @@ if test "$enable_builtin_codecparsers" = "yes"; then
     ac_cv_have_gst_mpeg2_parser="no"
     ac_cv_have_gst_h264_parser="no"
     ac_cv_have_gst_jpeg_parser="no"
+    ac_cv_have_gst_vp8_parser="no"
 else
 PKG_CHECK_MODULES([GST_CODEC_PARSERS],
     [gstreamer-codecparsers-$GST_PKG_VERSION >= $GST_PLUGINS_BAD_VERSION_REQUIRED])
@@ -413,6 +414,26 @@ AC_CACHE_CHECK([for JPEG parser],
 AM_CONDITIONAL([USE_LOCAL_CODEC_PARSERS_JPEG],
     [test "$ac_cv_have_gst_jpeg_parser" != "yes"])
 
+dnl ... VP8 parser, not upstream yet
+AC_CACHE_CHECK([for VP8 parser],
+    ac_cv_have_gst_vp8_parser, [
+    saved_CPPFLAGS="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS $GST_CFLAGS $GST_CODEC_PARSERS_CFLAGS"
+    saved_LIBS="$LIBS"
+    LIBS="$LIBS $GST_LIBS $GST_CODEC_PARSERS_LIBS"
+    AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM(
+            [[#include <gst/codecparsers/gstvp8parser.h>]],
+            [[GstVp8FrameHdr frame_hdr;]])],
+        [ac_cv_have_gst_vp8_parser="yes"],
+        [ac_cv_have_gst_vp8_parser="no"]
+    )
+    CPPFLAGS="$saved_CPPFLAGS"
+    LIBS="$saved_LIBS"
+])
+AM_CONDITIONAL([USE_LOCAL_CODEC_PARSERS_VP8],
+    [test "$ac_cv_have_gst_vp8_parser" != "yes"])
+
 case $GST_API_VERSION in
 0.10)   lt_bias=gst0_vaapi_lt_current_bias;;
 1.0)    lt_bias=gst1_vaapi_lt_current_bias;;
@@ -665,6 +686,31 @@ AC_CACHE_CHECK([for JPEG decoding API],
     LIBS="$saved_LIBS"
 ])
 
+dnl Check for VP8 decoding API (0.34+)
+USE_VP8_DECODER=0
+AC_CACHE_CHECK([for VP8 decoding API],
+    ac_cv_have_vp8_decoding_api, [
+    saved_CPPFLAGS="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS $LIBVA_CFLAGS"
+    saved_LIBS="$LIBS"
+    LIBS="$LIBS $LIBVA_LIBS"
+    AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM(
+            [[#include <va/va.h>
+              #include <va/va_dec_vp8.h>
+            ]],
+            [[VAPictureParameterBufferVP8 pic_param;
+              VASliceParameterBufferVP8 slice_param;
+              VAProbabilityDataBufferVP8 prob_data;
+              VAIQMatrixBufferVP8 iq_matrix;]])],
+        [ac_cv_have_vp8_decoding_api="yes" USE_VP8_DECODER=1],
+        [ac_cv_have_vp8_decoding_api="no"]
+    )
+    CPPFLAGS="$saved_CPPFLAGS"
+    LIBS="$saved_LIBS"
+])
+
+
 dnl Check for vpp (video post-processing) support
 USE_VA_VPP=0
 AC_CACHE_CHECK([for video post-postprocessing API],
@@ -737,6 +783,10 @@ AC_DEFINE_UNQUOTED(USE_JPEG_DECODER, $USE_JPEG_DECODER,
     [Defined to 1 if JPEG decoder is used])
 AM_CONDITIONAL(USE_JPEG_DECODER, test $USE_JPEG_DECODER -eq 1)
 
+AC_DEFINE_UNQUOTED(USE_VP8_DECODER, $USE_VP8_DECODER,
+    [Defined to 1 if JPEG decoder is used])
+AM_CONDITIONAL(USE_VP8_DECODER, test $USE_VP8_DECODER -eq 1)
+
 AC_DEFINE_UNQUOTED(USE_DRM, $USE_DRM,
     [Defined to 1 if DRM is enabled])
 AM_CONDITIONAL(USE_DRM, test $USE_DRM -eq 1)
index cfb2bc0..62f3ec4 100644 (file)
@@ -9,6 +9,7 @@ codecparsers_source_c = \
        gstmpeg4parser.c        \
        gstmpegvideoparser.c    \
        gstvc1parser.c          \
+       gstvp8parser.c          \
        parserutils.c           \
        $(NULL)
 
@@ -20,6 +21,7 @@ codecparsers_source_h = \
        gstmpeg4parser.h        \
        gstmpegvideoparser.h    \
        gstvc1parser.h          \
+       gstvp8parser.h          \
        parserutils.h           \
        $(NULL)
 
index 1da2217..3d414d9 100644 (file)
@@ -40,6 +40,14 @@ gen_source_c += gsth264parser.c
 gen_source_h += gsth264parser.h
 endif
 
+if USE_LOCAL_CODEC_PARSERS_VP8
+gen_source_c += gstvp8parser.c
+gen_source_h += gstvp8parser.h gstvp8rangedecoder.h vp8utils.h
+
+gen_source_c += dboolhuff.c gstvp8rangedecoder.c vp8utils.c
+gen_source_h += dboolhuff.h
+endif
+
 GENFILES = \
        $(gen_source_c)                         \
        $(gen_source_h)                         \
index 4d61713..402fff2 100644 (file)
@@ -56,6 +56,7 @@ libgstvaapi_source_c =                                \
        gstvaapidecoder_objects.c               \
        gstvaapidecoder_unit.c                  \
        gstvaapidecoder_vc1.c                   \
+       gstvaapidecoder_vp8.c                   \
        gstvaapidisplay.c                       \
        gstvaapidisplaycache.c                  \
        gstvaapifilter.c                        \
@@ -86,6 +87,7 @@ libgstvaapi_source_h =                                \
        gstvaapidecoder_mpeg2.h                 \
        gstvaapidecoder_mpeg4.h                 \
        gstvaapidecoder_vc1.h                   \
+       gstvaapidecoder_vp8.h                   \
        gstvaapidisplay.h                       \
        gstvaapifilter.h                        \
        gstvaapiimage.h                         \
index d72c176..edf4b35 100644 (file)
@@ -212,3 +212,39 @@ gst_vaapi_huffman_table_new (GstVaapiDecoder * decoder,
   return GST_VAAPI_HUFFMAN_TABLE_CAST (object);
 }
 #endif
+#if USE_VP8_DECODER
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiProbabilityTable,
+    gst_vaapi_probability_table);
+
+void
+gst_vaapi_probability_table_destroy (GstVaapiProbabilityTable * prob_table)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (prob_table), &prob_table->param_id);
+  prob_table->param = NULL;
+}
+
+gboolean
+gst_vaapi_probability_table_create (GstVaapiProbabilityTable * prob_table,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  prob_table->param_id = VA_INVALID_ID;
+  return vaapi_create_buffer (GET_VA_DISPLAY (prob_table),
+      GET_VA_CONTEXT (prob_table),
+      VAProbabilityBufferType,
+      args->param_size, args->param, &prob_table->param_id, &prob_table->param);
+}
+
+GstVaapiProbabilityTable *
+gst_vaapi_probability_table_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiProbabilityTableClass,
+      GST_VAAPI_CODEC_BASE (decoder), param, param_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_PROBABILITY_TABLE_CAST (object);
+}
+
+#endif
index c7b7902..163ebf7 100644 (file)
@@ -27,6 +27,9 @@
 
 #include <gst/vaapi/gstvaapiminiobject.h>
 #include <gst/vaapi/gstvaapidecoder.h>
+#if USE_VP8_DECODER
+#include <va/va_dec_vp8.h>
+#endif
 
 G_BEGIN_DECLS
 
@@ -36,6 +39,7 @@ typedef struct _GstVaapiCodecObjectClass        GstVaapiCodecObjectClass;
 typedef struct _GstVaapiIqMatrix                GstVaapiIqMatrix;
 typedef struct _GstVaapiBitPlane                GstVaapiBitPlane;
 typedef struct _GstVaapiHuffmanTable            GstVaapiHuffmanTable;
+typedef struct _GstVaapiProbabilityTable        GstVaapiProbabilityTable;
 
 /* ------------------------------------------------------------------------- */
 /* --- Base Codec Object                                                 --- */
@@ -196,6 +200,33 @@ gst_vaapi_huffman_table_new (GstVaapiDecoder * decoder, guint8 * data,
     guint data_size);
 
 /* ------------------------------------------------------------------------- */
+/* ---                   Probability (Update) Table                      --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_PROBABILITY_TABLE_CAST(obj) \
+    ((GstVaapiProbabilityTable *)(obj))
+
+/**
+ * GstVaapiProbabilityTable:
+ *
+ * A #GstVaapiCodecObject holding an Probability (Update) Table for RAC decoding
+ */
+struct _GstVaapiProbabilityTable
+{
+  /*< private > */
+  GstVaapiCodecObject parent_instance;
+  VABufferID param_id;
+
+  /*< public > */
+  gpointer param;
+};
+
+G_GNUC_INTERNAL
+GstVaapiProbabilityTable *
+gst_vaapi_probability_table_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size);
+
+/* ------------------------------------------------------------------------- */
 /* --- Helpers to create codec-dependent objects                         --- */
 /* ------------------------------------------------------------------------- */
 
@@ -230,6 +261,10 @@ static const GstVaapiCodecObjectClass G_PASTE (type, Class) = {         \
   gst_vaapi_huffman_table_new (GST_VAAPI_DECODER_CAST (decoder),        \
       NULL, sizeof (G_PASTE (VAHuffmanTableBuffer, codec)))
 
+#define GST_VAAPI_PROBABILITY_TABLE_NEW(codec, decoder)                 \
+  gst_vaapi_probability_table_new (GST_VAAPI_DECODER_CAST (decoder),    \
+      NULL, sizeof (G_PASTE (VAProbabilityDataBuffer, codec)))
+
 G_END_DECLS
 
 #endif /* GST_VAAPI_CODEC_OBJECTS_H */
index f3fb782..5f8c0f0 100644 (file)
@@ -71,6 +71,7 @@ gst_vaapi_picture_destroy (GstVaapiPicture * picture)
   gst_vaapi_codec_object_replace (&picture->iq_matrix, NULL);
   gst_vaapi_codec_object_replace (&picture->huf_table, NULL);
   gst_vaapi_codec_object_replace (&picture->bitplane, NULL);
+  gst_vaapi_codec_object_replace (&picture->prob_table, NULL);
 
   if (picture->proxy) {
     gst_vaapi_surface_proxy_unref (picture->proxy);
@@ -223,6 +224,7 @@ gst_vaapi_picture_decode (GstVaapiPicture * picture)
   GstVaapiIqMatrix *iq_matrix;
   GstVaapiBitPlane *bitplane;
   GstVaapiHuffmanTable *huf_table;
+  GstVaapiProbabilityTable *prob_table;
   VADisplay va_display;
   VAContextID va_context;
   VAStatus status;
@@ -257,6 +259,11 @@ gst_vaapi_picture_decode (GstVaapiPicture * picture)
           &huf_table->param_id, (void **) &huf_table->param))
     return FALSE;
 
+  prob_table = picture->prob_table;
+  if (prob_table && !do_decode (va_display, va_context,
+          &prob_table->param_id, (void **) &prob_table->param))
+    return FALSE;
+
   for (i = 0; i < picture->slices->len; i++) {
     GstVaapiSlice *const slice = g_ptr_array_index (picture->slices, i);
     VABufferID va_buffers[2];
index 91e7321..5a36f63 100644 (file)
@@ -134,6 +134,7 @@ struct _GstVaapiPicture
   GstVaapiIqMatrix *iq_matrix;
   GstVaapiHuffmanTable *huf_table;
   GstVaapiBitPlane *bitplane;
+  GstVaapiProbabilityTable *prob_table;
   GstClockTime pts;
   gint32 poc;
   guint structure;
diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c b/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c
new file mode 100644 (file)
index 0000000..40bf4db
--- /dev/null
@@ -0,0 +1,664 @@
+/*
+ *  gstvaapidecoder_vp8.c - VP8 decoder
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Halley Zhao <halley.zhao@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  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_vp8
+ * @short_description: VP8 decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gstvp8parser.h>
+#include "gstvaapidecoder_vp8.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiobject_priv.h"
+
+#include "gstvaapicompat.h"
+#include <va/va_dec_vp8.h>
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DECODER_VP8_CAST(decoder) \
+  ((GstVaapiDecoderVp8 *)(decoder))
+
+typedef struct _GstVaapiDecoderVp8Private GstVaapiDecoderVp8Private;
+typedef struct _GstVaapiDecoderVp8Class GstVaapiDecoderVp8Class;
+
+struct _GstVaapiDecoderVp8Private
+{
+  GstVaapiProfile profile;
+  guint width;
+  guint height;
+  GstVp8Parser parser;
+  GstVp8FrameHdr frame_hdr;
+  GstVaapiPicture *last_picture;
+  GstVaapiPicture *golden_ref_picture;
+  GstVaapiPicture *alt_ref_picture;
+  GstVaapiPicture *current_picture;
+  GstClockTime pts;
+  guint size_changed:1;
+};
+
+/**
+ * GstVaapiDecoderVp8:
+ *
+ * A decoder based on Vp8.
+ */
+struct _GstVaapiDecoderVp8
+{
+  /*< private >*/
+  GstVaapiDecoder parent_instance;
+
+  GstVaapiDecoderVp8Private priv;
+};
+
+/**
+ * GstVaapiDecoderVp8Class:
+ *
+ * A decoder class based on Vp8.
+ */
+struct _GstVaapiDecoderVp8Class
+{
+  /*< private >*/
+  GstVaapiDecoderClass parent_class;
+};
+
+static GstVaapiDecoderStatus
+get_status (GstVp8ParserResult result)
+{
+  GstVaapiDecoderStatus status;
+
+  switch (result) {
+    case GST_VP8_PARSER_OK:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    case GST_VP8_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_vp8_close (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->last_picture, NULL);
+  gst_vaapi_picture_replace (&priv->golden_ref_picture, NULL);
+  gst_vaapi_picture_replace (&priv->alt_ref_picture, NULL);
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+}
+
+static gboolean
+gst_vaapi_decoder_vp8_open (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_vp8_close (decoder);
+  gst_vp8_parser_init (&priv->parser);
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_vp8_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+
+  gst_vaapi_decoder_vp8_close (decoder);
+}
+
+static gboolean
+gst_vaapi_decoder_vp8_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+
+  if (!gst_vaapi_decoder_vp8_open (decoder))
+    return FALSE;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->pts = GST_CLOCK_TIME_NONE;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  const GstVaapiProfile profile = GST_VAAPI_PROFILE_VP8;
+  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.width = priv->width;
+    info.height = priv->height;
+    info.ref_frames = 3;
+    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 GstVaapiDecoderStatus
+ensure_quant_matrix (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVp8Segmentation *const seg = &priv->parser.segmentation;
+  VAIQMatrixBufferVP8 *iq_matrix;
+  const gint8 QI_MAX = 127;
+  gint8 qi, qi_base;
+  gint i;
+
+  picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (VP8, decoder);
+  if (!picture->iq_matrix) {
+    GST_ERROR ("failed to allocate IQ matrix");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  iq_matrix = picture->iq_matrix->param;
+
+  /* Fill in VAIQMatrixBufferVP8 */
+  for (i = 0; i < 4; i++) {
+    if (seg->segmentation_enabled) {
+      qi_base = seg->quantizer_update_value[i];
+      if (!seg->segment_feature_mode)   // 0 means delta update
+        qi_base += frame_hdr->quant_indices.y_ac_qi;
+    } else
+      qi_base = frame_hdr->quant_indices.y_ac_qi;
+
+    qi = qi_base;
+    iq_matrix->quantization_index[i][0] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.y_dc_delta;
+    iq_matrix->quantization_index[i][1] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.y2_dc_delta;
+    iq_matrix->quantization_index[i][2] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.y2_ac_delta;
+    iq_matrix->quantization_index[i][3] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.uv_dc_delta;
+    iq_matrix->quantization_index[i][4] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.uv_ac_delta;
+    iq_matrix->quantization_index[i][5] = CLAMP (qi, 0, QI_MAX);
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+ensure_probability_table (GstVaapiDecoderVp8 * decoder,
+    GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  VAProbabilityDataBufferVP8 *prob_table;
+
+  picture->prob_table = GST_VAAPI_PROBABILITY_TABLE_NEW (VP8, decoder);
+  if (!picture->prob_table) {
+    GST_ERROR ("failed to allocate probality table");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  prob_table = picture->prob_table->param;
+
+  /* Fill in VAProbabilityDataBufferVP8 */
+  memcpy (prob_table->dct_coeff_probs, frame_hdr->token_probs.prob,
+      sizeof (frame_hdr->token_probs.prob));
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+init_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  picture->type = frame_hdr->key_frame ? GST_VAAPI_PICTURE_TYPE_I :
+      GST_VAAPI_PICTURE_TYPE_P;
+  picture->pts = priv->pts;
+
+  if (!frame_hdr->show_frame)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  VAPictureParameterBufferVP8 *const pic_param = picture->param;
+  GstVp8Parser *const parser = &priv->parser;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVp8Segmentation *const seg = &parser->segmentation;
+  gint i;
+
+  /* Fill in VAPictureParameterBufferVP8 */
+  pic_param->frame_width = priv->width;
+  pic_param->frame_height = priv->height;
+
+  pic_param->last_ref_frame = VA_INVALID_SURFACE;
+  pic_param->golden_ref_frame = VA_INVALID_SURFACE;
+  pic_param->alt_ref_frame = VA_INVALID_SURFACE;
+  if (!frame_hdr->key_frame) {
+    if (priv->last_picture)
+      pic_param->last_ref_frame = priv->last_picture->surface_id;
+    if (priv->golden_ref_picture)
+      pic_param->golden_ref_frame = priv->golden_ref_picture->surface_id;
+    if (priv->alt_ref_picture)
+      pic_param->alt_ref_frame = priv->alt_ref_picture->surface_id;
+  }
+  pic_param->out_of_loop_frame = VA_INVALID_SURFACE;    // not used currently
+
+  pic_param->pic_fields.value = 0;
+  pic_param->pic_fields.bits.key_frame = !frame_hdr->key_frame;
+  pic_param->pic_fields.bits.version = frame_hdr->version;
+  pic_param->pic_fields.bits.segmentation_enabled = seg->segmentation_enabled;
+  pic_param->pic_fields.bits.update_mb_segmentation_map =
+      seg->update_mb_segmentation_map;
+  pic_param->pic_fields.bits.update_segment_feature_data =
+      seg->update_segment_feature_data;
+  pic_param->pic_fields.bits.filter_type = frame_hdr->filter_type;
+  pic_param->pic_fields.bits.sharpness_level = frame_hdr->sharpness_level;
+  pic_param->pic_fields.bits.loop_filter_adj_enable =
+      parser->mb_lf_adjust.loop_filter_adj_enable;
+  pic_param->pic_fields.bits.mode_ref_lf_delta_update =
+      parser->mb_lf_adjust.mode_ref_lf_delta_update;
+  pic_param->pic_fields.bits.sign_bias_golden = frame_hdr->sign_bias_golden;
+  pic_param->pic_fields.bits.sign_bias_alternate =
+      frame_hdr->sign_bias_alternate;
+  pic_param->pic_fields.bits.mb_no_coeff_skip = frame_hdr->mb_no_skip_coeff;
+
+  for (i = 0; i < 3; i++)
+    pic_param->mb_segment_tree_probs[i] = seg->segment_prob[i];
+
+  for (i = 0; i < 4; i++) {
+    if (seg->segmentation_enabled) {
+      pic_param->loop_filter_level[i] = seg->lf_update_value[i];
+      if (!seg->segment_feature_mode)
+        pic_param->loop_filter_level[i] += frame_hdr->loop_filter_level;
+    } else
+      pic_param->loop_filter_level[i] = frame_hdr->loop_filter_level;
+
+    pic_param->loop_filter_deltas_ref_frame[i] =
+        parser->mb_lf_adjust.ref_frame_delta[i];
+    pic_param->loop_filter_deltas_mode[i] =
+        parser->mb_lf_adjust.mb_mode_delta[i];
+  }
+  if ((pic_param->pic_fields.bits.version == 0)
+      || (pic_param->pic_fields.bits.version == 1)) {
+    pic_param->pic_fields.bits.loop_filter_disable =
+        pic_param->loop_filter_level[0] == 0;
+  }
+
+  pic_param->prob_skip_false = frame_hdr->prob_skip_false;
+  pic_param->prob_intra = frame_hdr->prob_intra;
+  pic_param->prob_last = frame_hdr->prob_last;
+  pic_param->prob_gf = frame_hdr->prob_gf;
+
+  memcpy (pic_param->y_mode_probs, frame_hdr->mode_probs.y_prob,
+      sizeof (frame_hdr->mode_probs.y_prob));
+  memcpy (pic_param->uv_mode_probs, frame_hdr->mode_probs.uv_prob,
+      sizeof (frame_hdr->mode_probs.uv_prob));
+  memcpy (pic_param->mv_probs, frame_hdr->mv_probs.prob,
+      sizeof (frame_hdr->mv_probs));
+
+  pic_param->bool_coder_ctx.range = frame_hdr->rd_range;
+  pic_param->bool_coder_ctx.value = frame_hdr->rd_value;
+  pic_param->bool_coder_ctx.count = frame_hdr->rd_count;
+
+  return TRUE;
+}
+
+static gboolean
+fill_slice (GstVaapiDecoderVp8 * decoder, GstVaapiSlice * slice)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  VASliceParameterBufferVP8 *const slice_param = slice->param;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  gint i;
+
+  /* Fill in VASliceParameterBufferVP8 */
+  slice_param->slice_data_offset = frame_hdr->data_chunk_size;
+  slice_param->macroblock_offset = frame_hdr->header_size;
+  slice_param->num_of_partitions =
+      (1 << frame_hdr->log2_nbr_of_dct_partitions) + 1;
+
+  slice_param->partition_size[0] =
+      frame_hdr->first_part_size - ((slice_param->macroblock_offset + 7) >> 3);
+  for (i = 1; i < slice_param->num_of_partitions; i++)
+    slice_param->partition_size[i] = frame_hdr->partition_size[i - 1];
+  for (; i < G_N_ELEMENTS (slice_param->partition_size); i++)
+    slice_param->partition_size[i] = 0;
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture,
+    const guchar * buf, guint buf_size)
+{
+  GstVaapiSlice *slice;
+
+  slice = GST_VAAPI_SLICE_NEW (VP8, 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 GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderVp8 * decoder, const guchar * buf,
+    guint buf_size)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiPicture *picture;
+  GstVaapiDecoderStatus status;
+
+  status = ensure_context (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  /* Create new picture */
+  picture = GST_VAAPI_PICTURE_NEW (VP8, 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);
+
+  status = ensure_quant_matrix (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  status = ensure_probability_table (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  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 void
+update_ref_frames (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiPicture *picture = priv->current_picture;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  // update picture reference
+  if (frame_hdr->key_frame) {
+    gst_vaapi_picture_replace (&priv->golden_ref_picture, picture);
+    gst_vaapi_picture_replace (&priv->alt_ref_picture, picture);
+  } else {
+    // process refresh_alternate_frame/copy_buffer_to_alternate first
+    if (frame_hdr->refresh_alternate_frame) {
+      gst_vaapi_picture_replace (&priv->alt_ref_picture, picture);
+    } else {
+      switch (frame_hdr->copy_buffer_to_alternate) {
+        case 0:
+          // do nothing
+          break;
+        case 1:
+          gst_vaapi_picture_replace (&priv->alt_ref_picture,
+              priv->last_picture);
+          break;
+        case 2:
+          gst_vaapi_picture_replace (&priv->alt_ref_picture,
+              priv->golden_ref_picture);
+          break;
+        default:
+          GST_WARNING
+              ("WARNING: VP8 decoder: unrecognized copy_buffer_to_alternate");
+      }
+    }
+
+    if (frame_hdr->refresh_golden_frame) {
+      gst_vaapi_picture_replace (&priv->golden_ref_picture, picture);
+    } else {
+      switch (frame_hdr->copy_buffer_to_golden) {
+        case 0:
+          // do nothing
+          break;
+        case 1:
+          gst_vaapi_picture_replace (&priv->golden_ref_picture,
+              priv->last_picture);
+          break;
+        case 2:
+          gst_vaapi_picture_replace (&priv->golden_ref_picture,
+              priv->alt_ref_picture);
+          break;
+        default:
+          GST_WARNING
+              ("WARNING: VP8 decoder: unrecognized copy_buffer_to_golden");
+      }
+    }
+  }
+  if (frame_hdr->key_frame || frame_hdr->refresh_last)
+    gst_vaapi_picture_replace (&priv->last_picture, picture);
+}
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  update_ref_frames (decoder);
+  if (!gst_vaapi_picture_decode (picture))
+    goto error;
+  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 GstVaapiDecoderStatus
+parse_frame_header (GstVaapiDecoderVp8 * decoder, const guchar * buf,
+    guint buf_size, GstVp8FrameHdr * frame_hdr)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8ParserResult result;
+
+  memset (frame_hdr, 0, sizeof (*frame_hdr));
+  result = gst_vp8_parser_parse_frame_header (&priv->parser, frame_hdr,
+      buf, buf_size);
+  if (result != GST_VP8_PARSER_OK)
+    return get_status (result);
+
+  if (frame_hdr->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_vp8_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  guint flags = 0;
+
+  priv->pts = gst_adapter_prev_pts (adapter, NULL);
+  unit->size = gst_adapter_available (adapter);
+
+  /* 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;
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+}
+
+static GstVaapiDecoderStatus
+decode_buffer (GstVaapiDecoderVp8 * decoder, const guchar * buf, guint buf_size)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  status = parse_frame_header (decoder, buf, buf_size, &priv->frame_hdr);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  return decode_picture (decoder, buf, buf_size);
+}
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_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_vp8_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * base_unit)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_flush (GstVaapiDecoder * base_decoder)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_vp8_class_init (GstVaapiDecoderVp8Class * klass)
+{
+  GstVaapiMiniObjectClass *const object_class =
+      GST_VAAPI_MINI_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->size = sizeof (GstVaapiDecoderVp8);
+  object_class->finalize = (GDestroyNotify) gst_vaapi_decoder_finalize;
+
+  decoder_class->create = gst_vaapi_decoder_vp8_create;
+  decoder_class->destroy = gst_vaapi_decoder_vp8_destroy;
+  decoder_class->parse = gst_vaapi_decoder_vp8_parse;
+  decoder_class->decode = gst_vaapi_decoder_vp8_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_vp8_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_vp8_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_vp8_flush;
+}
+
+static inline const GstVaapiDecoderClass *
+gst_vaapi_decoder_vp8_class (void)
+{
+  static GstVaapiDecoderVp8Class g_class;
+  static gsize g_class_init = FALSE;
+
+  if (g_once_init_enter (&g_class_init)) {
+    gst_vaapi_decoder_vp8_class_init (&g_class);
+    g_once_init_leave (&g_class_init, TRUE);
+  }
+  return GST_VAAPI_DECODER_CLASS (&g_class);
+}
+
+/**
+ * gst_vaapi_decoder_vp8_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for VP8 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_vp8_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return gst_vaapi_decoder_new (gst_vaapi_decoder_vp8_class (), display, caps);
+}
diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h b/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h
new file mode 100644 (file)
index 0000000..43a88fd
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  gstvaapidecoder_vp8.h - VP8 decoder
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Halley Zhao <halley.zhao@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  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_VP8_H
+#define GST_VAAPI_DECODER_VP8_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiDecoderVp8              GstVaapiDecoderVp8;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_vp8_new (GstVaapiDisplay * display, GstCaps * caps);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_VP8_H */
index ad3441a..76e5d0e 100644 (file)
@@ -65,6 +65,7 @@ static const GstVaapiCodecMap gst_vaapi_codecs[] = {
     { GST_VAAPI_CODEC_WMV3,     "wmv3"  },
     { GST_VAAPI_CODEC_VC1,      "vc1"   },
     { GST_VAAPI_CODEC_JPEG,     "jpeg"  },
+    { GST_VAAPI_CODEC_VP8,      "vp8"   },
     { 0, }
 };
 
@@ -125,6 +126,8 @@ static const GstVaapiProfileMap gst_vaapi_profiles[] = {
       "image/jpeg", "baseline"
     },
 #endif
+    {GST_VAAPI_PROFILE_VP8, VAProfileVP8Version0_3,
+      "video/x-vp8", "Version0_3"},
     { 0, }
 };
 
index be74a0a..24dde89 100644 (file)
@@ -51,6 +51,7 @@ typedef enum {
     GST_VAAPI_CODEC_WMV3        = GST_MAKE_FOURCC('W','M','V',0),
     GST_VAAPI_CODEC_VC1         = GST_MAKE_FOURCC('V','C','1',0),
     GST_VAAPI_CODEC_JPEG        = GST_MAKE_FOURCC('J','P','G',0),
+    GST_VAAPI_CODEC_VP8         = GST_MAKE_FOURCC('V','P','8',0),
 } GstVaapiCodec;
 
 /**
@@ -151,6 +152,7 @@ typedef enum {
     GST_VAAPI_PROFILE_VC1_MAIN              = GST_VAAPI_MAKE_PROFILE(VC1,2),
     GST_VAAPI_PROFILE_VC1_ADVANCED          = GST_VAAPI_MAKE_PROFILE(VC1,3),
     GST_VAAPI_PROFILE_JPEG_BASELINE         = GST_VAAPI_MAKE_PROFILE(JPEG,1),
+    GST_VAAPI_PROFILE_VP8                   = GST_VAAPI_MAKE_PROFILE(VP8,1),
 } GstVaapiProfile;
 
 /**
index 98d7916..9b57480 100644 (file)
@@ -49,6 +49,7 @@
 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
 #include <gst/vaapi/gstvaapidecoder_vc1.h>
+#include <gst/vaapi/gstvaapidecoder_vp8.h>
 
 #define GST_PLUGIN_NAME "vaapidecode"
 #define GST_PLUGIN_DESC "A VA-API based video decoder"
@@ -67,6 +68,7 @@ static const char gst_vaapidecode_sink_caps_str[] =
     GST_CAPS_CODEC("video/x-h263")
     GST_CAPS_CODEC("video/x-h264")
     GST_CAPS_CODEC("video/x-wmv")
+    GST_CAPS_CODEC("video/x-vp8")
     GST_CAPS_CODEC("image/jpeg")
     ;
 
@@ -631,6 +633,9 @@ gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
         break;
 #endif
+    case GST_VAAPI_CODEC_VP8:
+        decode->decoder = gst_vaapi_decoder_vp8_new(dpy, caps);
+        break;
     default:
         decode->decoder = NULL;
         break;