[mistelix/stable] Fixes video thumbnails
- From: Jordi Mas <jmas src gnome org>
- To: svn-commits-list gnome org
- Subject: [mistelix/stable] Fixes video thumbnails
- Date: Wed, 24 Jun 2009 18:10:10 +0000 (UTC)
commit 5db47a4184c372920c14a9321da3eea660395bf5
Author: Jordi Mas <jmas softcatala org>
Date: Sat Jun 13 16:53:02 2009 +0200
Fixes video thumbnails
libmistelix/Makefile.am | 3 +-
libmistelix/mistelix.c | 27 -------
libmistelix/mistelix.h | 12 ++-
libmistelix/thumbnail.c | 137 ++++++++++++++++++++++++++++++++++
src/core/MistelixLib.cs | 25 ++----
src/datamodel/VideoProjectElement.cs | 8 ++-
src/widgets/FileView.cs | 2 +
src/widgets/ImagesFileView.cs | 32 +++++---
src/widgets/ProjectElementView.cs | 8 +-
src/widgets/VideosFileView.cs | 33 +++++---
10 files changed, 211 insertions(+), 76 deletions(-)
---
diff --git a/libmistelix/Makefile.am b/libmistelix/Makefile.am
index 55825eb..19cb08e 100644
--- a/libmistelix/Makefile.am
+++ b/libmistelix/Makefile.am
@@ -8,7 +8,8 @@ dolibdir = $(libdir)/mistelix
dolib_LTLIBRARIES = libmistelix.la
libmistelix_la_SOURCES = \
- mistelix.c
+ mistelix.c \
+ thumbnail.c
noinst_HEADERS = \
mistelix.h
diff --git a/libmistelix/mistelix.c b/libmistelix/mistelix.c
index 2f62522..23eba94 100644
--- a/libmistelix/mistelix.c
+++ b/libmistelix/mistelix.c
@@ -33,11 +33,6 @@
#include "mistelix.h"
-#define SEEK_TIMEOUT 5 * GST_MSECOND
-
-/* Enable this define for debugging */
-
-//#define _DEBUG 1
typedef struct
{
@@ -445,28 +440,6 @@ mistelix_convert_media (const char* filein, const char* fileout)
return 0;
}
-void
-mistelix_thumbnail_video (const char* filein, const char* fileout, int width, int height)
-{
- GstElement* pipe;
- char desc [1024];
-
- mistelix_check_init ();
-
- // TODO: num-buffers is not the smarter way of doing this. Check gnlfilesource gstreamer element
- if (height == -1) // use videoscale aspect ratio
- sprintf (desc, "filesrc location=\"%s\" num-buffers=100 ! decodebin ! videoscale ! video/x-raw-yuv,format=(fourcc)I420,width=%u !jpegenc ! filesink location=%s", filein, width, fileout);
- else
- sprintf (desc, "filesrc location=\"%s\" num-buffers=100 ! decodebin ! videoscale ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u !jpegenc ! filesink location=%s", filein, width, height, fileout);
-#ifdef _DEBUG
- printf ("*** mistelix_thumbnail_video pipe %s\n", desc);
-#endif
- pipe = gst_parse_launch (desc, NULL);
- run_pipeline (pipe);
- //gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_NULL);
- //gst_object_unref (GST_OBJECT (pipe));
-}
-
//
// Private
//
diff --git a/libmistelix/mistelix.h b/libmistelix/mistelix.h
index b3bca0d..6acfeb1 100644
--- a/libmistelix/mistelix.h
+++ b/libmistelix/mistelix.h
@@ -24,10 +24,16 @@
#ifndef __MISTELIX_H__
#define __MISTELIX_H__
+#define SEEK_TIMEOUT 5 * GST_MSECOND
+
+/* Enable this define for debugging */
+/* #define _DEBUG 1 */
+
+
#include <stdio.h>
#include <gst/check/gstcheck.h>
-// Public API
+/* Public API */
void mistelix_slideshow_createstream (const gchar* filename, unsigned int type, unsigned int weight, unsigned int height, unsigned int framessec, unsigned int total_frames);
void mistelix_slideshow_add_image (unsigned char* bytes, unsigned int len);
@@ -42,10 +48,10 @@ void mistelix_launchtool (const char* app, const char* args, const char* in, con
int mistelix_convert_media (const char* filein, const char* fileout);
-void mistelix_thumbnail_video (const char* filein, const char* fileout, int width, int height);
+void mistelix_video_screenshot (const char* filein, void** image);
-// Private (not exposed)
+/* Private (not exposed) */
char * mistelix_get_element_name_from_pipeline (GstBin* pipe, char* generic_name);
diff --git a/libmistelix/thumbnail.c b/libmistelix/thumbnail.c
new file mode 100644
index 0000000..767d9a8
--- /dev/null
+++ b/libmistelix/thumbnail.c
@@ -0,0 +1,137 @@
+//
+// Copyright (C) 2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include "mistelix.h"
+
+void*
+mistelix_take_screenshot (GstElement* playbin, GstBus* bus, GstElement* pixbufsink, int time);
+
+
+/*
+ Creates a video screenshot using playbin and gdkpixbufsink
+*/
+void
+mistelix_video_screenshot (const char* filein, void** image)
+{
+ GstElement *playbin, *pixbufsink, *fakesink;
+ GstBus* bus;
+ gchar * uri;
+ void *pix;
+
+#ifdef _DEBUG
+ printf ("mistelix_video_snapshoot %s\n", filein);
+#endif
+ mistelix_check_init ();
+
+ pixbufsink = gst_element_factory_make ("gdkpixbufsink", "gdkpixbufsink");
+ fakesink = gst_element_factory_make ("fakesink", "fakesink");
+ playbin = gst_element_factory_make ("playbin", "playbin");
+
+ uri = g_filename_to_uri (filein, NULL, NULL);
+ g_object_set (G_OBJECT (playbin), "uri", uri, NULL);
+ g_object_set (G_OBJECT (playbin), "video-sink", pixbufsink, NULL);
+ g_object_set (G_OBJECT (playbin), "audio-sink", fakesink, NULL);
+
+ bus = gst_element_get_bus (playbin);
+ g_assert (bus);
+
+ /* Go to the second 5 since the beginning is black for many videos */
+ pix = mistelix_take_screenshot (playbin, bus, pixbufsink, 5);
+
+ gst_element_set_state (playbin, GST_STATE_NULL);
+ gst_element_get_state (playbin, NULL, NULL, SEEK_TIMEOUT);
+
+ gst_object_unref (playbin);
+ gst_object_unref (bus);
+ g_free (uri);
+
+ *image = pix;
+}
+
+void*
+mistelix_take_screenshot (GstElement* playbin, GstBus* bus, GstElement* pixbufsink, int time)
+{
+ void* pix;
+ GstMessage *message;
+ GstMessageType revent;
+ GstStateChangeReturn ret;
+
+ gst_element_set_state (GST_ELEMENT (playbin), GST_STATE_PAUSED);
+
+ /* Cannot block for ever because the call never returns for incorrect files */
+ gst_element_get_state (playbin, NULL, NULL, 2 * GST_SECOND);
+
+ gboolean bol = gst_element_seek (playbin, 1.0,
+ GST_FORMAT_TIME | GST_SEEK_FLAG_ACCURATE,
+ GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, time * GST_SECOND,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+ gst_element_set_state (GST_ELEMENT (playbin), GST_STATE_PLAYING);
+ gst_element_get_state (playbin, NULL, NULL, 2 * GST_SECOND);
+
+ /* gdkpixbufsink sends a GST_MESSAGE_ELEMENT when a picture is ready */
+ while (1) {
+ message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+#ifdef _DEBUG
+ printf ("*** run_pipeline message: %s (%x)\n", gst_message_type_get_name (revent), revent);
+#endif
+ if (message) {
+ revent = GST_MESSAGE_TYPE (message);
+ gst_message_unref (message);
+
+ if (revent == GST_MESSAGE_ELEMENT) {
+ printf ("*** run_pipeline: break element\n");
+ break;
+ }
+
+ } else
+ revent = GST_MESSAGE_UNKNOWN;
+
+ if (revent == GST_MESSAGE_UNKNOWN) {
+#ifdef _DEBUG
+ printf ("*** run_pipeline exiting reason GST_MESSAGE_UNKNOWN\n");
+#endif
+ break;
+ }
+
+ if (revent == GST_MESSAGE_ERROR) {
+#ifdef _DEBUG
+ printf ("*** run_pipeline exiting reason GST_MESSAGE_ERROR\n");
+#endif
+ break;
+ }
+
+ if (revent == GST_MESSAGE_EOS) {
+#ifdef _DEBUG
+ printf ("*** run_pipeline exiting reason: GST_MESSAGE_EOS\n");
+#endif
+ break;
+ }
+
+ }
+
+ g_object_get (G_OBJECT (pixbufsink), "last-pixbuf", &pix, NULL);
+ return pix;
+}
+
diff --git a/src/core/MistelixLib.cs b/src/core/MistelixLib.cs
index 90d20a1..8f1f2d2 100644
--- a/src/core/MistelixLib.cs
+++ b/src/core/MistelixLib.cs
@@ -70,8 +70,7 @@ namespace Mistelix.Core
static extern int mistelix_convert_media (string filein, string fileout);
[DllImport ("libmistelix")]
- static extern void mistelix_thumbnail_video (string filein, string fileout, int width, int height);
-
+ static extern void mistelix_video_screenshot (string filein, out IntPtr pixbuf);
public MistelixLib ()
{
@@ -208,26 +207,18 @@ namespace Mistelix.Core
mistelix_slideshow_close ();
}
- static public Gdk.Pixbuf CreateThumbnail (string file, int width, int height)
+ static public Gdk.Pixbuf VideoScreenshot (string file)
{
string thumbnail_file = Path.Combine (Path.GetTempPath (), Path.GetTempFileName ());
Gdk.Pixbuf thumbnail;
+ IntPtr pix;
- Logger.Debug ("MistelixLib.CreateThumbnail. File {0}", file);
+ mistelix_video_screenshot (file, out pix);
- // Request a thumbnail honoring the original aspect ratio
- mistelix_thumbnail_video (file, thumbnail_file, width, -1);
- thumbnail = new Gdk.Pixbuf (thumbnail_file);
-
- // We use videoscale gstreamer element to resize videos honouring the aspect ratio
- // however, does not work for all video types, then we do request a non-aspect ratio video
- if (thumbnail.Width > width || thumbnail.Height > height)
- {
- thumbnail.Dispose ();
- mistelix_thumbnail_video (file, thumbnail_file, width, height);
- thumbnail = new Gdk.Pixbuf (thumbnail_file);
- }
- File.Delete (thumbnail_file);
+ if (pix == IntPtr.Zero)
+ throw new InvalidOperationException ("No screenshot taken");
+
+ thumbnail = new Gdk.Pixbuf (pix);
return thumbnail;
}
}
diff --git a/src/datamodel/VideoProjectElement.cs b/src/datamodel/VideoProjectElement.cs
index b6d6545..18314fd 100644
--- a/src/datamodel/VideoProjectElement.cs
+++ b/src/datamodel/VideoProjectElement.cs
@@ -25,6 +25,7 @@
using System;
using Mono.Unix;
using System.Xml.Serialization;
+using Gdk;
using Mistelix.Core;
@@ -60,7 +61,12 @@ namespace Mistelix.DataModel
public override Gdk.Pixbuf GetThumbnail (int width, int height)
{
- return MistelixLib.CreateThumbnail (filename, 80, 80); // TODO: Hardcoded values
+ Gdk.Pixbuf im;
+ im = MistelixLib.VideoScreenshot (filename);
+ int max = Math.Max (im.Width, im.Height);
+ Gdk.Pixbuf scaled = im.ScaleSimple (width * im.Width / max, height * im.Height / max, InterpType.Nearest);
+ im.Dispose ();
+ return scaled;
}
}
}
diff --git a/src/widgets/FileView.cs b/src/widgets/FileView.cs
index 6b4b859..1db0ddd 100644
--- a/src/widgets/FileView.cs
+++ b/src/widgets/FileView.cs
@@ -118,6 +118,7 @@ namespace Mistelix.Widgets
return false;
});
+ thumbnailing.CancelAsync ();
thumbnailing.Dispose ();
}
@@ -136,6 +137,7 @@ namespace Mistelix.Widgets
thumbnailing.Dispose ();
thumbnailing = new BackgroundWorker ();
+ thumbnailing.WorkerSupportsCancellation = true;
thumbnailing.DoWork += new DoWorkEventHandler (DoWork);
// TODO: Optimize for directories with images videos
diff --git a/src/widgets/ImagesFileView.cs b/src/widgets/ImagesFileView.cs
index a647fed..1b488bd 100644
--- a/src/widgets/ImagesFileView.cs
+++ b/src/widgets/ImagesFileView.cs
@@ -125,17 +125,27 @@ namespace Mistelix.Widgets
store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter)
{
- string file = (string) store.GetValue (iter, 0);
- Gdk.Pixbuf im = new Gdk.Pixbuf (file);
- int max = Math.Max (im.Width, im.Height);
- Gdk.Pixbuf scaled = im.ScaleSimple (thumbnail_width * im.Width / max, thumbnail_height * im.Height / max, InterpType.Nearest);
-
- Application.Invoke (delegate {
- store.SetValue (iter, 2, scaled);
- } );
-
- im.Dispose ();
- return false;
+ try {
+ if (thumbnailing.CancellationPending)
+ return true;
+
+ string file = (string) store.GetValue (iter, COL_PATH);
+ Gdk.Pixbuf im = new Gdk.Pixbuf (file);
+ int max = Math.Max (im.Width, im.Height);
+ Gdk.Pixbuf scaled = im.ScaleSimple (thumbnail_width * im.Width / max, thumbnail_height * im.Height / max, InterpType.Nearest);
+
+ Application.Invoke (delegate {
+ store.SetValue (iter, COL_PIXBUF, scaled);
+ } );
+
+ im.Dispose ();
+ return false;
+ }
+
+ catch (Exception ex) {
+ Logger.Error ("ImagesFileView.Dork. Exception: " + ex.Message);
+ return false;
+ }
});
}
}
diff --git a/src/widgets/ProjectElementView.cs b/src/widgets/ProjectElementView.cs
index 004ab77..52df205 100644
--- a/src/widgets/ProjectElementView.cs
+++ b/src/widgets/ProjectElementView.cs
@@ -166,12 +166,14 @@ namespace Mistelix.Widgets
try {
im = element.Thumbnail;
}
- catch {
+
+ catch (Exception ex) {
+ Logger.Error ("ProjectElementView.Dowork. Exception: " + ex.Message);
return false;
}
-
+
Application.Invoke (delegate {
- store.SetValue (iter, 2, im);
+ store.SetValue (iter, COL_PIXBUF, im);
} );
return false;
diff --git a/src/widgets/VideosFileView.cs b/src/widgets/VideosFileView.cs
index da68207..c3d6a35 100644
--- a/src/widgets/VideosFileView.cs
+++ b/src/widgets/VideosFileView.cs
@@ -73,26 +73,33 @@ namespace Mistelix.Widgets
Logger.Debug ("VideosFileView.Dowork start");
store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter)
{
- string file = (string) store.GetValue (iter, 0);
- Gdk.Pixbuf im;
-
+ if (thumbnailing.CancellationPending)
+ return true;
+
+ string file = (string) store.GetValue (iter, COL_PATH);
+
try {
- im = MistelixLib.CreateThumbnail (file, thumbnail_width, thumbnail_height);
+ Gdk.Pixbuf im;
+
+ im = MistelixLib.VideoScreenshot (file);
+
+ int max = Math.Max (im.Width, im.Height);
+ Gdk.Pixbuf scaled = im.ScaleSimple (thumbnail_width * im.Width / max, thumbnail_height * im.Height / max, InterpType.Nearest);
+
+ Application.Invoke (delegate {
+ store.SetValue (iter, COL_PIXBUF, scaled);
+ } );
+
+ im.Dispose ();
+ return false;
}
- catch {
+ catch (Exception ex) {
+ Logger.Error ("VideosFileView.DoWork. Exception: " + ex.Message);
return false;
}
-
- Application.Invoke (delegate {
- store.SetValue (iter, 2, im);
- } );
-
- return false;
});
-
Logger.Debug ("VideosFileView.Dowork end");
}
-
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]