[cheese/wip/hadess/remove-clutter: 1/2] Port libcheese away from clutter




commit 3cca9c14c17dbab3c90f0f62357b5f4195ee45bd
Author: Bastien Nocera <hadess hadess net>
Date:   Sun Feb 6 19:05:19 2022 +0100

    Port libcheese away from clutter
    
    Use GStreamer's gtkglsink to display video instead of
    clutter{-gst,-gtk,}.
    
    --
    TODO:
    - There's no replacement for cheese_camera_size_change_cb() to handle
      setting a decent size for the video display widget
    - Performance seems slightly worse than clutter-gst, but there's at
      least a chance to get it accelerated with the vaapi widgets for
      MJPEG cameras.
    - The effects pipeline is untested as there weren't any tests for
      that in the tests/ subdirectory

 libcheese/cheese-camera.c  | 96 +++++++++++++++++-----------------------------
 libcheese/cheese-camera.h  |  8 ++--
 libcheese/cheese-gtk.c     | 11 +-----
 libcheese/cheese-widget.c  | 27 ++++---------
 libcheese/cheese-widget.h  |  2 -
 libcheese/cheese.c         | 11 ++----
 libcheese/meson.build      |  8 ++--
 tests/cheese-test-camera.c | 22 ++---------
 8 files changed, 57 insertions(+), 128 deletions(-)
---
diff --git a/libcheese/cheese-camera.c b/libcheese/cheese-camera.c
index e123ff34..149bef92 100644
--- a/libcheese/cheese-camera.c
+++ b/libcheese/cheese-camera.c
@@ -28,8 +28,6 @@
 #include <glib-object.h>
 #include <glib.h>
 #include <glib/gi18n-lib.h>
-#include <clutter/clutter.h>
-#include <clutter-gst/clutter-gst.h>
 #include <gst/gst.h>
 /* Avoid a warning. */
 #define GST_USE_UNSTABLE_API
@@ -66,7 +64,7 @@ struct _CheeseCameraPrivate
   GstElement *video_source;
   GstElement *camera_source;
 
-  ClutterActor *video_texture;
+  GtkWidget *video_widget;
 
   GstElement *effect_filter, *effects_capsfilter;
   GstElement *video_balance;
@@ -99,7 +97,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (CheeseCamera, cheese_camera, G_TYPE_OBJECT)
 enum
 {
   PROP_0,
-  PROP_VIDEO_TEXTURE,
+  PROP_WIDGET,
   PROP_DEVICE,
   PROP_FORMAT,
   PROP_NUM_CAMERA_DEVICES,
@@ -1009,28 +1007,24 @@ cheese_camera_toggle_effects_pipeline (CheeseCamera *camera, gboolean active)
   priv->effect_pipeline_is_playing = active;
 }
 
-static void
-cheese_camera_connected_size_change_cb (ClutterGstContent *content, gint width, gint height, ClutterActor 
*actor)
-{
-  clutter_actor_set_size (actor, width, height);
-}
-
 /**
  * cheese_camera_connect_effect_texture:
  * @camera: a #CheeseCamera
  * @effect: a #CheeseEffect
- * @texture: a #ClutterActor
+ * @container: a #GtkContainer
  *
- * Connect the supplied @texture to the @camera, using @effect.
+ * Insert a video widget connected to the @camera in the supplied @container, using @effect.
  */
 void
-cheese_camera_connect_effect_texture (CheeseCamera *camera, CheeseEffect *effect, ClutterActor *texture)
+cheese_camera_connect_effect_texture (CheeseCamera *camera, CheeseEffect *effect, GtkContainer *container)
 {
   CheeseCameraPrivate *priv;
   GstElement *effect_filter;
-  GstElement *display_element;
+  GstElement *video_sink;
+  GstElement *glsinkbin;
   GstElement *display_queue;
   GstElement *control_valve;
+  GtkWidget *video_widget;
   gboolean ok;
   g_return_if_fail (CHEESE_IS_CAMERA (camera));
 
@@ -1046,27 +1040,24 @@ cheese_camera_connect_effect_texture (CheeseCamera *camera, CheeseEffect *effect
 
   effect_filter = cheese_camera_element_from_effect (camera, effect);
 
-  display_element = GST_ELEMENT (clutter_gst_video_sink_new ());
-  g_object_set (G_OBJECT (texture),
-                "content", g_object_new (CLUTTER_GST_TYPE_CONTENT,
-                                         "sink", display_element,
-                                         NULL),
-                NULL);
-
-  g_signal_connect (G_OBJECT (clutter_actor_get_content (texture)),
-                    "size-change", G_CALLBACK (cheese_camera_connected_size_change_cb), texture);
+  video_sink = gst_element_factory_make ("gtkglsink", "gtkglsink");
+  glsinkbin = gst_element_factory_make ("glsinkbin", "glsinkbin");
+  g_object_set (glsinkbin, "sink", video_sink, NULL);
+  g_object_get (video_sink, "widget", &video_widget, NULL);
+  gtk_container_add (container, video_widget);
+  g_object_unref (video_widget);
 
-  gst_bin_add_many (GST_BIN (priv->video_filter_bin), control_valve, effect_filter, display_queue, 
display_element, NULL);
+  gst_bin_add_many (GST_BIN (priv->video_filter_bin), control_valve, effect_filter, display_queue, 
glsinkbin, NULL);
 
-  ok = gst_element_link_many (priv->effects_tee, control_valve, effect_filter, display_queue, 
display_element, NULL);
+  ok = gst_element_link_many (priv->effects_tee, control_valve, effect_filter, display_queue, glsinkbin, 
NULL);
   g_return_if_fail (ok);
 
   /* HACK: I don't understand GStreamer enough to know why this works. */
   gst_element_set_state (control_valve, GST_STATE_PLAYING);
   gst_element_set_state (effect_filter, GST_STATE_PLAYING);
   gst_element_set_state (display_queue, GST_STATE_PLAYING);
-  gst_element_set_state (display_element, GST_STATE_PLAYING);
-  gst_element_set_locked_state (display_element, TRUE);
+  gst_element_set_state (glsinkbin, GST_STATE_PLAYING);
+  gst_element_set_locked_state (glsinkbin, TRUE);
 
   if (!ok)
       g_warning ("Could not create effects pipeline");
@@ -1319,8 +1310,8 @@ cheese_camera_get_property (GObject *object, guint prop_id, GValue *value,
 
   switch (prop_id)
   {
-    case PROP_VIDEO_TEXTURE:
-      g_value_set_pointer (value, priv->video_texture);
+    case PROP_WIDGET:
+      g_value_set_pointer (value, priv->video_widget);
       break;
     case PROP_DEVICE:
       g_value_set_object (value, priv->device);
@@ -1349,9 +1340,6 @@ cheese_camera_set_property (GObject *object, guint prop_id, const GValue *value,
 
   switch (prop_id)
   {
-    case PROP_VIDEO_TEXTURE:
-      priv->video_texture = g_value_get_pointer (value);
-      break;
     case PROP_DEVICE:
       g_clear_object (&priv->device);
       priv->device = g_value_dup_object (value);
@@ -1439,15 +1427,15 @@ cheese_camera_class_init (CheeseCameraClass *klass)
 
 
   /**
-   * CheeseCamera:video-texture:
+   * CheeseCamera:widget:
    *
    * The video texture for the #CheeseCamera to render into.
    */
-  properties[PROP_VIDEO_TEXTURE] = g_param_spec_pointer ("video-texture",
-                                                         "Video texture",
-                                                         "The video texture for the CheeseCamera to render 
into",
-                                                         G_PARAM_READWRITE |
-                                                         G_PARAM_STATIC_STRINGS);
+  properties[PROP_WIDGET] = g_param_spec_pointer ("widget",
+                                                  "Widget",
+                                                  "The video widget for the CheeseCamera to render into",
+                                                  G_PARAM_READABLE |
+                                                  G_PARAM_STATIC_STRINGS);
 
   /**
    * CheeseCamera:device:
@@ -1502,7 +1490,6 @@ cheese_camera_init (CheeseCamera *camera)
 
 /**
  * cheese_camera_new:
- * @video_texture: an actor in which to render the video
  * @name: (allow-none): the name of the device
  * @x_resolution: the resolution width
  * @y_resolution: the resolution height
@@ -1512,13 +1499,12 @@ cheese_camera_init (CheeseCamera *camera)
  * Returns: a new #CheeseCamera
  */
 CheeseCamera *
-cheese_camera_new (ClutterActor *video_texture, const gchar *name,
-                   gint x_resolution, gint y_resolution)
+cheese_camera_new (const gchar *name, gint x_resolution, gint y_resolution)
 {
     CheeseCamera      *camera;
     CheeseVideoFormat format = { x_resolution, y_resolution };
 
-    camera = g_object_new (CHEESE_TYPE_CAMERA, "video-texture", video_texture,
+    camera = g_object_new (CHEESE_TYPE_CAMERA,
                            "format", &format, NULL);
 
     if (name)
@@ -1546,14 +1532,6 @@ cheese_camera_set_device (CheeseCamera *camera, CheeseCameraDevice *device)
   g_object_set (camera, "device", device, NULL);
 }
 
-static void
-cheese_camera_size_change_cb (ClutterGstContent *content, gint width, gint height, CheeseCamera* camera)
-{
-  CheeseCameraPrivate *priv = cheese_camera_get_instance_private (camera);
-
-  clutter_actor_set_size (priv->video_texture, width, height);
-}
-
 /**
  * cheese_camera_setup:
  * @camera: a #CheeseCamera
@@ -1567,7 +1545,7 @@ cheese_camera_setup (CheeseCamera *camera, CheeseCameraDevice *device, GError **
 {
   CheeseCameraPrivate *priv;
   GError  *tmp_error = NULL;
-  GstElement *video_sink;
+  GstElement *video_sink, *glsinkbin;
 
   g_return_if_fail (error == NULL || *error == NULL);
   g_return_if_fail (CHEESE_IS_CAMERA (camera));
@@ -1614,18 +1592,14 @@ cheese_camera_setup (CheeseCamera *camera, CheeseCameraDevice *device, GError **
   }
   g_object_set (priv->camerabin, "camera-source", priv->camera_source, NULL);
 
-  /* Create a clutter-gst sink and set it as camerabin sink*/
+  /* Create a GTK GL sink and set it as camerabin sink*/
 
-  video_sink = GST_ELEMENT (clutter_gst_video_sink_new ());
-  g_object_set (G_OBJECT (priv->video_texture),
-                "content", g_object_new (CLUTTER_GST_TYPE_CONTENT,
-                                         "sink", video_sink,
-                                         NULL),
-                NULL);
-  g_signal_connect (G_OBJECT (clutter_actor_get_content (priv->video_texture)),
-                    "size-change", G_CALLBACK(cheese_camera_size_change_cb), camera);
+  video_sink = gst_element_factory_make ("gtkglsink", "gtkglsink");
+  glsinkbin = gst_element_factory_make ("glsinkbin", "glsinkbin");
+  g_object_set (glsinkbin, "sink", video_sink, NULL);
+  g_object_get (video_sink, "widget", &priv->video_widget, NULL);
 
-  g_object_set (G_OBJECT (priv->camerabin), "viewfinder-sink", video_sink, NULL);
+  g_object_set (G_OBJECT (priv->camerabin), "viewfinder-sink", glsinkbin, NULL);
 
   /* Set flags to enable conversions*/
 
diff --git a/libcheese/cheese-camera.h b/libcheese/cheese-camera.h
index 6756dff7..b87d085c 100644
--- a/libcheese/cheese-camera.h
+++ b/libcheese/cheese-camera.h
@@ -25,10 +25,9 @@
 #define __CHEESE_CAMERA_H__
 
 #include <glib-object.h>
-#include <clutter/clutter.h>
 #include <cheese-camera-device.h>
 #include <cheese-effect.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
@@ -95,8 +94,7 @@ typedef enum
 } CheeseCameraError;
 
 GType         cheese_camera_get_type (void);
-CheeseCamera *cheese_camera_new (ClutterActor *video_texture,
-                                 const gchar  *name,
+CheeseCamera *cheese_camera_new (const gchar  *name,
                                  gint          x_resolution,
                                  gint          y_resolution);
 
@@ -107,7 +105,7 @@ void                     cheese_camera_stop (CheeseCamera *camera);
 void                     cheese_camera_set_effect (CheeseCamera *camera, CheeseEffect *effect);
 void                     cheese_camera_connect_effect_texture (CheeseCamera *camera,
                                                                CheeseEffect *effect,
-                                                               ClutterActor *texture);
+                                                               GtkContainer *container);
 void                cheese_camera_start_video_recording (CheeseCamera *camera, const gchar *filename);
 void                cheese_camera_stop_video_recording (CheeseCamera *camera);
 gboolean            cheese_camera_take_photo (CheeseCamera *camera, const gchar *filename);
diff --git a/libcheese/cheese-gtk.c b/libcheese/cheese-gtk.c
index 08cca76e..faea7291 100644
--- a/libcheese/cheese-gtk.c
+++ b/libcheese/cheese-gtk.c
@@ -21,7 +21,6 @@
 #ifdef GDK_WINDOWING_X11
   #include <X11/Xlib.h>
 #endif
-#include <clutter-gtk/clutter-gtk.h>
 
 #include "cheese-gtk.h"
 #include "cheese.h"
@@ -41,7 +40,7 @@
  * @argc: (allow-none): pointer to the argument list count
  * @argv: (allow-none): pointer to the argument list vector
  *
- * Initialize libcheese-gtk, by initializing Clutter, GStreamer and GTK+. This
+ * Initialize libcheese-gtk, by initializing GStreamer and GTK+. This
  * automatically calls cheese_init(), initializing libcheese.
  *
  * Returns: %TRUE if the initialization was successful, %FALSE otherwise
@@ -49,17 +48,11 @@
 gboolean
 cheese_gtk_init (int *argc, char ***argv)
 {
-    ClutterInitError error;
-
 #ifdef GDK_WINDOWING_X11
     XInitThreads ();
 #endif
 
-    error = gtk_clutter_init (argc, argv);
-
-    if (error != CLUTTER_INIT_SUCCESS)
-        return FALSE;
-
+    gtk_init (argc, argv);
     if (!cheese_init (argc, argv))
         return FALSE;
 
diff --git a/libcheese/cheese-widget.c b/libcheese/cheese-widget.c
index be697a7b..996cd41c 100644
--- a/libcheese/cheese-widget.c
+++ b/libcheese/cheese-widget.c
@@ -20,13 +20,11 @@
 #include "config.h"
 
 #include <glib/gi18n-lib.h>
-#include <clutter-gst/clutter-gst.h>
 
 #include "cheese-widget.h"
 #include "cheese-widget-private.h"
 #include "cheese-camera.h"
 #include "cheese-enums.h"
-#include "totem-aspect-frame.h"
 
 /**
  * SECTION:cheese-widget
@@ -70,7 +68,6 @@ typedef struct
 {
   GtkWidget *spinner;
   GtkWidget *screen;
-  ClutterActor *texture;
   GtkWidget *problem;
   GSettings *settings;
   CheeseCamera *webcam;
@@ -201,8 +198,6 @@ cheese_widget_init (CheeseWidget *widget)
 {
     CheeseWidgetPrivate *priv = cheese_widget_get_instance_private (widget);
   GtkWidget           *box;
-  ClutterActor        *stage, *frame;
-  ClutterColor black = { 0x00, 0x00, 0x00, 0xff };
 
   priv->state = CHEESE_WIDGET_STATE_NONE;
   priv->error = NULL;
@@ -223,20 +218,8 @@ cheese_widget_init (CheeseWidget *widget)
                             box, gtk_label_new ("spinner"));
 
   /* Webcam page */
-  priv->screen = gtk_clutter_embed_new ();
-  gtk_widget_set_size_request (priv->screen, 460, 345);
-  stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (priv->screen));
-  clutter_actor_set_background_color (stage, &black);
-  frame = totem_aspect_frame_new ();
-
-  priv->texture = clutter_actor_new ();
-  totem_aspect_frame_set_child (TOTEM_ASPECT_FRAME (frame), priv->texture);
-
-  clutter_actor_set_layout_manager (stage, clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FILL, 
CLUTTER_BIN_ALIGNMENT_FILL));
-  clutter_actor_add_child (stage, frame);
-
+  priv->screen = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
   gtk_widget_show (priv->screen);
-  clutter_actor_show (priv->texture);
   gtk_notebook_append_page (GTK_NOTEBOOK (widget),
                             priv->screen, gtk_label_new ("webcam"));
 
@@ -309,18 +292,22 @@ setup_camera (CheeseWidget *widget)
     gchar *webcam_device;
     gint x_resolution;
     gint y_resolution;
+    GtkWidget *video_widget;
 
     x_resolution = g_settings_get_int (priv->settings, "photo-x-resolution");
     y_resolution = g_settings_get_int (priv->settings, "photo-y-resolution");
     webcam_device = g_settings_get_string (priv->settings, "camera");
 
-    priv->webcam = cheese_camera_new (priv->texture,
-                                      webcam_device, x_resolution,
+    priv->webcam = cheese_camera_new (webcam_device,
+                                      x_resolution,
                                       y_resolution);
 
     g_free (webcam_device);
 
     cheese_camera_setup (priv->webcam, NULL, &priv->error);
+    g_object_get (G_OBJECT (priv->webcam), "widget", &video_widget, NULL);
+    gtk_container_add (GTK_CONTAINER (priv->screen), video_widget);
+    gtk_widget_show (video_widget);
 
     gtk_spinner_stop (GTK_SPINNER (priv->spinner));
 
diff --git a/libcheese/cheese-widget.h b/libcheese/cheese-widget.h
index e8923877..3aa0ad8c 100644
--- a/libcheese/cheese-widget.h
+++ b/libcheese/cheese-widget.h
@@ -22,8 +22,6 @@
 
 #include <glib-object.h>
 #include <gtk/gtk.h>
-#include <clutter/clutter.h>
-#include <clutter-gtk/clutter-gtk.h>
 
 G_BEGIN_DECLS
 
diff --git a/libcheese/cheese.c b/libcheese/cheese.c
index 0e2e33e2..257d6f59 100644
--- a/libcheese/cheese.c
+++ b/libcheese/cheese.c
@@ -17,7 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <clutter-gst/clutter-gst.h>
+#include <gst/gst.h>
 
 #include "cheese.h"
 
@@ -36,19 +36,14 @@
  * @argc: (allow-none): pointer to the argument list count
  * @argv: (allow-none): pointer to the argument list vector
  *
- * Initialize libcheese, by initializing Clutter and GStreamer.
+ * Initialize libcheese, by initializing GStreamer.
  *
  * Returns: %TRUE if the initialization was successful, %FALSE otherwise
  */
 gboolean
 cheese_init (int *argc, char ***argv)
 {
-    ClutterInitError error;
-
-    error = clutter_gst_init (argc, argv);
-
-    if (error != CLUTTER_INIT_SUCCESS)
-        return FALSE;
+    gst_init (argc, argv);
 
     return TRUE;
 }
diff --git a/libcheese/meson.build b/libcheese/meson.build
index 4265f878..eae80758 100644
--- a/libcheese/meson.build
+++ b/libcheese/meson.build
@@ -33,15 +33,15 @@ sources = files(
 )
 
 deps = [
-  clutter_dep,
   gdk_pixbuf_dep,
   gio_dep,
   glib_dep,
+  gtk_dep,
   gstreamer_dep,
 ]
 
 private_deps = [
-  clutter_gst_dep,
+  gstreamer_dep,
   gstreamer_pbutils_dep,
   gstreamer_plugins_bad_dep,
   x11_dep,
@@ -78,7 +78,6 @@ pkg.generate(
 # GObject Introspection
 if enable_gir
   incs = [
-    'Clutter-1.0',
     'GdkPixbuf-2.0',
     'Gst-1.0',
   ]
@@ -113,12 +112,11 @@ enum_sources = gnome.mkenums_simple(
 )
 
 deps = [
-  clutter_gtk_dep,
   gtk_dep,
 ]
 
 private_deps = [
-  clutter_gst_dep,
+  gstreamer_dep,
   libcanberra_gtk3_dep,
   m_dep,
   x11_dep,
diff --git a/tests/cheese-test-camera.c b/tests/cheese-test-camera.c
index fd058f0d..5bb64209 100644
--- a/tests/cheese-test-camera.c
+++ b/tests/cheese-test-camera.c
@@ -5,7 +5,6 @@
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
-#include <clutter-gtk/clutter-gtk.h>
 #include <gst/gst.h>
 #include "cheese-camera.h"
 #include "cheese.h"
@@ -34,38 +33,25 @@ main (int argc, char **argv)
   GtkWidget *window;
   GtkWidget *screen;
   CheeseCamera *camera;
-  ClutterActor *stage;
-  ClutterActor *texture;
 
   bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALEDIR);
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
   textdomain (GETTEXT_PACKAGE);
 
-  if (gtk_clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
-    return EXIT_FAILURE;
-
   if (!cheese_init (&argc, &argv))
     return EXIT_FAILURE;
+  gtk_init (&argc, &argv);
 
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
   g_signal_connect (G_OBJECT (window), "delete-event",
                     G_CALLBACK (delete_callback), NULL);
 
-  screen = gtk_clutter_embed_new ();
-  stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (screen));
-  texture = clutter_actor_new ();
-
-  clutter_actor_set_size (texture, 400, 300);
-  clutter_actor_add_child (stage, texture);
-
-  gtk_widget_show (screen);
-  clutter_actor_show (texture);
-
-  camera = cheese_camera_new (texture, NULL, 640, 480);
-
+  camera = cheese_camera_new (NULL, 640, 480);
   cheese_camera_setup (camera, NULL, NULL);
 
+  g_object_get (G_OBJECT (camera), "widget", &screen, NULL);
+  gtk_widget_show (screen);
   gtk_container_add (GTK_CONTAINER (window), screen);
 
   gtk_widget_show_all (window);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]