[frogr] Added support for loading both pictures and videos in the UI.
- From: Mario Sanchez Prada <msanchez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [frogr] Added support for loading both pictures and videos in the UI.
- Date: Sun, 4 Nov 2012 21:47:02 +0000 (UTC)
commit a4ea2c927d62310f3cf18c563a9d3e725fdeb64a
Author: Mario Sanchez Prada <msanchez gnome org>
Date: Sat Nov 3 13:42:17 2012 +0100
Added support for loading both pictures and videos in the UI.
A thumbnail will be created for videos, both in the icon view and the details dialog
src/frogr-details-dialog.c | 36 +++----
src/frogr-file-loader.c | 234 +++++++++++++++++++++----------------------
src/frogr-util.c | 192 ++++++++++++++++++++++++++++++++++++
src/frogr-util.h | 4 +
4 files changed, 326 insertions(+), 140 deletions(-)
---
diff --git a/src/frogr-details-dialog.c b/src/frogr-details-dialog.c
index 9cf04f0..f4f9c1b 100644
--- a/src/frogr-details-dialog.c
+++ b/src/frogr-details-dialog.c
@@ -526,30 +526,26 @@ _load_picture_from_disk_cb (GObject *object,
file = G_FILE (object);
if (g_file_load_contents_finish (file, res, &contents, &length, NULL, &error))
{
- GdkPixbufLoader *pixbuf_loader = gdk_pixbuf_loader_new ();
-
- if (gdk_pixbuf_loader_write (pixbuf_loader,
- (const guchar *)contents,
- length,
- &error))
- {
- GdkPixbuf *pixbuf = NULL;
- GdkPixbuf *s_pixbuf = NULL;
-
- gdk_pixbuf_loader_close (pixbuf_loader, NULL);
- pixbuf = gdk_pixbuf_loader_get_pixbuf (pixbuf_loader);
-
- /* Get (scaled, and maybe rotated) pixbuf */
- s_pixbuf = frogr_util_get_corrected_pixbuf (pixbuf, PICTURE_WIDTH, PICTURE_HEIGHT);
+ FrogrPicture *picture = NULL;
+ GdkPixbuf *pixbuf = NULL;
- gtk_image_set_from_pixbuf (GTK_IMAGE (priv->picture_img), s_pixbuf);
- g_object_unref (s_pixbuf);
+ picture = FROGR_PICTURE (priv->pictures->data);
+ if (frogr_picture_is_video (picture))
+ pixbuf = frogr_util_get_pixbuf_for_video_file (file, PICTURE_WIDTH, PICTURE_HEIGHT, &error);
+ else
+ pixbuf = frogr_util_get_pixbuf_from_image_contents ((const guchar *)contents, length,
+ PICTURE_WIDTH, PICTURE_HEIGHT, &error);
- /* Everything should be fine by now, show it */
- _place_picture_in_dialog_and_show (self);
+ if (pixbuf)
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->picture_img), pixbuf);
+ g_object_unref (pixbuf);
}
- g_object_unref (pixbuf_loader);
+ /* Everything should be fine by now, show it */
+ _place_picture_in_dialog_and_show (self);
+
+ g_free (contents);
}
/* Show error to the user and finalize dialog if needed */
diff --git a/src/frogr-file-loader.c b/src/frogr-file-loader.c
index 76c774a..b633df3 100644
--- a/src/frogr-file-loader.c
+++ b/src/frogr-file-loader.c
@@ -217,145 +217,139 @@ _load_next_file_cb (GObject *object,
file = G_FILE (object);
if (g_file_load_contents_finish (file, res, &contents, &length, NULL, &error))
{
- GdkPixbufLoader *pixbuf_loader = gdk_pixbuf_loader_new ();
-
- if (gdk_pixbuf_loader_write (pixbuf_loader,
- (const guchar *)contents,
- length,
- &error))
+ GdkPixbuf *pixbuf = NULL;
+ GFileInfo* file_info = NULL;
+ ExifLoader *exif_loader = NULL;
+ ExifData *exif_data = NULL;
+ ExifEntry *exif_entry = NULL;
+ gchar *file_uri = NULL;
+ gchar *file_name = NULL;
+ const gchar *mime_type = NULL;
+ guint64 filesize = 0;
+ gboolean is_video = FALSE;
+
+ /* Gather needed information */
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
+ "," G_FILE_ATTRIBUTE_STANDARD_SIZE
+ "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
+ if (!error)
{
- GdkPixbuf *pixbuf = NULL;
- GdkPixbuf *s_pixbuf = NULL;
- GFileInfo* file_info = NULL;
- ExifLoader *exif_loader = NULL;
- ExifData *exif_data = NULL;
- ExifEntry *exif_entry = NULL;
- gchar *file_uri = NULL;
- gchar *file_name = NULL;
- guint64 filesize = 0;
-
- /* Gather needed information */
- file_info = g_file_query_info (file,
- G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
- "," G_FILE_ATTRIBUTE_STANDARD_SIZE,
- G_FILE_QUERY_INFO_NONE,
- NULL, &error);
- if (!error)
- {
- file_name = g_strdup (g_file_info_get_display_name (file_info));
- filesize = g_file_info_get_size (file_info);
- }
- else
- {
- g_warning ("Not able to write pixbuf: %s", error->message);
- g_error_free (error);
+ file_name = g_strdup (g_file_info_get_display_name (file_info));
+ filesize = g_file_info_get_size (file_info);
+ }
+ else
+ {
+ g_warning ("Not able to read file information: %s", error->message);
+ g_error_free (error);
- /* Fallback if g_file_query_info() failed */
- file_name = g_file_get_basename (file);
- }
+ /* Fallback if g_file_query_info() failed */
+ file_name = g_file_get_basename (file);
+ }
- if (!priv->keep_file_extensions)
- {
- gchar *extension_dot = NULL;
+ mime_type = g_file_info_get_content_type (file_info);
+ is_video = g_str_has_prefix (mime_type, "video");
- /* Remove extension if present */
- extension_dot = g_strrstr (file_name, ".");
- if (extension_dot)
- *extension_dot = '\0';
- }
+ /* Load the pixbuf for the video or the image */
+ if (is_video)
+ pixbuf = frogr_util_get_pixbuf_for_video_file (file, IV_THUMB_WIDTH, IV_THUMB_HEIGHT, &error);
+ else
+ pixbuf = frogr_util_get_pixbuf_from_image_contents ((const guchar *)contents, length,
+ IV_THUMB_WIDTH, IV_THUMB_HEIGHT, &error);
+ if (error)
+ {
+ g_warning ("Not able to read pixbuf: %s", error->message);
+ g_error_free (error);
+ }
- file_uri = g_file_get_uri (file);
- gdk_pixbuf_loader_close (pixbuf_loader, NULL);
- pixbuf = gdk_pixbuf_loader_get_pixbuf (pixbuf_loader);
-
- /* Get (scaled, and maybe rotated) pixbuf */
- s_pixbuf = frogr_util_get_corrected_pixbuf (pixbuf, IV_THUMB_WIDTH, IV_THUMB_HEIGHT);
-
- /* Build the FrogrPicture */
- fpicture = frogr_picture_new (file_uri,
- file_name,
- priv->public_visibility,
- priv->family_visibility,
- priv->friend_visibility,
- FALSE);
-
- frogr_picture_set_send_location (fpicture, priv->send_location);
- frogr_picture_set_show_in_search (fpicture, priv->show_in_search);
- frogr_picture_set_license (fpicture, priv->license);
- frogr_picture_set_content_type (fpicture, priv->content_type);
- frogr_picture_set_safety_level (fpicture, priv->safety_level);
- frogr_picture_set_pixbuf (fpicture, s_pixbuf);
-
- /* FrogrPicture stores the size in KB */
- frogr_picture_set_filesize (fpicture, filesize / 1024);
-
- /* Set date and time from exif data, if present */
- exif_loader = exif_loader_new();
- exif_loader_write (exif_loader, (unsigned char *) contents, length);
-
- exif_data = exif_loader_get_data (exif_loader);
- if (exif_data)
- {
- FrogrLocation *location = NULL;
+ if (!priv->keep_file_extensions)
+ {
+ gchar *extension_dot = NULL;
- /* Date and time for picture taken */
- exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_DATE_TIME);
- if (exif_entry)
- {
- if (exif_entry->format == EXIF_FORMAT_ASCII)
- {
- gchar *value = g_new0 (char, 20);
- exif_entry_get_value (exif_entry, value, 20);
+ /* Remove extension if present */
+ extension_dot = g_strrstr (file_name, ".");
+ if (extension_dot)
+ *extension_dot = '\0';
+ }
- frogr_picture_set_datetime (fpicture, value);
- g_free (value);
- }
- else
- g_warning ("Found DateTime exif tag of invalid type");
- }
+ /* Build the FrogrPicture */
+ file_uri = g_file_get_uri (file);
+ fpicture = frogr_picture_new (file_uri,
+ file_name,
+ priv->public_visibility,
+ priv->family_visibility,
+ priv->friend_visibility,
+ is_video);
+
+ frogr_picture_set_send_location (fpicture, priv->send_location);
+ frogr_picture_set_show_in_search (fpicture, priv->show_in_search);
+ frogr_picture_set_license (fpicture, priv->license);
+ frogr_picture_set_content_type (fpicture, priv->content_type);
+ frogr_picture_set_safety_level (fpicture, priv->safety_level);
+ frogr_picture_set_pixbuf (fpicture, pixbuf);
+
+ /* FrogrPicture stores the size in KB */
+ frogr_picture_set_filesize (fpicture, filesize / 1024);
+
+ /* Set date and time from exif data, if present */
+ exif_loader = exif_loader_new();
+ exif_loader_write (exif_loader, (unsigned char *) contents, length);
+
+ exif_data = exif_loader_get_data (exif_loader);
+ if (exif_data)
+ {
+ FrogrLocation *location = NULL;
- /* Import tags from XMP metadata, if required */
- if (priv->import_tags)
+ /* Date and time for picture taken */
+ exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_DATE_TIME);
+ if (exif_entry)
+ {
+ if (exif_entry->format == EXIF_FORMAT_ASCII)
{
- gchar *imported_tags = NULL;
+ gchar *value = g_new0 (char, 20);
+ exif_entry_get_value (exif_entry, value, 20);
- imported_tags = import_tags_from_xmp_keywords (contents, length);
- if (imported_tags)
- {
- frogr_picture_set_tags (fpicture, imported_tags);
- g_free (imported_tags);
- }
+ frogr_picture_set_datetime (fpicture, value);
+ g_free (value);
}
+ else
+ g_warning ("Found DateTime exif tag of invalid type");
+ }
+
+ /* Import tags from XMP metadata, if required */
+ if (priv->import_tags)
+ {
+ gchar *imported_tags = NULL;
- /* GPS coordinates */
- location = get_location_from_exif (exif_data);
- if (location != NULL)
+ imported_tags = import_tags_from_xmp_keywords (contents, length);
+ if (imported_tags)
{
- /* frogr_picture_set_location takes ownership of location */
- frogr_picture_set_location (fpicture, location);
- g_object_unref (location);
+ frogr_picture_set_tags (fpicture, imported_tags);
+ g_free (imported_tags);
}
- exif_data_unref (exif_data);
}
- if (file_info)
- g_object_unref (file_info);
+ /* GPS coordinates */
+ location = get_location_from_exif (exif_data);
+ if (location != NULL)
+ {
+ /* frogr_picture_set_location takes ownership of location */
+ frogr_picture_set_location (fpicture, location);
+ g_object_unref (location);
+ }
+ exif_data_unref (exif_data);
+ }
- exif_loader_unref (exif_loader);
+ if (file_info)
+ g_object_unref (file_info);
- g_object_unref (s_pixbuf);
- g_free (file_uri);
- g_free (file_name);
- }
- else
- {
- /* Not able to write pixbuf */
- g_warning ("Not able to write pixbuf: %s",
- error->message);
- g_error_free (error);
- }
+ exif_loader_unref (exif_loader);
- g_object_unref (pixbuf_loader);
+ g_object_unref (pixbuf);
+ g_free (file_uri);
+ g_free (file_name);
}
else
{
diff --git a/src/frogr-util.c b/src/frogr-util.c
index d7fe2c3..5584473 100644
--- a/src/frogr-util.c
+++ b/src/frogr-util.c
@@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>
*
+ * Parts of this file based on code from gst-plugins-base, licensed as
+ * GPL version 2 or later (Copyright (C) <2007> Wim Taymans <wim taymans gmail com>)
*/
#include "frogr-util.h"
@@ -24,6 +26,7 @@
#include <config.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
+#include <gst/gst.h>
#include <libexif/exif-byte-order.h>
#include <libexif/exif-data.h>
#include <libexif/exif-entry.h>
@@ -31,6 +34,8 @@
#include <libexif/exif-loader.h>
#include <libexif/exif-tag.h>
+#define CAPS "video/x-raw-rgb,width=160,pixel-aspect-ratio=1/1,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)0xff0000, green_mask=(int)0x00ff00, blue_mask=(int)0x0000ff"
+
static gboolean
_spawn_command (const gchar* cmd)
{
@@ -308,6 +313,193 @@ frogr_util_get_corrected_pixbuf (GdkPixbuf *pixbuf, gint max_width, gint max_hei
return scaled_pixbuf;
}
+static GdkPixbuf *
+_get_pixbuf_from_image_contents (const guchar *contents, gsize length, GError **out_error)
+{
+ GdkPixbufLoader *pixbuf_loader = NULL;
+ GdkPixbuf *pixbuf = NULL;
+ GError *error = NULL;
+
+ pixbuf_loader = gdk_pixbuf_loader_new ();
+ if (gdk_pixbuf_loader_write (pixbuf_loader,
+ (const guchar *)contents,
+ length,
+ &error))
+ {
+ gdk_pixbuf_loader_close (pixbuf_loader, NULL);
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (pixbuf_loader);
+ }
+
+ if (error)
+ {
+ DEBUG ("Error loading pixbuf: %s", error->message);
+ g_propagate_error (out_error, error);
+ }
+
+ /* Keep the pixbuf before destroying the loader */
+ if (pixbuf)
+ g_object_ref (pixbuf);
+ g_object_unref (pixbuf_loader);
+
+ return pixbuf;
+}
+
+/* The following function is based in GStreamer's snapshot example,
+ from gst-plugins-base, licensed as GPL version 2 or later
+ (Copyright (C) <2007> Wim Taymans <wim taymans gmail com>) */
+static GdkPixbuf *
+_get_pixbuf_from_video_file (GFile *file, GError **out_error)
+{
+ GdkPixbuf *pixbuf = NULL;
+ GstElement *pipeline, *sink;
+ GstBuffer *buffer;
+ GstFormat format;
+ GstStateChangeReturn ret;
+ gchar *file_uri;
+ gchar *descr;
+ gint width, height;
+ gint64 duration, position;
+ GError *error = NULL;
+ gboolean res;
+
+ /* create a new pipeline */
+ file_uri = g_file_get_uri (file);
+ descr = g_strdup_printf ("uridecodebin uri=%s ! ffmpegcolorspace ! videoscale ! "
+ " appsink name=sink caps=\"" CAPS "\"", file_uri);
+ g_free (file_uri);
+
+ pipeline = gst_parse_launch (descr, &error);
+ g_free (descr);
+
+ if (error != NULL) {
+ DEBUG ("Could not construct pipeline: %s\n", error->message);
+ g_propagate_error (out_error, error);
+ return NULL;
+ }
+
+ /* get sink */
+ sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+
+ /* set to PAUSED to make the first frame arrive in the sink */
+ ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ switch (ret) {
+ case GST_STATE_CHANGE_FAILURE:
+ DEBUG ("failed to play the file\n");
+ return NULL;
+ case GST_STATE_CHANGE_NO_PREROLL:
+ /* for live sources, we need to set the pipeline to PLAYING before we can
+ * receive a buffer. We don't do that yet */
+ DEBUG ("live sources not supported yet\n");
+ return NULL;
+ default:
+ break;
+ }
+
+ /* This can block for up to 5 seconds. If your machine is really overloaded,
+ * it might time out before the pipeline prerolled and we generate an error. A
+ * better way is to run a mainloop and catch errors there. */
+ ret = gst_element_get_state (pipeline, NULL, NULL, 5 * GST_SECOND);
+ if (ret == GST_STATE_CHANGE_FAILURE) {
+ DEBUG ("failed to play the file\n");
+ return NULL;
+ }
+
+ /* get the duration */
+ format = GST_FORMAT_TIME;
+ gst_element_query_duration (pipeline, &format, &duration);
+
+ if (duration != -1)
+ /* we have a duration, seek to 50% */
+ position = duration * 0.5;
+ else
+ /* no duration, seek to 1 second, this could EOS */
+ position = 1 * GST_SECOND;
+
+ /* seek to the a position in the file. Most files have a black first frame so
+ * by seeking to somewhere else we have a bigger chance of getting something
+ * more interesting. */
+ gst_element_seek_simple (pipeline, GST_FORMAT_TIME,
+ GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH, position);
+
+ /* get the preroll buffer from appsink, this block untils appsink really prerolls */
+ g_signal_emit_by_name (sink, "pull-preroll", &buffer, NULL);
+
+ /* if we have a buffer now, convert it to a pixbuf. It's possible that we
+ * don't have a buffer because we went EOS right away or had an error. */
+ if (buffer) {
+ GstCaps *caps;
+ GstStructure *s;
+
+ /* get the snapshot buffer format now. We set the caps on the appsink so
+ * that it can only be an rgb buffer. The only thing we have not specified
+ * on the caps is the height, which is dependant on the pixel-aspect-ratio
+ * of the source material */
+ caps = GST_BUFFER_CAPS (buffer);
+ if (!caps) {
+ DEBUG ("could not get snapshot format\n");
+ return NULL;
+ }
+ s = gst_caps_get_structure (caps, 0);
+
+ /* we need to get the final caps on the buffer to get the size */
+ res = gst_structure_get_int (s, "width", &width);
+ res |= gst_structure_get_int (s, "height", &height);
+ if (!res) {
+ DEBUG ("could not get snapshot dimension\n");
+ return NULL;
+ }
+
+ /* create pixmap from buffer and save, gstreamer video buffers have a stride
+ * that is rounded up to the nearest multiple of 4 */
+ pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
+ GDK_COLORSPACE_RGB, FALSE, 8, width, height,
+ GST_ROUND_UP_4 (width * 3), NULL, NULL);
+
+ } else {
+ DEBUG ("could not make snapshot\n");
+ }
+
+ /* cleanup and exit */
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_object_unref (pipeline);
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+frogr_util_get_pixbuf_for_video_file (GFile *file, gint max_width, gint max_height, GError **error)
+{
+ GdkPixbuf *pixbuf = NULL;
+
+ pixbuf = _get_pixbuf_from_video_file (file, error);
+ if (pixbuf)
+ {
+ GdkPixbuf *c_pixbuf = NULL;
+ c_pixbuf = frogr_util_get_corrected_pixbuf (pixbuf, max_width, max_height);
+ g_object_unref (pixbuf);
+ pixbuf = c_pixbuf;
+ }
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+frogr_util_get_pixbuf_from_image_contents (const guchar *contents, gsize length, gint max_width, gint max_height, GError **error)
+{
+ GdkPixbuf *pixbuf = NULL;
+
+ pixbuf = _get_pixbuf_from_image_contents (contents, length, error);
+ if (pixbuf)
+ {
+ GdkPixbuf *c_pixbuf = NULL;
+ c_pixbuf = frogr_util_get_corrected_pixbuf (pixbuf, max_width, max_height);
+ g_object_unref (pixbuf);
+ pixbuf = c_pixbuf;
+ }
+
+ return pixbuf;
+}
+
gchar *
frogr_util_get_datasize_string (gulong datasize)
{
diff --git a/src/frogr-util.h b/src/frogr-util.h
index 0c776e0..ffb74ca 100644
--- a/src/frogr-util.h
+++ b/src/frogr-util.h
@@ -43,6 +43,10 @@ void frogr_util_show_error_dialog (GtkWindow *parent, const gchar *message);
GdkPixbuf *frogr_util_get_corrected_pixbuf (GdkPixbuf *pixbuf, gint max_width, gint max_height);
+GdkPixbuf *frogr_util_get_pixbuf_for_video_file (GFile *file, gint max_width, gint max_height, GError **error);
+
+GdkPixbuf *frogr_util_get_pixbuf_from_image_contents (const guchar *contents, gsize length, gint max_width, gint max_height, GError **error);
+
gchar *frogr_util_get_datasize_string (gulong datasize);
const gchar * const *frogr_util_get_supported_files (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]