fake{video|audio}sink: don't proxy properties at instance init.
authorMathieu Duponchelle <mathieu@centricular.com>
Fri, 23 Sep 2022 16:25:41 +0000 (18:25 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 19 Oct 2022 09:12:11 +0000 (09:12 +0000)
Instead proxy properties from the GstBaseSink class at class_init time,
and duplicate the rest of the fakesink properties manually.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1442

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3073>

subprojects/gst-docs/symbols/symbol_index.json
subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json
subprojects/gst-plugins-bad/gst/debugutils/gstfakeaudiosink.c
subprojects/gst-plugins-bad/gst/debugutils/gstfakesinkutils.c
subprojects/gst-plugins-bad/gst/debugutils/gstfakesinkutils.h
subprojects/gst-plugins-bad/gst/debugutils/gstfakevideosink.c

index 3c1efbf..54c29ae 100644 (file)
   "element-fakesink",
   "element-fakesrc",
   "element-fakevideosink",
-  "element-fakevideosink_GstFakeSinkStateError",
-  "element-fakevideosink_GstFakeSinkStateError::none",
-  "element-fakevideosink_GstFakeSinkStateError::null-to-ready",
-  "element-fakevideosink_GstFakeSinkStateError::paused-to-playing",
-  "element-fakevideosink_GstFakeSinkStateError::paused-to-ready",
-  "element-fakevideosink_GstFakeSinkStateError::playing-to-paused",
-  "element-fakevideosink_GstFakeSinkStateError::ready-to-null",
-  "element-fakevideosink_GstFakeSinkStateError::ready-to-paused",
   "element-fbdevsink",
   "element-fdkaacdec",
   "element-fdkaacenc",
index 5f7e7d7..dbc2b82 100644 (file)
                         "default": "none (0)",
                         "mutable": "null",
                         "readable": true,
-                        "type": "GstFakeSinkStateError",
+                        "type": "GstFakeAudioSinkStateError",
                         "writable": true
                     },
                     "stats": {
                         "default": "none (0)",
                         "mutable": "null",
                         "readable": true,
-                        "type": "GstFakeSinkStateError",
+                        "type": "GstFakeVideoSinkStateError",
                         "writable": true
                     },
                     "stats": {
                     }
                 ]
             },
-            "GstFakeSinkStateError": {
+            "GstFakeAudioSinkStateError": {
                 "kind": "enum",
                 "values": [
                     {
                         "value": "0x00000002"
                     }
                 ]
+            },
+            "GstFakeVideoSinkStateError": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "No state change errors",
+                        "name": "none",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Fail state change from NULL to READY",
+                        "name": "null-to-ready",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Fail state change from READY to PAUSED",
+                        "name": "ready-to-paused",
+                        "value": "2"
+                    },
+                    {
+                        "desc": "Fail state change from PAUSED to PLAYING",
+                        "name": "paused-to-playing",
+                        "value": "3"
+                    },
+                    {
+                        "desc": "Fail state change from PLAYING to PAUSED",
+                        "name": "playing-to-paused",
+                        "value": "4"
+                    },
+                    {
+                        "desc": "Fail state change from PAUSED to READY",
+                        "name": "paused-to-ready",
+                        "value": "5"
+                    },
+                    {
+                        "desc": "Fail state change from READY to NULL",
+                        "name": "ready-to-null",
+                        "value": "6"
+                    }
+                ]
             }
         },
         "package": "GStreamer Bad Plug-ins",
index 1493965..6a33435 100644 (file)
 
 #include <gst/audio/audio.h>
 
+typedef enum
+{
+  FAKE_SINK_STATE_ERROR_NONE = 0,
+  FAKE_SINK_STATE_ERROR_NULL_READY,
+  FAKE_SINK_STATE_ERROR_READY_PAUSED,
+  FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
+  FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
+  FAKE_SINK_STATE_ERROR_PAUSED_READY,
+  FAKE_SINK_STATE_ERROR_READY_NULL
+} GstFakeSinkStateError;
+
+#define DEFAULT_DROP_OUT_OF_SEGMENT TRUE
+#define DEFAULT_STATE_ERROR FAKE_SINK_STATE_ERROR_NONE
+#define DEFAULT_SILENT TRUE
+#define DEFAULT_DUMP FALSE
+#define DEFAULT_SIGNAL_HANDOFFS FALSE
+#define DEFAULT_LAST_MESSAGE NULL
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
+#define DEFAULT_CAN_ACTIVATE_PULL FALSE
+#define DEFAULT_NUM_BUFFERS -1
+
+/**
+ * GstFakeAudioSinkStateError:
+ *
+ * Proxy for GstFakeSinkError.
+ *
+ * Since: 1.22
+ */
+
+#define GST_TYPE_FAKE_AUDIO_SINK_STATE_ERROR (gst_fake_audio_sink_state_error_get_type())
+static GType
+gst_fake_audio_sink_state_error_get_type (void)
+{
+  static GType fakeaudiosink_state_error_type = 0;
+  static const GEnumValue fakeaudiosink_state_error[] = {
+    {FAKE_SINK_STATE_ERROR_NONE, "No state change errors", "none"},
+    {FAKE_SINK_STATE_ERROR_NULL_READY,
+        "Fail state change from NULL to READY", "null-to-ready"},
+    {FAKE_SINK_STATE_ERROR_READY_PAUSED,
+        "Fail state change from READY to PAUSED", "ready-to-paused"},
+    {FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
+        "Fail state change from PAUSED to PLAYING", "paused-to-playing"},
+    {FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
+        "Fail state change from PLAYING to PAUSED", "playing-to-paused"},
+    {FAKE_SINK_STATE_ERROR_PAUSED_READY,
+        "Fail state change from PAUSED to READY", "paused-to-ready"},
+    {FAKE_SINK_STATE_ERROR_READY_NULL,
+        "Fail state change from READY to NULL", "ready-to-null"},
+    {0, NULL, NULL},
+  };
+
+  if (!fakeaudiosink_state_error_type) {
+    fakeaudiosink_state_error_type =
+        g_enum_register_static ("GstFakeAudioSinkStateError",
+        fakeaudiosink_state_error);
+  }
+  return fakeaudiosink_state_error_type;
+}
+
+
 enum
 {
   PROP_0,
   PROP_VOLUME,
   PROP_MUTE,
+  PROP_STATE_ERROR,
+  PROP_SILENT,
+  PROP_DUMP,
+  PROP_SIGNAL_HANDOFFS,
+  PROP_DROP_OUT_OF_SEGMENT,
+  PROP_LAST_MESSAGE,
+  PROP_CAN_ACTIVATE_PUSH,
+  PROP_CAN_ACTIVATE_PULL,
+  PROP_NUM_BUFFERS,
   PROP_LAST
 };
 
@@ -60,29 +129,20 @@ enum
 
 static guint gst_fake_audio_sink_signals[LAST_SIGNAL] = { 0 };
 
+static GParamSpec *pspec_last_message = NULL;
+
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL)));
 
 G_DEFINE_TYPE_WITH_CODE (GstFakeAudioSink, gst_fake_audio_sink, GST_TYPE_BIN,
-    G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL););
+    G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL);
+    );
 GST_ELEMENT_REGISTER_DEFINE (fakeaudiosink, "fakeaudiosink",
     GST_RANK_NONE, gst_fake_audio_sink_get_type ());
 
 static void
-gst_fake_audio_sink_proxy_properties (GstFakeAudioSink * self,
-    GstElement * child)
-{
-  static gsize initialized = 0;
-
-  if (g_once_init_enter (&initialized)) {
-    gst_fake_sink_proxy_properties (GST_ELEMENT_CAST (self), child, PROP_LAST);
-    g_once_init_leave (&initialized, 1);
-  }
-}
-
-static void
 gst_fake_audio_sink_proxy_handoff (GstElement * element, GstBuffer * buffer,
     GstPad * pad, GstFakeAudioSink * self)
 {
@@ -99,6 +159,12 @@ gst_fake_audio_sink_proxy_preroll_handoff (GstElement * element,
 }
 
 static void
+gst_fake_audio_sink_proxy_last_message (GstElement * element)
+{
+  g_object_notify_by_pspec ((GObject *) element, pspec_last_message);
+}
+
+static void
 gst_fake_audio_sink_init (GstFakeAudioSink * self)
 {
   GstElement *child;
@@ -126,7 +192,8 @@ gst_fake_audio_sink_init (GstFakeAudioSink * self)
 
     self->child = child;
 
-    gst_fake_audio_sink_proxy_properties (self, child);
+    g_signal_connect (child, "notify::last-message",
+        G_CALLBACK (gst_fake_audio_sink_proxy_last_message), self);
     g_signal_connect (child, "handoff",
         G_CALLBACK (gst_fake_audio_sink_proxy_handoff), self);
     g_signal_connect (child, "preroll-handoff",
@@ -180,6 +247,7 @@ gst_fake_audio_sink_class_init (GstFakeAudioSinkClass * klass)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GObjectClass *base_sink_class;
 
   object_class->get_property = gst_fake_audio_sink_get_property;
   object_class->set_property = gst_fake_audio_sink_set_property;
@@ -241,8 +309,56 @@ gst_fake_audio_sink_class_init (GstFakeAudioSinkClass * klass)
           preroll_handoff), NULL, NULL, NULL, G_TYPE_NONE, 2,
       GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
 
+  g_object_class_install_property (object_class, PROP_STATE_ERROR,
+      g_param_spec_enum ("state-error", "State Error",
+          "Generate a state change error", GST_TYPE_FAKE_AUDIO_SINK_STATE_ERROR,
+          DEFAULT_STATE_ERROR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  pspec_last_message = g_param_spec_string ("last-message", "Last Message",
+      "The message describing current status", DEFAULT_LAST_MESSAGE,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_LAST_MESSAGE,
+      pspec_last_message);
+  g_object_class_install_property (object_class, PROP_SIGNAL_HANDOFFS,
+      g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
+          "Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_DROP_OUT_OF_SEGMENT,
+      g_param_spec_boolean ("drop-out-of-segment",
+          "Drop out-of-segment buffers",
+          "Drop and don't render / hand off out-of-segment buffers",
+          DEFAULT_DROP_OUT_OF_SEGMENT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_SILENT,
+      g_param_spec_boolean ("silent", "Silent",
+          "Don't produce last_message events", DEFAULT_SILENT,
+          G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
+          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_DUMP,
+      g_param_spec_boolean ("dump", "Dump", "Dump buffer contents to stdout",
+          DEFAULT_DUMP,
+          G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
+          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PUSH,
+      g_param_spec_boolean ("can-activate-push", "Can activate push",
+          "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PULL,
+      g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+          "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_NUM_BUFFERS,
+      g_param_spec_int ("num-buffers", "num-buffers",
+          "Number of buffers to accept going EOS", -1, G_MAXINT,
+          DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  base_sink_class = g_type_class_ref (GST_TYPE_BASE_SINK);
+  gst_util_proxy_class_properties (object_class, base_sink_class, PROP_LAST);
+  g_type_class_unref (base_sink_class);
+
   gst_element_class_add_static_pad_template (element_class, &sink_factory);
   gst_element_class_set_static_metadata (element_class, "Fake Audio Sink",
       "Audio/Sink", "Fake audio renderer",
       "Philippe Normand <philn@igalia.com>");
+
+  gst_type_mark_as_plugin_api (GST_TYPE_FAKE_AUDIO_SINK_STATE_ERROR, 0);
 }
index 46ac983..137c061 100644 (file)
 
 /* TODO complete the types */
 void
-gst_fake_sink_proxy_properties (GstElement * self,
-    GstElement * child, guint property_id_offset)
+gst_util_proxy_class_properties (GObjectClass * object_class,
+    GObjectClass * target_class, guint property_id_offset)
 {
-  GObjectClass *object_class;
   GParamSpec **properties;
   guint n_properties, i;
 
-  object_class = G_OBJECT_CLASS (GST_ELEMENT_GET_CLASS (self));
-  properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (child),
+  properties = g_object_class_list_properties (G_OBJECT_CLASS (target_class),
       &n_properties);
 
   for (i = 0; i < n_properties; i++) {
     guint property_id = i + property_id_offset;
 
-    if (properties[i]->owner_type != G_OBJECT_TYPE (child) &&
-        properties[i]->owner_type != GST_TYPE_BASE_SINK)
+    if (properties[i]->owner_type == G_TYPE_OBJECT
+        || properties[i]->owner_type == GST_TYPE_OBJECT)
       continue;
 
     if (G_IS_PARAM_SPEC_BOOLEAN (properties[i])) {
index ca8231f..62760b4 100644 (file)
 
 G_BEGIN_DECLS
 
-void gst_fake_sink_proxy_properties (GstElement * self, GstElement * child, guint property_id_offset);
+void
+gst_util_proxy_class_properties (GObjectClass *object_class,
+                                 GObjectClass *target_class,
+                                 guint property_id_offset);
 
 G_END_DECLS
 
index 4e47e69..2cb683d 100644 (file)
@@ -70,10 +70,78 @@ gst_fake_video_sink_allocation_meta_flags_get_type (void)
   return id;
 }
 
+typedef enum
+{
+  FAKE_SINK_STATE_ERROR_NONE = 0,
+  FAKE_SINK_STATE_ERROR_NULL_READY,
+  FAKE_SINK_STATE_ERROR_READY_PAUSED,
+  FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
+  FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
+  FAKE_SINK_STATE_ERROR_PAUSED_READY,
+  FAKE_SINK_STATE_ERROR_READY_NULL
+} GstFakeSinkStateError;
+
+#define DEFAULT_DROP_OUT_OF_SEGMENT TRUE
+#define DEFAULT_STATE_ERROR FAKE_SINK_STATE_ERROR_NONE
+#define DEFAULT_SILENT TRUE
+#define DEFAULT_DUMP FALSE
+#define DEFAULT_SIGNAL_HANDOFFS FALSE
+#define DEFAULT_LAST_MESSAGE NULL
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
+#define DEFAULT_CAN_ACTIVATE_PULL FALSE
+#define DEFAULT_NUM_BUFFERS -1
+
+/**
+ * GstFakeVideoSinkStateError:
+ *
+ * Proxy for GstFakeSinkError.
+ *
+ * Since: 1.22
+ */
+
+#define GST_TYPE_FAKE_VIDEO_SINK_STATE_ERROR (gst_fake_video_sink_state_error_get_type())
+static GType
+gst_fake_video_sink_state_error_get_type (void)
+{
+  static GType fakevideosink_state_error_type = 0;
+  static const GEnumValue fakevideosink_state_error[] = {
+    {FAKE_SINK_STATE_ERROR_NONE, "No state change errors", "none"},
+    {FAKE_SINK_STATE_ERROR_NULL_READY,
+        "Fail state change from NULL to READY", "null-to-ready"},
+    {FAKE_SINK_STATE_ERROR_READY_PAUSED,
+        "Fail state change from READY to PAUSED", "ready-to-paused"},
+    {FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
+        "Fail state change from PAUSED to PLAYING", "paused-to-playing"},
+    {FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
+        "Fail state change from PLAYING to PAUSED", "playing-to-paused"},
+    {FAKE_SINK_STATE_ERROR_PAUSED_READY,
+        "Fail state change from PAUSED to READY", "paused-to-ready"},
+    {FAKE_SINK_STATE_ERROR_READY_NULL,
+        "Fail state change from READY to NULL", "ready-to-null"},
+    {0, NULL, NULL},
+  };
+
+  if (!fakevideosink_state_error_type) {
+    fakevideosink_state_error_type =
+        g_enum_register_static ("GstFakeVideoSinkStateError",
+        fakevideosink_state_error);
+  }
+  return fakevideosink_state_error_type;
+}
+
 enum
 {
   PROP_0,
   PROP_ALLOCATION_META_FLAGS,
+  PROP_STATE_ERROR,
+  PROP_SILENT,
+  PROP_DUMP,
+  PROP_SIGNAL_HANDOFFS,
+  PROP_DROP_OUT_OF_SEGMENT,
+  PROP_LAST_MESSAGE,
+  PROP_CAN_ACTIVATE_PUSH,
+  PROP_CAN_ACTIVATE_PULL,
+  PROP_NUM_BUFFERS,
   PROP_LAST
 };
 
@@ -86,6 +154,8 @@ enum
 
 static guint gst_fake_video_sink_signals[LAST_SIGNAL] = { 0 };
 
+static GParamSpec *pspec_last_message = NULL;
+
 #define ALLOCATION_META_DEFAULT_FLAGS GST_ALLOCATION_FLAG_CROP_META | GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META
 
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
@@ -137,18 +207,6 @@ gst_fake_video_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
 }
 
 static void
-gst_fake_video_sink_proxy_properties (GstFakeVideoSink * self,
-    GstElement * child)
-{
-  static gsize initialized = 0;
-
-  if (g_once_init_enter (&initialized)) {
-    gst_fake_sink_proxy_properties (GST_ELEMENT_CAST (self), child, PROP_LAST);
-    g_once_init_leave (&initialized, 1);
-  }
-}
-
-static void
 gst_fake_video_sink_proxy_handoff (GstElement * element, GstBuffer * buffer,
     GstPad * pad, GstFakeVideoSink * self)
 {
@@ -157,6 +215,12 @@ gst_fake_video_sink_proxy_handoff (GstElement * element, GstBuffer * buffer,
 }
 
 static void
+gst_fake_video_sink_proxy_last_message (GstElement * element)
+{
+  g_object_notify_by_pspec ((GObject *) element, pspec_last_message);
+}
+
+static void
 gst_fake_video_sink_proxy_preroll_handoff (GstElement * element,
     GstBuffer * buffer, GstPad * pad, GstFakeVideoSink * self)
 {
@@ -195,7 +259,8 @@ gst_fake_video_sink_init (GstFakeVideoSink * self)
 
     self->child = child;
 
-    gst_fake_video_sink_proxy_properties (self, child);
+    g_signal_connect (child, "notify::last-message",
+        G_CALLBACK (gst_fake_video_sink_proxy_last_message), self);
     g_signal_connect (child, "handoff",
         G_CALLBACK (gst_fake_video_sink_proxy_handoff), self);
     g_signal_connect (child, "preroll-handoff",
@@ -247,6 +312,7 @@ gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GObjectClass *base_sink_class;
 
   object_class->get_property = gst_fake_video_sink_get_property;
   object_class->set_property = gst_fake_video_sink_set_property;
@@ -270,7 +336,6 @@ gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
           ALLOCATION_META_DEFAULT_FLAGS,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
-
   /**
    * GstFakeVideoSink::handoff:
    * @fakevideosink: the fakevideosink instance
@@ -303,6 +368,53 @@ gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
           preroll_handoff), NULL, NULL, NULL, G_TYPE_NONE, 2,
       GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
 
+  g_object_class_install_property (object_class, PROP_STATE_ERROR,
+      g_param_spec_enum ("state-error", "State Error",
+          "Generate a state change error", GST_TYPE_FAKE_VIDEO_SINK_STATE_ERROR,
+          DEFAULT_STATE_ERROR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  pspec_last_message = g_param_spec_string ("last-message", "Last Message",
+      "The message describing current status", DEFAULT_LAST_MESSAGE,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_LAST_MESSAGE,
+      pspec_last_message);
+  g_object_class_install_property (object_class, PROP_SIGNAL_HANDOFFS,
+      g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
+          "Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_DROP_OUT_OF_SEGMENT,
+      g_param_spec_boolean ("drop-out-of-segment",
+          "Drop out-of-segment buffers",
+          "Drop and don't render / hand off out-of-segment buffers",
+          DEFAULT_DROP_OUT_OF_SEGMENT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_SILENT,
+      g_param_spec_boolean ("silent", "Silent",
+          "Don't produce last_message events", DEFAULT_SILENT,
+          G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
+          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_DUMP,
+      g_param_spec_boolean ("dump", "Dump", "Dump buffer contents to stdout",
+          DEFAULT_DUMP,
+          G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
+          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PUSH,
+      g_param_spec_boolean ("can-activate-push", "Can activate push",
+          "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_CAN_ACTIVATE_PULL,
+      g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+          "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_NUM_BUFFERS,
+      g_param_spec_int ("num-buffers", "num-buffers",
+          "Number of buffers to accept going EOS", -1, G_MAXINT,
+          DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  base_sink_class = g_type_class_ref (GST_TYPE_BASE_SINK);
+  gst_util_proxy_class_properties (object_class, base_sink_class, PROP_LAST);
+  g_type_class_unref (base_sink_class);
+
   gst_type_mark_as_plugin_api (GST_TYPE_FAKE_VIDEO_SINK_ALLOCATION_META_FLAGS,
       0);
+  gst_type_mark_as_plugin_api (GST_TYPE_FAKE_VIDEO_SINK_STATE_ERROR, 0);
 }