[frogr] Added support for loading both pictures and videos in the UI.



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]