update GdkPixbuf loader. Fixes:
authorBenjamin Otte <otte@gnome.org>
Tue, 11 Nov 2003 22:43:24 +0000 (22:43 +0000)
committerBenjamin Otte <otte@gnome.org>
Tue, 11 Nov 2003 22:43:24 +0000 (22:43 +0000)
Original commit message from CVS:
update GdkPixbuf loader. Fixes:
- has a begin_load implementation
- makes sure it only works when threads are enabled (this fixes segfaults with gtk 2.3)
There are still some kinks though, feel free to hack on it :)

ext/gdk_pixbuf/gst_loader.c
ext/gdk_pixbuf/gstgdkanimation.c
ext/gdk_pixbuf/gstgdkanimation.h

index 0a21b82..b8d1c9d 100644 (file)
 #endif
 
 #include "gstgdkanimation.h"
+#include <gst/gstinfo.h>
 #include <stdio.h>
 
+typedef struct {
+  /* stuff gdk throws at us and we're supposed to keep */
+  GdkPixbufModuleSizeFunc      size_func;
+  GdkPixbufModulePreparedFunc  prepared_func;
+  GdkPixbufModuleUpdatedFunc   updated_func;
+  gpointer                     user_data;
+  /* our own stuff - we're much better at keeping fields small :p */
+  GstGdkAnimation *            ani;
+  gboolean                     initialized;
+} GstLoaderContext;
+
+GST_DEBUG_CATEGORY_STATIC (gst_loader_debug);
+#define GST_CAT_DEFAULT gst_loader_debug
+
+static gboolean
+gst_loader_init (GError **error)
+{
+  static gboolean inited = FALSE;
+  
+  if (inited)
+    return TRUE;
+  
+  if (!g_thread_supported ()) {
+    g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
+                "The GStreamer loader requires threading support.");
+    return FALSE;
+  }
+
+  if (!gst_init_check (0, NULL)) {
+    g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
+                "GStreamer could not be initialized.");
+    return FALSE;
+  }
+
+  inited = TRUE;
+  GST_DEBUG_CATEGORY_INIT (gst_loader_debug, "gstloader", 0, "entry point debugging for the GStreamer gdk pixbuf loader");
+  return TRUE;
+}
+static gpointer
+gst_loader_begin_load (GdkPixbufModuleSizeFunc size_func, GdkPixbufModulePreparedFunc prepared_func,
+                      GdkPixbufModuleUpdatedFunc updated_func, gpointer user_data, GError **error)
+{
+  GstLoaderContext *context;
+  
+  if (!gst_loader_init (error))
+    return NULL;
+  
+  context = g_new (GstLoaderContext, 1);
+  context->size_func = size_func;
+  context->prepared_func = prepared_func;
+  context->updated_func = updated_func;
+  context->user_data = user_data;
+  context->ani = gst_gdk_animation_new (error);
+  context->initialized = FALSE;
+
+  if (!context->ani) {
+    GST_WARNING ("creating animation failed");
+    g_free (context);
+    return NULL;
+  }
+  GST_LOG_OBJECT (context->ani, "begin loading");
+  return context;
+}
+static gboolean
+gst_loader_load_increment (gpointer context_pointer, const guchar *buf, guint size, GError **error)
+{
+  GdkPixbufAnimationIter *iter;
+  GstLoaderContext *context = (GstLoaderContext *) context_pointer;
+
+  GST_LOG_OBJECT (context->ani, "load increment: %u bytes", size);
+  gst_gdk_animation_add_data (context->ani, buf, size);
+  if (!context->initialized && (iter = gdk_pixbuf_animation_get_iter (
+             GDK_PIXBUF_ANIMATION (context->ani), NULL)) != NULL) {
+    int width = gdk_pixbuf_animation_get_width (GDK_PIXBUF_ANIMATION (context->ani));
+    int height = gdk_pixbuf_animation_get_height (GDK_PIXBUF_ANIMATION (context->ani));
+    GdkPixbuf *pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->ani));
+
+    g_object_unref (iter);
+    GST_LOG_OBJECT (context->ani, "initializing loader");
+    if (context->size_func) {
+      GST_LOG_OBJECT (context->ani, "calling size_func %p", context->size_func);
+      context->size_func (&width, &height, context->user_data);
+    }
+
+    if (context->prepared_func) {
+      GST_LOG_OBJECT (context->ani, "calling prepared_func %p", context->prepared_func);
+      context->prepared_func (pixbuf, GDK_PIXBUF_ANIMATION (context->ani), context->user_data);
+    }
+    
+    context->initialized = TRUE;
+  }
+  
+  return TRUE;
+}
+static gboolean
+gst_loader_stop_load (gpointer context_pointer, GError **error)
+{
+  GstLoaderContext *context = (GstLoaderContext *) context_pointer;
+
+  GST_LOG_OBJECT (context->ani, "stop loading");
+  gst_gdk_animation_done_adding (context->ani);
+  g_object_unref (context->ani);
+  g_free (context);
+
+  return TRUE;
+}
+
 static GdkPixbufAnimation *
 gst_loader_load_animation (FILE *f, GError **error)
 {
-  return gst_gdk_animation_new_from_file (f, error);
+  guchar data[4096];
+  guint size;
+  GdkPixbufAnimationIter *iter;
+  GstGdkAnimation *ani;
+  
+  if (!gst_loader_init (error))
+    return NULL;
+  
+  GST_LOG ("load_animation");
+  ani = gst_gdk_animation_new (error);
+  if (!ani)
+    return NULL;
+  
+  while ((size = fread (data, 1, 4096, f)) > 0) {
+    if (!gst_gdk_animation_add_data (ani, data, size)) {
+      g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
+                  "could not add more data to animation"); /* our errors suck ;) */
+      g_object_unref (ani);
+      GST_WARNING ("load_animation failed");
+      return NULL;
+    }
+  }
+  gst_gdk_animation_done_adding (ani);
+  iter = gdk_pixbuf_animation_get_iter (GDK_PIXBUF_ANIMATION (ani), NULL);
+  if (iter == NULL) {
+      g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                  "could not create an image");
+      g_object_unref (ani);
+      GST_INFO ("could not create an image");
+      return NULL; 
+  }
+  g_object_unref (iter);
+  GST_LOG_OBJECT (ani, "load_animation succeeded");
+  return GDK_PIXBUF_ANIMATION (ani);
 }
 void
 fill_vtable (GdkPixbufModule *module)
 {
-  if (gst_init_check (0, NULL)) {
-    module->load_animation = gst_loader_load_animation;
-  }
+  module->begin_load = gst_loader_begin_load;
+  module->load_increment = gst_loader_load_increment;
+  module->stop_load = gst_loader_stop_load;
+  module->load_animation = gst_loader_load_animation;
 }
 void
 fill_info (GdkPixbufFormat *info)
index 6519cc1..9e1aa16 100644 (file)
@@ -93,35 +93,36 @@ gst_gdk_animation_finalize (GObject *object)
     remove (ani->temp_location);
     g_free (ani->temp_location);
   }
+  if (ani->pixbuf) {
+    g_object_unref (ani->pixbuf);
+    ani->pixbuf = NULL;
+  }
         
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
-GdkPixbufAnimation *
-gst_gdk_animation_new_from_file (FILE *f, GError **error)
+GstGdkAnimation *
+gst_gdk_animation_new (GError **error)
 {
-  GdkPixbufAnimationIter *iter;
-  GTimeVal tv;
-  int fd2;  
-  guint8 data[4096];
-  guint size;
-  int fd = fileno (f);
   GstGdkAnimation *ani = GST_GDK_ANIMATION (g_object_new (GST_TYPE_GDK_ANIMATION, NULL));
 
-  fd2 = g_file_open_tmp (NULL, &ani->temp_location, error);
-  if (fd2 == -1)
+  ani->temp_fd = g_file_open_tmp (NULL, &ani->temp_location, error);
+  if (ani->temp_fd == 0) {
+    g_object_unref (ani);
     return NULL;
-  while ((size = read (fd, data, 4096)) > 0) {
-    if (write (fd2, data, size) != size)
-      break;
   }
-  close (fd2);
-  
-  /* we need some info that is only provided by iters */
-  g_get_current_time (&tv);
-  iter = gst_gdk_animation_get_iter (GDK_PIXBUF_ANIMATION (ani), &tv);
-  g_object_unref (iter);
-  
-  return GDK_PIXBUF_ANIMATION (ani);
+
+  return ani;
+}
+gboolean
+gst_gdk_animation_add_data (GstGdkAnimation *ani, const guint8 *data, guint size)
+{
+  return (write (ani->temp_fd, data, size) == size);
+}
+void
+gst_gdk_animation_done_adding (GstGdkAnimation *ani)
+{
+  close (ani->temp_fd);
+  ani->temp_fd = 0;
 }
 static gboolean
 gst_gdk_animation_is_static_image (GdkPixbufAnimation *animation)
@@ -132,7 +133,9 @@ gst_gdk_animation_is_static_image (GdkPixbufAnimation *animation)
 static GdkPixbuf*
 gst_gdk_animation_get_static_image (GdkPixbufAnimation *animation)
 {
-  return NULL;
+  GstGdkAnimation *ani = GST_GDK_ANIMATION (animation);
+
+  return ani->pixbuf;
 }
 
 static void
@@ -269,20 +272,24 @@ gst_gdk_animation_iter_create_pipeline (GstGdkAnimationIter *iter)
   if (!(autoplugger = gst_element_factory_make ("spider", "autoplugger")))
     goto error;
   gst_bin_add (GST_BIN (ret), autoplugger);
-  gst_element_link (src, autoplugger);
+  if (!gst_element_link (src, autoplugger))
+    goto error;
   
   if (!(colorspace = gst_element_factory_make ("colorspace", "colorspace")))
     goto error;
   gst_bin_add (GST_BIN (ret), colorspace);
-  gst_element_link (autoplugger, colorspace);
+  if (!gst_element_link (autoplugger, colorspace))
+    goto error;
   
   if (!(sink = gst_element_factory_make ("fakesink", "sink")))
     goto error;
   g_object_set (sink, "signal-handoffs", TRUE, NULL);
   g_signal_connect (sink, "handoff", (GCallback) got_handoff, iter);
   gst_bin_add (GST_BIN (ret), sink);
-  gst_element_link_filtered (colorspace, sink, caps);
-  gst_element_set_state (ret, GST_STATE_PLAYING);
+  if (!gst_element_link_filtered (colorspace, sink, caps))
+    goto error;
+  if (gst_element_set_state (ret, GST_STATE_PLAYING) != GST_STATE_SUCCESS)
+    goto error;
   
   return ret;
 error:
@@ -303,7 +310,7 @@ gst_gdk_animation_iter_may_advance (GstGdkAnimationIter *iter)
   g_assert (data_amount >= 0);
   g_assert (gst_element_query (gst_bin_get_by_name (GST_BIN (iter->pipeline), "source"),
                         GST_QUERY_POSITION, &bytes, &offset));
-  if (data_amount - offset > GST_GDK_BUFFER_SIZE) /* random number */
+  if (data_amount - offset > GST_GDK_BUFFER_SIZE)
     return TRUE;
 
   return FALSE;
@@ -315,15 +322,17 @@ gst_gdk_animation_get_more_buffers (GstGdkAnimationIter *iter)
   
   do {
     GST_LOG_OBJECT (iter, "iterating...");
-    if (!gst_gdk_animation_iter_may_advance (iter))
-      return FALSE;
+    if (!gst_gdk_animation_iter_may_advance (iter)) {
+      GST_LOG_OBJECT (iter, "no more data available");
+      break;
+    }
     if (!gst_bin_iterate (GST_BIN (iter->pipeline))) {
       GST_LOG_OBJECT (iter, "iterating done, setting EOS");
       iter->eos = TRUE;
       break;
     }
   } while (last == g_queue_peek_tail (iter->buffers));
-  return TRUE;
+  return last != g_queue_peek_tail (iter->buffers);
 }
 static void
 pixbuf_destroy_notify (guchar *pixels, gpointer data)
@@ -377,25 +386,38 @@ gst_gdk_animation_iter_create_pixbuf (GstGdkAnimationIter *iter)
 static GdkPixbufAnimationIter*
 gst_gdk_animation_get_iter (GdkPixbufAnimation *anim, const GTimeVal *start_time)
 {
+  GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
   GstGdkAnimationIter *iter;
 
+  if (ani->temp_fd != 0 && lseek (ani->temp_fd, 0, SEEK_CUR) < GST_GDK_BUFFER_SIZE)
+    return NULL;
+
   iter = g_object_new (GST_TYPE_GDK_ANIMATION_ITER, NULL);
 
   iter->start = *start_time;
   
-  iter->ani = GST_GDK_ANIMATION (anim);
+  iter->ani = ani;
+  g_object_ref (ani);
   iter->pipeline = gst_gdk_animation_iter_create_pipeline (iter);
-  if (iter->pipeline == NULL) {
-    g_object_unref (iter);
-    return NULL;
-  }
+  if (iter->pipeline == NULL) 
+    goto error;
     
-  g_object_ref (iter->ani);
         
-  gst_gdk_animation_get_more_buffers (iter);
+  if (!gst_gdk_animation_get_more_buffers (iter))
+    goto error;
+  
   gst_gdk_animation_iter_create_pixbuf (iter);
+  if (!ani->pixbuf) {
+    /* set our static image */
+    g_object_ref (iter->pixbuf);
+    ani->pixbuf = iter->pixbuf;
+  }
         
   return GDK_PIXBUF_ANIMATION_ITER (iter);
+
+error:
+  g_object_unref (iter);
+  return NULL;
 }
 static gboolean
 gst_gdk_animation_iter_advance (GdkPixbufAnimationIter *anim_iter, const GTimeVal *current_time)
index de5ce05..1ac4867 100644 (file)
@@ -52,13 +52,13 @@ struct _GstGdkAnimation
   gchar *                      temp_location;
   /* file descriptor to temporary file or 0 if we're done writing */
   int                          temp_fd;
-  /* functions to notify the loader */
-
 
   /* size of image */
   gint                         width;
   gint                         height;
   gint                         bpp;
+  /* static image we use */
+  GdkPixbuf *                  pixbuf;
 };
 
 struct _GstGdkAnimationClass 
@@ -66,9 +66,14 @@ struct _GstGdkAnimationClass
   GdkPixbufAnimationClass      parent_class;
 };
 
-GType gst_gdk_animation_get_type (void);
+GType                  gst_gdk_animation_get_type      (void);
+
+GstGdkAnimation *      gst_gdk_animation_new           (GError **error);
 
-GdkPixbufAnimation *gst_gdk_animation_new_from_file (FILE *f, GError **error);
+gboolean               gst_gdk_animation_add_data      (GstGdkAnimation *      ani,
+                                                        const guint8 *         data,
+                                                        guint                  size);
+void                   gst_gdk_animation_done_adding   (GstGdkAnimation *      ani);
 
 
 #define GST_TYPE_GDK_ANIMATION_ITER            (gst_gdk_animation_iter_get_type ())