[pinpoint] clutteR: add a "camera" background type



commit cb1a1594f6853273833c44a5a4dd58869d765329
Author: Damien Lespiau <damien lespiau intel com>
Date:   Sat Jul 23 13:11:59 2011 +0100

    clutteR: add a "camera" background type
    
    It's awesome, it lets you put pull your webcam into your presentation.

 pinpoint.c   |   23 +++++++-
 pinpoint.h   |    9 +++
 pp-cairo.c   |    3 +
 pp-clutter.c |  180 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 190 insertions(+), 25 deletions(-)
---
diff --git a/pinpoint.c b/pinpoint.c
index 052a109..4d15d8d 100644
--- a/pinpoint.c
+++ b/pinpoint.c
@@ -74,6 +74,10 @@ static PinPointPoint pin_default_point = {
   .transition = NULL,
 
   .command = NULL,
+
+  .camera_framerate = 0,                    /* auto */
+  .camera_resolution = {0, 0},              /* auto */
+
   .data = NULL,
 };
 
@@ -392,6 +396,14 @@ void     pp_parse_slides  (PinPointRenderer *renderer,
  */
 
 static void
+parse_resolution (PPResolution *r,
+                  const gchar  *str)
+{
+  if (sscanf (str, "%dx%d", &r->width, &r->height) != 2)
+    r->width = r->height = 0;
+}
+
+static void
 parse_setting (PinPointPoint *point,
                const char    *setting)
 {
@@ -405,7 +417,9 @@ parse_setting (PinPointPoint *point,
 #define IF_PREFIX(prefix) } else if (g_str_has_prefix (setting, prefix)) {
 #define IF_EQUAL(string) } else if (g_str_equal (setting, string)) {
 #define STRING  g_intern_string (strchr (setting, '=') + 1)
+#define INT     atoi (strchr (setting, '=') + 1)
 #define FLOAT   g_ascii_strtod (strchr (setting, '=') + 1, NULL)
+#define RESOLUTION(r) parse_resolution (&r, strchr (setting, '=') + 1)
 #define ENUM(r,t,s) \
   do { \
       int _i; \
@@ -426,6 +440,8 @@ parse_setting (PinPointPoint *point,
   IF_PREFIX("duration=")   point->duration = FLOAT;
   IF_PREFIX("command=")    point->command = STRING;
   IF_PREFIX("transition=") point->transition = STRING;
+  IF_PREFIX("camera-framerate=")  point->camera_framerate = INT;
+  IF_PREFIX("camera-resolution=") RESOLUTION (point->camera_resolution);
   IF_EQUAL("fill")         point->bg_scale = PP_BG_FILL;
   IF_EQUAL("fit")          point->bg_scale = PP_BG_FIT;
   IF_EQUAL("stretch")      point->bg_scale = PP_BG_STRETCH;
@@ -452,7 +468,9 @@ parse_setting (PinPointPoint *point,
 #undef IF_EQUAL
 #undef FLOAT
 #undef STRING
+#undef INT
 #undef ENUM
+#undef RESOLUTION
 }
 
 static void
@@ -775,7 +793,10 @@ pp_parse_slides (PinPointRenderer *renderer,
                             filename[i] = tolower(filename[i]);
                             i++;
                           }
-                        if (str_has_video_suffix (filename))
+
+                        if (strcmp (filename, "camera") == 0)
+                          point->bg_type = PP_BG_CAMERA;
+                        else if (str_has_video_suffix (filename))
                           point->bg_type = PP_BG_VIDEO;
                         else if (g_str_has_suffix (filename, ".svg"))
                           point->bg_type = PP_BG_SVG;
diff --git a/pinpoint.h b/pinpoint.h
index 3508e95..2e7ecae 100644
--- a/pinpoint.h
+++ b/pinpoint.h
@@ -47,6 +47,7 @@ typedef enum
   PP_BG_COLOR,
   PP_BG_IMAGE,
   PP_BG_VIDEO,
+  PP_BG_CAMERA,
   PP_BG_SVG
 } PPBackgroundType;
 
@@ -58,6 +59,11 @@ typedef enum
   PP_BG_STRETCH
 } PPBackgroundScale;
 
+typedef struct
+{
+  gint width, height;
+} PPResolution;
+
 #define PINPOINT_RENDERER(renderer) ((PinPointRenderer *) renderer)
 
 struct _PinPointRenderer
@@ -103,6 +109,9 @@ struct _PinPointPoint
 
   const char        *command;
 
+  gint              camera_framerate;
+  PPResolution      camera_resolution;
+
   void              *data;            /* the renderer can attach data here */
 };
 
diff --git a/pp-cairo.c b/pp-cairo.c
index 167a9f7..de58e48 100644
--- a/pp-cairo.c
+++ b/pp-cairo.c
@@ -426,6 +426,9 @@ _cairo_render_background (CairoRenderer *renderer,
       }
 #endif
       break;
+    case PP_BG_CAMERA:
+      /* silently ignore camera backgrounds */
+      break;
     default:
       g_assert_not_reached();
     }
diff --git a/pp-clutter.c b/pp-clutter.c
index fa21d63..a7126bf 100644
--- a/pp-clutter.c
+++ b/pp-clutter.c
@@ -156,6 +156,10 @@ typedef struct
   ClutterActor     *midground;
   ClutterActor     *foreground;
   ClutterActor     *shading;
+
+#ifdef USE_CLUTTER_GST
+  GstElement       *pipeline; /* used for the custom camera pipeline */
+#endif
 } ClutterPointData;
 
 #define CLUTTER_RENDERER(renderer)  ((ClutterRenderer *) renderer)
@@ -175,9 +179,39 @@ static void     file_changed  (GFileMonitor     *monitor,
 static void     stage_resized (ClutterActor     *actor,
                                GParamSpec       *pspec,
                                ClutterRenderer  *renderer);
-static gboolean key_pressed   (ClutterActor     *actor,
-                               ClutterEvent     *event,
-                               ClutterRenderer  *renderer);
+static gboolean key_pressed (ClutterActor    *actor,
+                             ClutterEvent    *event,
+                             ClutterRenderer *renderer);
+
+static void
+pp_clutter_render_adjust_background (ClutterRenderer *renderer,
+                                     PinPointPoint   *point)
+{
+  float bg_x, bg_y, bg_width, bg_height, bg_scale_x, bg_scale_y;
+  ClutterPointData *data = point->data;
+
+  if (!data)
+    return;
+
+  if (CLUTTER_IS_RECTANGLE (data->background))
+    {
+      clutter_actor_get_size (renderer->stage, &bg_width, &bg_height);
+      clutter_actor_set_size (data->background, bg_width, bg_height);
+    }
+  else
+    {
+      clutter_actor_get_size (data->background, &bg_width, &bg_height);
+    }
+
+  pp_get_background_position_scale (point,
+                                    clutter_actor_get_width (renderer->stage),
+                                    clutter_actor_get_height (renderer->stage),
+                                    bg_width, bg_height,
+                                    &bg_x, &bg_y, &bg_scale_x, &bg_scale_y);
+
+  clutter_actor_set_scale (data->background, bg_scale_x, bg_scale_y);
+  clutter_actor_set_position (data->background, bg_x, bg_y);
+}
 
 #ifdef HAVE_CLUTTER_X11
 static void pp_set_fullscreen (ClutterStage  *stage,
@@ -870,6 +904,111 @@ _clutter_get_texture (ClutterRenderer *renderer,
   return clutter_clone_new (source);
 }
 
+#if USE_CLUTTER_GST
+static void
+on_size_changed (ClutterActor *texture,
+                 gint          width,
+                 gint          height,
+                 gpointer      user_data)
+{
+  PinPointRenderer *pp_renderer = user_data;
+  ClutterRenderer *renderer = CLUTTER_RENDERER (pp_renderer);
+  PinPointPoint *point;
+  ClutterPointData *data;
+
+  point = pp_slidep->data;
+  if (!point)
+    return;
+
+  data = point->data;
+
+  if (data->background != texture)
+    {
+      g_warning ("size changed but not current background ?!");
+      return;
+    }
+
+  clutter_actor_set_size (texture, width, height);
+  pp_clutter_render_adjust_background (renderer, point);
+}
+
+static gboolean
+setup_camera (PinPointRenderer *renderer,
+              PinPointPoint    *point)
+{
+  /* These are static to be able to share the texture and the pipeline between
+   * all the slides using the camera */
+  static ClutterActor *texture = NULL;
+  static GstElement   *pipeline = NULL;
+
+  ClutterPointData *data = point->data;
+  GstElement       *src;
+  GstElement       *capsfilter;
+  GstElement       *sink;
+  GstCaps          *caps;
+  gboolean          result;
+
+  if (texture)
+    {
+      data->background = clutter_clone_new (texture);
+      data->pipeline = pipeline;
+
+      return TRUE;
+    }
+
+  texture = g_object_new (CLUTTER_TYPE_TEXTURE, "disable-slicing", TRUE, NULL);
+
+  g_signal_connect (CLUTTER_TEXTURE (texture),
+                    "size-change",
+                    G_CALLBACK (on_size_changed), renderer);
+
+  /* Set up pipeline */
+  pipeline = gst_pipeline_new (NULL);
+
+  src = gst_element_factory_make ("v4l2src", NULL);
+  capsfilter = gst_element_factory_make ("capsfilter", NULL);
+  sink = clutter_gst_video_sink_new (CLUTTER_TEXTURE (texture));
+
+  /* make videotestsrc spit the format we want */
+  caps = gst_caps_new_simple ("video/x-raw-yuv", NULL);
+
+  if (point->camera_framerate)
+    {
+      gst_caps_set_simple (caps,
+                           "framerate", GST_TYPE_FRACTION,
+                           point->camera_framerate, 1,
+                           NULL);
+    }
+
+#define W (point->camera_resolution.width)
+#define H (point->camera_resolution.height)
+  if (W != 0 && H != 0)
+    {
+      gst_caps_set_simple (caps,
+                           "width", G_TYPE_INT, W,
+                           "height", G_TYPE_INT, H,
+                           NULL);
+    }
+#undef W
+#undef H
+
+  g_object_set (capsfilter, "caps", caps, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, capsfilter, sink, NULL);
+  result = gst_element_link_many (src, capsfilter, sink, NULL);
+  if (result == FALSE)
+    {
+      g_critical("Could not link elements");
+      gst_object_unref (pipeline);
+      return FALSE;
+    }
+
+  data->background = texture;
+  data->pipeline = pipeline;
+
+  return TRUE;
+}
+#endif
 
 static gboolean
 clutter_renderer_make_point (PinPointRenderer *pp_renderer,
@@ -917,6 +1056,11 @@ clutter_renderer_make_point (PinPointRenderer *pp_renderer,
       ret = TRUE;
 #endif
       break;
+    case PP_BG_CAMERA:
+#ifdef USE_CLUTTER_GST
+      ret = setup_camera (pp_renderer, point);
+#endif
+      break;
     case PP_BG_SVG:
 #ifdef USE_DAX
       {
@@ -1127,6 +1271,10 @@ static void leave_slide (ClutterRenderer *renderer,
                                  "opacity",      0x0,
                                  NULL);
 #ifdef USE_CLUTTER_GST
+          if (point->bg_type == PP_BG_CAMERA)
+            {
+              gst_element_set_state (data->pipeline, GST_STATE_PAUSED);
+            }
           if (CLUTTER_GST_IS_VIDEO_TEXTURE (data->background))
             {
               clutter_media_set_playing (CLUTTER_MEDIA (data->background),
@@ -1610,30 +1758,14 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
 
   if (data->background)
     {
-      float bg_x, bg_y, bg_width, bg_height, bg_scale_x, bg_scale_y;
+      pp_clutter_render_adjust_background (renderer, point);
 
-      if (CLUTTER_IS_RECTANGLE (data->background))
-        {
-          clutter_actor_get_size (renderer->stage, &bg_width, &bg_height);
-          clutter_actor_set_size (data->background, bg_width, bg_height);
-        }
-      else
+#ifdef USE_CLUTTER_GST
+      if (point->bg_type == PP_BG_CAMERA)
         {
-          clutter_actor_get_size (data->background, &bg_width, &bg_height);
+          gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
         }
-
-      pp_get_background_position_scale (
-          point,
-          clutter_actor_get_width (renderer->stage),
-          clutter_actor_get_height (renderer->stage),
-          bg_width, bg_height,
-          &bg_x, &bg_y, &bg_scale_x, &bg_scale_y);
-
-      clutter_actor_set_scale (data->background, bg_scale_x, bg_scale_y);
-      clutter_actor_set_position (data->background, bg_x, bg_y);
-
-#ifdef USE_CLUTTER_GST
-      if (CLUTTER_GST_IS_VIDEO_TEXTURE (data->background))
+      else if (CLUTTER_GST_IS_VIDEO_TEXTURE (data->background))
         {
           clutter_media_set_progress (CLUTTER_MEDIA (data->background), 0.0);
           clutter_media_set_playing (CLUTTER_MEDIA (data->background), TRUE);



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