[longomatch/livecapture2: 24/31] Add support to take screenshots from the live source



commit 9868783f132413b676ca6a6cd4609d7c3cc4b2b3
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date:   Sat May 1 11:18:07 2010 +0200

    Add support to take screenshots from the live source

 CesarPlayer/Capturer/FakeCapturer.cs      |    4 +
 CesarPlayer/Capturer/GstCameraCapturer.cs |   17 +++
 CesarPlayer/Capturer/ICapturer.cs         |    5 +
 CesarPlayer/Gui/CapturerBin.cs            |   29 +++++
 LongoMatch/Handlers/EventsManager.cs      |    8 +-
 libcesarplayer/src/gst-camera-capturer.c  |  162 ++++++++++++++++++++++++++++-
 libcesarplayer/src/gst-camera-capturer.h  |    2 +
 7 files changed, 224 insertions(+), 3 deletions(-)
---
diff --git a/CesarPlayer/Capturer/FakeCapturer.cs b/CesarPlayer/Capturer/FakeCapturer.cs
index 92fe24f..f074bb2 100644
--- a/CesarPlayer/Capturer/FakeCapturer.cs
+++ b/CesarPlayer/Capturer/FakeCapturer.cs
@@ -19,6 +19,7 @@
 using System;
 using Mono.Unix;
 using GLib;
+using Gdk;
 using LongoMatch.Video.Handlers;
 
 namespace LongoMatch.Video.Capturer
@@ -89,6 +90,9 @@ namespace LongoMatch.Video.Capturer
 			set {}
 		}		
 		
+		public Pixbuf CurrentFrame {
+			get {return null;}
+		}
 		public bool SetVideoEncoder(LongoMatch.Video.Capturer.GccVideoEncoderType type){
 			return true;
 		}
diff --git a/CesarPlayer/Capturer/GstCameraCapturer.cs b/CesarPlayer/Capturer/GstCameraCapturer.cs
index a6f8461..bb41690 100644
--- a/CesarPlayer/Capturer/GstCameraCapturer.cs
+++ b/CesarPlayer/Capturer/GstCameraCapturer.cs
@@ -365,6 +365,23 @@ namespace LongoMatch.Video.Capturer {
 		}
 		
 		
+		[DllImport("libcesarplayer.dll")]
+		static extern IntPtr gst_camera_capturer_get_current_frame(IntPtr raw);
+		[DllImport("libcesarplayer.dll")]
+		static extern IntPtr gst_camera_capturer_unref_pixbuf(IntPtr raw);
+		
+		public Gdk.Pixbuf CurrentFrame {
+			get {
+				IntPtr raw_ret = gst_camera_capturer_get_current_frame (Handle);
+				Gdk.Pixbuf p = GLib.Object.GetObject (raw_ret) as Gdk.Pixbuf;
+				/* The refcount for p is now 2. We need to decrease the counter to 1
+				 * so that p.Dipose() sets it to 0 and triggers the pixbuf destroy function
+				 * that frees the associated data*/ 
+				gst_camera_capturer_unref_pixbuf (raw_ret);
+				return p;
+			}
+		}		
+		
 		static GstCameraCapturer ()
 		{
 			LongoMatch.GtkSharp.Capturer.ObjectManager.Initialize ();
diff --git a/CesarPlayer/Capturer/ICapturer.cs b/CesarPlayer/Capturer/ICapturer.cs
index 7b8ea58..298d7a7 100644
--- a/CesarPlayer/Capturer/ICapturer.cs
+++ b/CesarPlayer/Capturer/ICapturer.cs
@@ -20,6 +20,7 @@
 
 using System;
 using LongoMatch.Video.Handlers;
+using Gdk;
 
 namespace LongoMatch.Video.Capturer
 {
@@ -58,6 +59,10 @@ namespace LongoMatch.Video.Capturer
 			get ;
 		}
 		
+		Pixbuf CurrentFrame {
+			get;
+		}
+		
 		bool SetVideoEncoder(LongoMatch.Video.Capturer.GccVideoEncoderType type);
 		
 		bool SetAudioEncoder(LongoMatch.Video.Capturer.GccAudioEncoderType type);
diff --git a/CesarPlayer/Gui/CapturerBin.cs b/CesarPlayer/Gui/CapturerBin.cs
index af3d2bf..f47307b 100644
--- a/CesarPlayer/Gui/CapturerBin.cs
+++ b/CesarPlayer/Gui/CapturerBin.cs
@@ -46,6 +46,7 @@ namespace LongoMatch.Gui
 		private GccAudioEncoderType audioEncoder;
 		private GccVideoMuxerType videoMuxer;
 		private string outputFile;
+		private const int THUMBNAIL_MAX_WIDTH = 100;		
 		
 		ICapturer capturer;
 		
@@ -170,6 +171,34 @@ namespace LongoMatch.Gui
 			capturer.Close();
 		}
 		
+		public Pixbuf CurrentMiniatureFrame {
+			get {
+				int h, w;
+				double rate;
+				Pixbuf scaled_pix;
+				Pixbuf pix = capturer.CurrentFrame;
+				
+				if (pix == null)
+					return null;
+				
+				w = pix.Width;
+				h = pix.Height;
+				rate = (double)w / (double)h;
+				
+				if (h > w) {
+					w = (int)(THUMBNAIL_MAX_WIDTH * rate);
+					h = THUMBNAIL_MAX_WIDTH;
+				} else {
+					h = (int)(THUMBNAIL_MAX_WIDTH / rate);
+					w = THUMBNAIL_MAX_WIDTH;
+				}
+				scaled_pix = pix.ScaleSimple (w, h, Gdk.InterpType.Bilinear);
+				pix.Dispose();
+					
+				return scaled_pix;				                       
+			}
+		}
+		
 		public void SetVideoEncoder(GccVideoEncoderType type){
 			capturer.SetVideoEncoder(type);
 			videoEncoder = type;
diff --git a/LongoMatch/Handlers/EventsManager.cs b/LongoMatch/Handlers/EventsManager.cs
index 5dcfde9..1b4bb33 100644
--- a/LongoMatch/Handlers/EventsManager.cs
+++ b/LongoMatch/Handlers/EventsManager.cs
@@ -179,8 +179,12 @@ namespace LongoMatch
 			Pixbuf miniature;
 			MediaTimeNode tn;
 		
-			miniature = projectType == ProjectType.FakeCaptureProject ?
-				null : player.CurrentMiniatureFrame;
+			if (projectType == ProjectType.CaptureProject)
+				miniature = capturer.CurrentMiniatureFrame;
+			else if (projectType == ProjectType.FileProject)
+				miniature = player.CurrentMiniatureFrame;
+			else 
+				miniature = null;
 			tn = openedProject.AddTimeNode(section, start, stop,miniature);
 			treewidget.AddPlay(tn,section);
 			tagsTreeWidget.AddPlay(tn);
diff --git a/libcesarplayer/src/gst-camera-capturer.c b/libcesarplayer/src/gst-camera-capturer.c
index 44897ba..3115377 100644
--- a/libcesarplayer/src/gst-camera-capturer.c
+++ b/libcesarplayer/src/gst-camera-capturer.c
@@ -32,7 +32,7 @@
 
 #include "gst-camera-capturer.h"
 #include "gstvideowidget.h"
-
+#include "gstscreenshot.h"
 
 /*Default video source*/
 #ifdef WIN32
@@ -97,6 +97,8 @@ struct GstCameraCapturerPrivate
   gboolean media_has_video;
   gboolean media_has_audio;
 
+  /* Snapshots */
+  GstBuffer *last_buffer;
 
   /*GStreamer elements */
   GstElement *main_pipeline;
@@ -164,6 +166,7 @@ gst_camera_capturer_init (GstCameraCapturer * object)
   priv->output_fps_d = 1;
   priv->audio_bitrate = 128;
   priv->video_bitrate = 5000;
+  priv->last_buffer = NULL;
 
   priv->lock = g_mutex_new ();
 }
@@ -192,6 +195,9 @@ gst_camera_capturer_finalize (GObject * object)
     gcc->priv->interface_update_id = 0;
   }
 
+  if (gcc->priv->last_buffer != NULL)
+    gst_buffer_unref (gcc->priv->last_buffer);
+
   if (gcc->priv->main_pipeline != NULL
       && GST_IS_ELEMENT (gcc->priv->main_pipeline)) {
     gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
@@ -807,10 +813,28 @@ gst_camera_capturer_error_quark (void)
   return q;
 }
 
+gboolean
+gst_camera_capture_videosrc_buffer_probe (GstPad * pad, GstBuffer * buf,
+    gpointer data)
+{
+  GstCameraCapturer *gcc = GST_CAMERA_CAPTURER(data);
+
+  if (gcc->priv->last_buffer){
+    gst_buffer_unref(gcc->priv->last_buffer);
+    gcc->priv->last_buffer = NULL;
+  }
+
+  gst_buffer_ref(buf);
+  gcc->priv->last_buffer = buf;
+
+  return TRUE;
+}
+
 GstCameraCapturer *
 gst_camera_capturer_new (gchar * filename, GError ** err)
 {
   GstCameraCapturer *gcc = NULL;
+  GstPad *videosrcpad;
   gchar * plugin;
 
   gcc = g_object_new (GST_TYPE_CAMERA_CAPTURER, NULL);
@@ -874,6 +898,10 @@ gst_camera_capturer_new (gchar * filename, GError ** err)
       g_signal_connect (gcc->priv->bus, "sync-message::element",
       G_CALLBACK (gcc_element_msg_sync), gcc);
 
+  /* Install pad probe to store the last buffer */
+  videosrcpad = gst_element_get_pad (gcc->priv->videosrc, "src");
+  gst_pad_add_buffer_probe (videosrcpad, 
+    G_CALLBACK (gst_camera_capture_videosrc_buffer_probe), gcc);
   return gcc;
 
 /* Missing plugin */
@@ -1256,3 +1284,135 @@ gst_camera_capturer_enum_audio_devices(void)
   return gst_camera_capturer_enum_devices(AUDIOSRC); 
 }
 
+gboolean
+gst_camera_capturer_can_get_frames (GstCameraCapturer * gcc, GError ** error)
+{
+  g_return_val_if_fail (gcc != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+  g_return_val_if_fail (GST_IS_ELEMENT (gcc->priv->camerabin), FALSE);
+
+  /* check for video */
+  if (!gcc->priv->media_has_video)
+    {
+      g_set_error_literal (error, GCC_ERROR, GCC_ERROR_GENERIC,
+			   "Media contains no supported video streams.");
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static void
+destroy_pixbuf (guchar * pix, gpointer data)
+{
+  gst_buffer_unref (GST_BUFFER (data));
+}
+
+void
+gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf)
+{
+  gdk_pixbuf_unref (pixbuf);
+}
+
+GdkPixbuf *
+gst_camera_capturer_get_current_frame (GstCameraCapturer * gcc)
+{
+  GstStructure *s;
+  GdkPixbuf *pixbuf;
+  GstBuffer *last_buffer;
+  GstBuffer *buf;
+  GstCaps *to_caps;
+  gint outwidth = 0;
+  gint outheight = 0;
+
+  g_return_val_if_fail (gcc != NULL, NULL);
+  g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), NULL);
+  g_return_val_if_fail (GST_IS_ELEMENT (gcc->priv->camerabin), NULL);
+
+  gst_element_get_state (gcc->priv->camerabin, NULL, NULL, -1);
+
+  /* no video info */
+  if (!gcc->priv->video_width || !gcc->priv->video_height)
+    {
+      GST_DEBUG ("Could not take screenshot: %s", "no video info");
+      g_warning ("Could not take screenshot: %s", "no video info");
+      return NULL;
+    }
+
+  /* get frame */
+  last_buffer = gcc->priv->last_buffer;
+  gst_buffer_ref (last_buffer);
+
+  if (!last_buffer) {
+    GST_DEBUG ("Could not take screenshot: %s", "no last video frame");
+    g_warning ("Could not take screenshot: %s", "no last video frame");
+    return NULL;
+  }
+
+  if (GST_BUFFER_CAPS (last_buffer) == NULL) {
+    GST_DEBUG ("Could not take screenshot: %s", "no caps on buffer");
+    g_warning ("Could not take screenshot: %s", "no caps on buffer");
+    return NULL;
+  }
+
+  /* convert to our desired format (RGB24) */
+  to_caps = gst_caps_new_simple ("video/x-raw-rgb",
+				 "bpp", G_TYPE_INT, 24,
+				 "depth", G_TYPE_INT, 24,
+				 /* Note: we don't ask for a specific width/height here, so that
+				  * videoscale can adjust dimensions from a non-1/1 pixel aspect
+				  * ratio to a 1/1 pixel-aspect-ratio */
+				 "pixel-aspect-ratio", GST_TYPE_FRACTION, 1,
+				 1, "endianness", G_TYPE_INT, G_BIG_ENDIAN,
+				 "red_mask", G_TYPE_INT, 0xff0000,
+				 "green_mask", G_TYPE_INT, 0x00ff00,
+				 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
+
+  if (gcc->priv->video_fps_n > 0 && gcc->priv->video_fps_d > 0)
+    {
+      gst_caps_set_simple (to_caps, "framerate", GST_TYPE_FRACTION,
+			   gcc->priv->video_fps_n, gcc->priv->video_fps_d,
+			   NULL);
+    }
+
+  GST_DEBUG ("frame caps: %" GST_PTR_FORMAT, 
+      GST_BUFFER_CAPS (gcc->priv->last_buffer));
+  GST_DEBUG ("pixbuf caps: %" GST_PTR_FORMAT, to_caps);
+
+  /* bvw_frame_conv_convert () takes ownership of the buffer passed */
+  buf = bvw_frame_conv_convert (last_buffer, to_caps);
+
+  gst_caps_unref (to_caps);
+  gst_buffer_unref (last_buffer);
+
+  if (!buf)
+    {
+      GST_DEBUG ("Could not take screenshot: %s", "conversion failed");
+      g_warning ("Could not take screenshot: %s", "conversion failed");
+      return NULL;
+    }
+
+  if (!GST_BUFFER_CAPS (buf))
+    {
+      GST_DEBUG ("Could not take screenshot: %s", "no caps on output buffer");
+      g_warning ("Could not take screenshot: %s", "no caps on output buffer");
+      return NULL;
+    }
+
+  s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
+  gst_structure_get_int (s, "width", &outwidth);
+  gst_structure_get_int (s, "height", &outheight);
+  g_return_val_if_fail (outwidth > 0 && outheight > 0, NULL);
+
+  /* create pixbuf from that - we don't want to use the gstreamer's buffer
+   * because the GTK# bindings won't call the destroy funtion */
+  pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buf),
+      GDK_COLORSPACE_RGB, FALSE, 8, outwidth,
+      outheight, GST_ROUND_UP_4 (outwidth * 3), destroy_pixbuf, buf);
+
+  if (!pixbuf) {
+    GST_DEBUG ("Could not take screenshot: %s", "could not create pixbuf");
+    g_warning ("Could not take screenshot: %s", "could not create pixbuf");
+  }
+
+  return pixbuf;
+}
diff --git a/libcesarplayer/src/gst-camera-capturer.h b/libcesarplayer/src/gst-camera-capturer.h
index f22b6b1..20b807c 100644
--- a/libcesarplayer/src/gst-camera-capturer.h
+++ b/libcesarplayer/src/gst-camera-capturer.h
@@ -139,6 +139,8 @@ EXPORT gboolean gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc,
                                                     GError ** err);
 EXPORT GList* gst_camera_capturer_enum_audio_devices (void);
 EXPORT GList* gst_camera_capturer_enum_video_devices (void);
+EXPORT GdkPixbuf* gst_camera_capturer_get_current_frame(GstCameraCapturer *gcc);
+EXPORT void gst_camera_capture_unref_pixbuf (GdkPixbuf * pixbuf);
 
 G_END_DECLS
 #endif /* _GST_CAMERA_CAPTURER_H_ */



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