codecs: Add new baseclass for VP8 decoder
authorSeungha Yang <seungha@centricular.com>
Sun, 29 Mar 2020 13:23:23 +0000 (22:23 +0900)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 22 Apr 2020 23:20:44 +0000 (23:20 +0000)
This implemenation is similar to VP9 but much simpler than it.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1079>

gst-libs/gst/codecs/gstvp8decoder.c [new file with mode: 0644]
gst-libs/gst/codecs/gstvp8decoder.h [new file with mode: 0644]
gst-libs/gst/codecs/gstvp8picture.c [new file with mode: 0644]
gst-libs/gst/codecs/gstvp8picture.h [new file with mode: 0644]
gst-libs/gst/codecs/meson.build

diff --git a/gst-libs/gst/codecs/gstvp8decoder.c b/gst-libs/gst/codecs/gstvp8decoder.c
new file mode 100644 (file)
index 0000000..b3179e2
--- /dev/null
@@ -0,0 +1,393 @@
+/* GStreamer
+ * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:gstvp8decoder
+ * @title: GstVP8Decoder
+ * @short_description: Base class to implement stateless VP8 decoders
+ * @sources:
+ * - gstvp8picture.h
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstvp8decoder.h"
+
+GST_DEBUG_CATEGORY (gst_vp8_decoder_debug);
+#define GST_CAT_DEFAULT gst_vp8_decoder_debug
+
+struct _GstVp8DecoderPrivate
+{
+  gint width;
+  gint height;
+
+  gboolean had_sequence;
+  GstVp8Parser parser;
+  gboolean wait_keyframe;
+};
+
+#define parent_class gst_vp8_decoder_parent_class
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVp8Decoder, gst_vp8_decoder,
+    GST_TYPE_VIDEO_DECODER,
+    G_ADD_PRIVATE (GstVp8Decoder);
+    GST_DEBUG_CATEGORY_INIT (gst_vp8_decoder_debug, "vp8decoder", 0,
+        "VP8 Video Decoder"));
+
+static gboolean gst_vp8_decoder_start (GstVideoDecoder * decoder);
+static gboolean gst_vp8_decoder_stop (GstVideoDecoder * decoder);
+static gboolean gst_vp8_decoder_set_format (GstVideoDecoder * decoder,
+    GstVideoCodecState * state);
+static GstFlowReturn gst_vp8_decoder_finish (GstVideoDecoder * decoder);
+static gboolean gst_vp8_decoder_flush (GstVideoDecoder * decoder);
+static GstFlowReturn gst_vp8_decoder_drain (GstVideoDecoder * decoder);
+static GstFlowReturn gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame);
+
+static void
+gst_vp8_decoder_class_init (GstVp8DecoderClass * klass)
+{
+  GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
+
+  decoder_class->start = GST_DEBUG_FUNCPTR (gst_vp8_decoder_start);
+  decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp8_decoder_stop);
+  decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_vp8_decoder_set_format);
+  decoder_class->finish = GST_DEBUG_FUNCPTR (gst_vp8_decoder_finish);
+  decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vp8_decoder_flush);
+  decoder_class->drain = GST_DEBUG_FUNCPTR (gst_vp8_decoder_drain);
+  decoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_vp8_decoder_handle_frame);
+}
+
+static void
+gst_vp8_decoder_init (GstVp8Decoder * self)
+{
+  gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
+
+  self->priv = gst_vp8_decoder_get_instance_private (self);
+}
+
+static gboolean
+gst_vp8_decoder_start (GstVideoDecoder * decoder)
+{
+  GstVp8Decoder *self = GST_VP8_DECODER (decoder);
+  GstVp8DecoderPrivate *priv = self->priv;
+
+  gst_vp8_parser_init (&priv->parser);
+  priv->wait_keyframe = TRUE;
+
+  return TRUE;
+}
+
+static void
+gst_vp8_decoder_reset (GstVp8Decoder * self)
+{
+  GstVp8DecoderPrivate *priv = self->priv;
+
+  gst_vp8_picture_clear (&self->last_picture);
+  gst_vp8_picture_clear (&self->golden_ref_picture);
+  gst_vp8_picture_clear (&self->alt_ref_picture);
+
+  priv->wait_keyframe = TRUE;
+}
+
+static gboolean
+gst_vp8_decoder_stop (GstVideoDecoder * decoder)
+{
+  GstVp8Decoder *self = GST_VP8_DECODER (decoder);
+
+  if (self->input_state) {
+    gst_video_codec_state_unref (self->input_state);
+    self->input_state = NULL;
+  }
+
+  gst_vp8_decoder_reset (self);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vp8_decoder_check_codec_change (GstVp8Decoder * self,
+    const GstVp8FrameHdr * frame_hdr)
+{
+  GstVp8DecoderPrivate *priv = self->priv;
+  gboolean ret = TRUE;
+  gboolean changed = FALSE;
+
+  if (priv->width != frame_hdr->width || priv->height != frame_hdr->height) {
+    GST_INFO_OBJECT (self, "resolution changed %dx%d", frame_hdr->width,
+        frame_hdr->height);
+    priv->width = frame_hdr->width;
+    priv->height = frame_hdr->height;
+    changed = TRUE;
+  }
+
+  if (changed || !priv->had_sequence) {
+    GstVp8DecoderClass *klass = GST_VP8_DECODER_GET_CLASS (self);
+
+    priv->had_sequence = TRUE;
+
+    if (klass->new_sequence)
+      ret = klass->new_sequence (self, frame_hdr);
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_vp8_decoder_set_format (GstVideoDecoder * decoder,
+    GstVideoCodecState * state)
+{
+  GstVp8Decoder *self = GST_VP8_DECODER (decoder);
+  GstVp8DecoderPrivate *priv = self->priv;
+
+  GST_DEBUG_OBJECT (decoder, "Set format");
+
+  if (self->input_state)
+    gst_video_codec_state_unref (self->input_state);
+
+  self->input_state = gst_video_codec_state_ref (state);
+
+  priv->width = GST_VIDEO_INFO_WIDTH (&state->info);
+  priv->height = GST_VIDEO_INFO_HEIGHT (&state->info);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vp8_decoder_update_reference (GstVp8Decoder * self, GstVp8Picture * picture)
+{
+  GstVp8FrameHdr *frame_hdr = &picture->frame_hdr;
+
+  if (frame_hdr->key_frame) {
+    gst_vp8_picture_replace (&self->last_picture, picture);
+    gst_vp8_picture_replace (&self->golden_ref_picture, picture);
+    gst_vp8_picture_replace (&self->alt_ref_picture, picture);
+
+    goto done;
+  }
+
+  if (frame_hdr->refresh_alternate_frame) {
+    gst_vp8_picture_replace (&self->alt_ref_picture, picture);
+  } else {
+    switch (frame_hdr->copy_buffer_to_alternate) {
+      case 0:
+        /* do nothing */
+        break;
+      case 1:
+        gst_vp8_picture_replace (&self->alt_ref_picture, self->last_picture);
+        break;
+      case 2:
+        gst_vp8_picture_replace (&self->alt_ref_picture,
+            self->golden_ref_picture);
+        break;
+      default:
+        GST_WARNING_OBJECT (self, "unrecognized copy_buffer_to_alternate %d",
+            frame_hdr->copy_buffer_to_alternate);
+        break;
+    }
+  }
+
+  if (frame_hdr->refresh_golden_frame) {
+    gst_vp8_picture_replace (&self->golden_ref_picture, picture);
+  } else {
+    switch (frame_hdr->copy_buffer_to_golden) {
+      case 0:
+        /* do nothing */
+        break;
+      case 1:
+        gst_vp8_picture_replace (&self->golden_ref_picture, self->last_picture);
+        break;
+      case 2:
+        gst_vp8_picture_replace (&self->golden_ref_picture,
+            self->alt_ref_picture);
+        break;
+      default:
+        GST_WARNING_OBJECT (self, "unrecognized copy_buffer_to_golden %d",
+            frame_hdr->copy_buffer_to_alternate);
+        break;
+    }
+  }
+
+  if (frame_hdr->refresh_last)
+    gst_vp8_picture_replace (&self->last_picture, picture);
+
+done:
+  gst_vp8_picture_unref (picture);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vp8_decoder_finish (GstVideoDecoder * decoder)
+{
+  GstVp8Decoder *self = GST_VP8_DECODER (decoder);
+
+  GST_DEBUG_OBJECT (self, "finish");
+
+  gst_vp8_decoder_reset (self);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_vp8_decoder_flush (GstVideoDecoder * decoder)
+{
+  GstVp8Decoder *self = GST_VP8_DECODER (decoder);
+
+  GST_DEBUG_OBJECT (self, "flush");
+
+  gst_vp8_decoder_reset (self);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vp8_decoder_drain (GstVideoDecoder * decoder)
+{
+  GstVp8Decoder *self = GST_VP8_DECODER (decoder);
+
+  GST_DEBUG_OBJECT (self, "drain");
+
+  gst_vp8_decoder_reset (self);
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame)
+{
+  GstVp8Decoder *self = GST_VP8_DECODER (decoder);
+  GstVp8DecoderClass *klass = GST_VP8_DECODER_GET_CLASS (self);
+  GstVp8DecoderPrivate *priv = self->priv;
+  GstBuffer *in_buf = frame->input_buffer;
+  GstMapInfo map;
+  GstVp8FrameHdr frame_hdr;
+  GstVp8ParserResult pres;
+  GstVp8Picture *picture = NULL;
+
+  GST_LOG_OBJECT (self,
+      "handle frame, PTS: %" GST_TIME_FORMAT ", DTS: %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (in_buf)),
+      GST_TIME_ARGS (GST_BUFFER_DTS (in_buf)));
+
+  if (!gst_buffer_map (in_buf, &map, GST_MAP_READ)) {
+    GST_ERROR_OBJECT (self, "Cannot map buffer");
+
+    goto error;
+  }
+
+  pres = gst_vp8_parser_parse_frame_header (&priv->parser,
+      &frame_hdr, map.data, map.size);
+
+  if (pres != GST_VP8_PARSER_OK) {
+    GST_ERROR_OBJECT (self, "Cannot parser frame header");
+
+    goto unmap_and_error;
+  }
+
+  if (priv->wait_keyframe) {
+    if (!frame_hdr.key_frame) {
+      GST_DEBUG_OBJECT (self, "Waiting initial keyframe, drop buffer %"
+          GST_PTR_FORMAT, in_buf);
+
+      gst_buffer_unmap (in_buf, &map);
+      gst_video_decoder_drop_frame (decoder, frame);
+
+      return GST_FLOW_OK;
+    }
+  }
+
+  priv->wait_keyframe = FALSE;
+
+  if (frame_hdr.key_frame &&
+      !gst_vp8_decoder_check_codec_change (self, &frame_hdr)) {
+    GST_ERROR_OBJECT (self, "Subclass cannot handle codec change");
+    goto unmap_and_error;
+  }
+
+  picture = gst_vp8_picture_new ();
+  picture->frame_hdr = frame_hdr;
+  picture->pts = GST_BUFFER_PTS (in_buf);
+  picture->data = map.data;
+  picture->size = map.size;
+  picture->system_frame_number = frame->system_frame_number;
+
+  if (klass->new_picture) {
+    if (!klass->new_picture (self, picture)) {
+      GST_ERROR_OBJECT (self, "subclass cannot handle new picture");
+      goto unmap_and_error;
+    }
+  }
+
+  if (klass->start_picture) {
+    if (!klass->start_picture (self, picture)) {
+      GST_ERROR_OBJECT (self, "subclass cannot handle start picture");
+      goto unmap_and_error;
+    }
+  }
+
+  if (klass->decode_picture) {
+    if (!klass->decode_picture (self, picture, &priv->parser)) {
+      GST_ERROR_OBJECT (self, "subclass cannot decode current picture");
+      goto unmap_and_error;
+    }
+  }
+
+  if (klass->end_picture) {
+    if (!klass->end_picture (self, picture)) {
+      GST_ERROR_OBJECT (self, "subclass cannot handle end picture");
+      goto unmap_and_error;
+    }
+  }
+
+  gst_buffer_unmap (in_buf, &map);
+
+  gst_video_codec_frame_set_user_data (frame, gst_vp8_picture_ref (picture),
+      (GDestroyNotify) gst_vp8_picture_unref);
+  gst_video_codec_frame_unref (frame);
+
+  /* transfer ownership of picture */
+  gst_vp8_decoder_update_reference (self, picture);
+
+  g_assert (klass->output_picture);
+  return klass->output_picture (self, picture);
+
+unmap_and_error:
+  {
+    gst_buffer_unmap (in_buf, &map);
+    goto error;
+  }
+
+error:
+  {
+    GstFlowReturn ret;
+
+    if (picture)
+      gst_vp8_picture_unref (picture);
+
+    gst_video_decoder_drop_frame (decoder, frame);
+    GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
+        ("Failed to decode data"), (NULL), ret);
+
+    return ret;
+  }
+}
diff --git a/gst-libs/gst/codecs/gstvp8decoder.h b/gst-libs/gst/codecs/gstvp8decoder.h
new file mode 100644 (file)
index 0000000..c229f4d
--- /dev/null
@@ -0,0 +1,121 @@
+/* GStreamer
+ * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_VP8_DECODER_H__
+#define __GST_VP8_DECODER_H__
+
+#include <gst/codecs/codecs-prelude.h>
+
+#include <gst/video/video.h>
+#include <gst/codecparsers/gstvp8parser.h>
+#include <gst/codecs/gstvp8picture.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VP8_DECODER            (gst_vp8_decoder_get_type())
+#define GST_VP8_DECODER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP8_DECODER,GstVp8Decoder))
+#define GST_VP8_DECODER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP8_DECODER,GstVp8DecoderClass))
+#define GST_VP8_DECODER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_VP8_DECODER,GstVp8DecoderClass))
+#define GST_IS_VP8_DECODER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP8_DECODER))
+#define GST_IS_VP8_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP8_DECODER))
+#define GST_VP8_DECODER_CAST(obj)       ((GstVP8Decoder*)obj)
+
+typedef struct _GstVp8Decoder GstVp8Decoder;
+typedef struct _GstVp8DecoderClass GstVp8DecoderClass;
+typedef struct _GstVp8DecoderPrivate GstVp8DecoderPrivate;
+
+/**
+ * GstVp8Decoder:
+ *
+ * The opaque #GstVp8Decoder data structure.
+ */
+struct _GstVp8Decoder
+{
+  /*< private >*/
+  GstVideoDecoder parent;
+
+  /*< protected >*/
+  GstVideoCodecState * input_state;
+
+  /* reference frames */
+  GstVp8Picture *last_picture;
+  GstVp8Picture *golden_ref_picture;
+  GstVp8Picture *alt_ref_picture;
+
+  /*< private >*/
+  GstVp8DecoderPrivate *priv;
+  gpointer padding[GST_PADDING_LARGE];
+};
+
+/**
+ * GstVp8DecoderClass:
+ * @new_sequence:      Notifies subclass of SPS update
+ * @new_picture:       Optional.
+ *                     Called whenever new #GstVp8Picture is created.
+ *                     Subclass can set implementation specific user data
+ *                     on the #GstVp8Picture via gst_vp8_picture_set_user_data()
+ * @start_picture:     Optional.
+ *                     Called per one #GstVp8Picture to notify subclass to prepare
+ *                     decoding process for the #GstVp8Picture
+ * @decode_slice:      Provides per slice data with parsed slice header and
+ *                     required raw bitstream for subclass to decode it
+ * @end_picture:       Optional.
+ *                     Called per one #GstVp8Picture to notify subclass to finish
+ *                     decoding process for the #GstVp8Picture
+ * @output_picture:    Called with a #GstVp8Picture which is required to be outputted.
+ *                     Subclass can retrieve parent #GstVideoCodecFrame by using
+ *                     gst_video_decoder_get_frame() with system_frame_number
+ *                     and the #GstVideoCodecFrame must be consumed by subclass via
+ *                     gst_video_decoder_{finish,drop,release}_frame().
+ */
+struct _GstVp8DecoderClass
+{
+  GstVideoDecoderClass parent_class;
+
+  gboolean        (*new_sequence)      (GstVp8Decoder * decoder,
+                                        const GstVp8FrameHdr * frame_hdr);
+
+  gboolean        (*new_picture)       (GstVp8Decoder * decoder,
+                                        GstVp8Picture * picture);
+
+  gboolean        (*start_picture)     (GstVp8Decoder * decoder,
+                                        GstVp8Picture * picture);
+
+  gboolean        (*decode_picture)    (GstVp8Decoder * decoder,
+                                        GstVp8Picture * picture,
+                                        GstVp8Parser * parser);
+
+  gboolean        (*end_picture)       (GstVp8Decoder * decoder,
+                                        GstVp8Picture * picture);
+
+  GstFlowReturn   (*output_picture)    (GstVp8Decoder * decoder,
+                                        GstVp8Picture * picture);
+
+  /*< private >*/
+  gpointer padding[GST_PADDING_LARGE];
+};
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVp8Decoder, gst_object_unref)
+
+GST_CODECS_API
+GType gst_vp8_decoder_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_VP8_DECODER_H__ */
diff --git a/gst-libs/gst/codecs/gstvp8picture.c b/gst-libs/gst/codecs/gstvp8picture.c
new file mode 100644 (file)
index 0000000..b40e207
--- /dev/null
@@ -0,0 +1,104 @@
+/* GStreamer
+ * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstvp8picture.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_vp8_decoder_debug);
+#define GST_CAT_DEFAULT gst_vp8_decoder_debug
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstVp8Picture, gst_vp8_picture);
+
+static void
+_gst_vp8_picture_free (GstVp8Picture * picture)
+{
+  GST_TRACE ("Free picture %p", picture);
+
+  if (picture->notify)
+    picture->notify (picture->user_data);
+
+  g_free (picture);
+}
+
+/**
+ * gst_vp8_picture_new:
+ *
+ * Create new #GstVp8Picture
+ *
+ * Returns: a new #GstVp8Picture
+ */
+GstVp8Picture *
+gst_vp8_picture_new (void)
+{
+  GstVp8Picture *pic;
+
+  pic = g_new0 (GstVp8Picture, 1);
+  pic->pts = GST_CLOCK_TIME_NONE;
+
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (pic), 0,
+      GST_TYPE_VP8_PICTURE, NULL, NULL,
+      (GstMiniObjectFreeFunction) _gst_vp8_picture_free);
+
+  GST_TRACE ("New picture %p", pic);
+
+  return pic;
+}
+
+/**
+ * gst_vp8_picture_set_user_data:
+ * @picture: a #GstVp8Picture
+ * @user_data: private data
+ * @notify: (closure user_data): a #GDestroyNotify
+ *
+ * Sets @user_data on the picture and the #GDestroyNotify that will be called when
+ * the picture is freed.
+ *
+ * If a @user_data was previously set, then the previous set @notify will be called
+ * before the @user_data is replaced.
+ */
+void
+gst_vp8_picture_set_user_data (GstVp8Picture * picture, gpointer user_data,
+    GDestroyNotify notify)
+{
+  g_return_if_fail (GST_IS_VP8_PICTURE (picture));
+
+  if (picture->notify)
+    picture->notify (picture->user_data);
+
+  picture->user_data = user_data;
+  picture->notify = notify;
+}
+
+/**
+ * gst_vp8_picture_get_user_data:
+ * @picture: a #GstVp8Picture
+ *
+ * Gets private data set on the picture via
+ * gst_vp8_picture_set_user_data() previously.
+ *
+ * Returns: (transfer none): The previously set user_data
+ */
+gpointer
+gst_vp8_picture_get_user_data (GstVp8Picture * picture)
+{
+  return picture->user_data;
+}
diff --git a/gst-libs/gst/codecs/gstvp8picture.h b/gst-libs/gst/codecs/gstvp8picture.h
new file mode 100644 (file)
index 0000000..5de240b
--- /dev/null
@@ -0,0 +1,98 @@
+/* GStreamer
+ * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_VP8_PICTURE_H__
+#define __GST_VP8_PICTURE_H__
+
+#include <gst/codecs/codecs-prelude.h>
+#include <gst/codecparsers/gstvp8parser.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VP8_PICTURE     (gst_vp8_picture_get_type())
+#define GST_IS_VP8_PICTURE(obj)  (GST_IS_MINI_OBJECT_TYPE(obj, GST_TYPE_VP8_PICTURE))
+#define GST_VP8_PICTURE(obj)     ((GstVp8Picture *)obj)
+#define GST_VP8_PICTURE_CAST(obj) (GST_VP8_PICTURE(obj))
+
+typedef struct _GstVp8Picture GstVp8Picture;
+
+struct _GstVp8Picture
+{
+  GstMiniObject parent;
+
+  GstClockTime pts;
+  /* From GstVideoCodecFrame */
+  guint32 system_frame_number;
+
+  GstVp8FrameHdr frame_hdr;
+
+  /* raw data and size (does not have ownership) */
+  const guint8 * data;
+  gsize size;
+
+  gpointer user_data;
+  GDestroyNotify notify;
+};
+
+GST_CODECS_API
+GType gst_vp8_picture_get_type (void);
+
+GST_CODECS_API
+GstVp8Picture * gst_vp8_picture_new (void);
+
+static inline GstVp8Picture *
+gst_vp8_picture_ref (GstVp8Picture * picture)
+{
+  return (GstVp8Picture *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (picture));
+}
+
+static inline void
+gst_vp8_picture_unref (GstVp8Picture * picture)
+{
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (picture));
+}
+
+static inline gboolean
+gst_vp8_picture_replace (GstVp8Picture ** old_picture,
+    GstVp8Picture * new_picture)
+{
+  return gst_mini_object_replace ((GstMiniObject **) old_picture,
+      (GstMiniObject *) new_picture);
+}
+
+static inline void
+gst_vp8_picture_clear (GstVp8Picture ** picture)
+{
+  if (picture && *picture) {
+    gst_vp8_picture_unref (*picture);
+    *picture = NULL;
+  }
+}
+
+GST_CODECS_API
+void gst_vp8_picture_set_user_data (GstVp8Picture * picture,
+                                    gpointer user_data,
+                                    GDestroyNotify notify);
+
+GST_CODECS_API
+gpointer gst_vp8_picture_get_user_data (GstVp8Picture * picture);
+
+G_END_DECLS
+
+#endif /* __GST_VP8_PICTURE_H__ */
index 455fafc..1476090 100644 (file)
@@ -5,6 +5,8 @@ codecs_sources = files([
   'gsth265picture.c',
   'gstvp9decoder.c',
   'gstvp9picture.c',
+  'gstvp8decoder.c',
+  'gstvp8picture.c',
 ])
 
 codecs_headers = [
@@ -14,6 +16,8 @@ codecs_headers = [
   'gsth265picture.h',
   'gstvp9decoder.h',
   'gstvp9picture.h',
+  'gstvp8decoder.h',
+  'gstvp8picture.h',
 ]
 
 cp_args = [
@@ -46,7 +50,9 @@ if build_gir
     extra_args : gir_init_section + ['-DGST_USE_UNSTABLE_API'] +
       ['--c-include=gst/codecs/gsth264decoder.h',
       '--c-include=gst/codecs/gsth265decoder.h',
-      '--c-include=gst/codecs/gstvp9decoder.h', ],
+      '--c-include=gst/codecs/gstvp9decoder.h',
+      '--c-include=gst/codecs/gstvp8decoder.h',
+      ],
     dependencies : [gstvideo_dep, gstcodecparsers_dep]
   )
 endif