From f3d2d6f938dd25176d63db65fb2a4524b6c63514 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 11 Nov 2003 22:43:24 +0000 Subject: update GdkPixbuf loader. Fixes: 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 | 150 +++++++++++++++++++++++++++++++++++++-- ext/gdk_pixbuf/gstgdkanimation.c | 96 +++++++++++++++---------- ext/gdk_pixbuf/gstgdkanimation.h | 13 ++-- 3 files changed, 214 insertions(+), 45 deletions(-) (limited to 'ext/gdk_pixbuf') diff --git a/ext/gdk_pixbuf/gst_loader.c b/ext/gdk_pixbuf/gst_loader.c index 0a21b825..b8d1c9d7 100644 --- a/ext/gdk_pixbuf/gst_loader.c +++ b/ext/gdk_pixbuf/gst_loader.c @@ -24,19 +24,161 @@ #endif #include "gstgdkanimation.h" +#include #include +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) diff --git a/ext/gdk_pixbuf/gstgdkanimation.c b/ext/gdk_pixbuf/gstgdkanimation.c index 6519cc1b..9e1aa16f 100644 --- a/ext/gdk_pixbuf/gstgdkanimation.c +++ b/ext/gdk_pixbuf/gstgdkanimation.c @@ -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) diff --git a/ext/gdk_pixbuf/gstgdkanimation.h b/ext/gdk_pixbuf/gstgdkanimation.h index de5ce053..1ac48675 100644 --- a/ext/gdk_pixbuf/gstgdkanimation.h +++ b/ext/gdk_pixbuf/gstgdkanimation.h @@ -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 ()) -- cgit