[longomatch/livecapture2: 24/31] Add support to take screenshots from the live source
- From: Andoni Morales Alastruey <amorales src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [longomatch/livecapture2: 24/31] Add support to take screenshots from the live source
- Date: Mon, 3 May 2010 22:40:50 +0000 (UTC)
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]