mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
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 :)
This commit is contained in:
parent
c72f2fd4ed
commit
f3d2d6f938
3 changed files with 214 additions and 45 deletions
|
@ -24,19 +24,161 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstgdkanimation.h"
|
#include "gstgdkanimation.h"
|
||||||
|
#include <gst/gstinfo.h>
|
||||||
#include <stdio.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 *
|
static GdkPixbufAnimation *
|
||||||
gst_loader_load_animation (FILE *f, GError **error)
|
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
|
void
|
||||||
fill_vtable (GdkPixbufModule *module)
|
fill_vtable (GdkPixbufModule *module)
|
||||||
{
|
{
|
||||||
if (gst_init_check (0, NULL)) {
|
module->begin_load = gst_loader_begin_load;
|
||||||
module->load_animation = gst_loader_load_animation;
|
module->load_increment = gst_loader_load_increment;
|
||||||
}
|
module->stop_load = gst_loader_stop_load;
|
||||||
|
module->load_animation = gst_loader_load_animation;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
fill_info (GdkPixbufFormat *info)
|
fill_info (GdkPixbufFormat *info)
|
||||||
|
|
|
@ -93,35 +93,36 @@ gst_gdk_animation_finalize (GObject *object)
|
||||||
remove (ani->temp_location);
|
remove (ani->temp_location);
|
||||||
g_free (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);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
GdkPixbufAnimation *
|
GstGdkAnimation *
|
||||||
gst_gdk_animation_new_from_file (FILE *f, GError **error)
|
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));
|
GstGdkAnimation *ani = GST_GDK_ANIMATION (g_object_new (GST_TYPE_GDK_ANIMATION, NULL));
|
||||||
|
|
||||||
fd2 = g_file_open_tmp (NULL, &ani->temp_location, error);
|
ani->temp_fd = g_file_open_tmp (NULL, &ani->temp_location, error);
|
||||||
if (fd2 == -1)
|
if (ani->temp_fd == 0) {
|
||||||
|
g_object_unref (ani);
|
||||||
return NULL;
|
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 */
|
return ani;
|
||||||
g_get_current_time (&tv);
|
}
|
||||||
iter = gst_gdk_animation_get_iter (GDK_PIXBUF_ANIMATION (ani), &tv);
|
gboolean
|
||||||
g_object_unref (iter);
|
gst_gdk_animation_add_data (GstGdkAnimation *ani, const guint8 *data, guint size)
|
||||||
|
{
|
||||||
return GDK_PIXBUF_ANIMATION (ani);
|
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
|
static gboolean
|
||||||
gst_gdk_animation_is_static_image (GdkPixbufAnimation *animation)
|
gst_gdk_animation_is_static_image (GdkPixbufAnimation *animation)
|
||||||
|
@ -132,7 +133,9 @@ gst_gdk_animation_is_static_image (GdkPixbufAnimation *animation)
|
||||||
static GdkPixbuf*
|
static GdkPixbuf*
|
||||||
gst_gdk_animation_get_static_image (GdkPixbufAnimation *animation)
|
gst_gdk_animation_get_static_image (GdkPixbufAnimation *animation)
|
||||||
{
|
{
|
||||||
return NULL;
|
GstGdkAnimation *ani = GST_GDK_ANIMATION (animation);
|
||||||
|
|
||||||
|
return ani->pixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -269,20 +272,24 @@ gst_gdk_animation_iter_create_pipeline (GstGdkAnimationIter *iter)
|
||||||
if (!(autoplugger = gst_element_factory_make ("spider", "autoplugger")))
|
if (!(autoplugger = gst_element_factory_make ("spider", "autoplugger")))
|
||||||
goto error;
|
goto error;
|
||||||
gst_bin_add (GST_BIN (ret), autoplugger);
|
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")))
|
if (!(colorspace = gst_element_factory_make ("colorspace", "colorspace")))
|
||||||
goto error;
|
goto error;
|
||||||
gst_bin_add (GST_BIN (ret), colorspace);
|
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")))
|
if (!(sink = gst_element_factory_make ("fakesink", "sink")))
|
||||||
goto error;
|
goto error;
|
||||||
g_object_set (sink, "signal-handoffs", TRUE, NULL);
|
g_object_set (sink, "signal-handoffs", TRUE, NULL);
|
||||||
g_signal_connect (sink, "handoff", (GCallback) got_handoff, iter);
|
g_signal_connect (sink, "handoff", (GCallback) got_handoff, iter);
|
||||||
gst_bin_add (GST_BIN (ret), sink);
|
gst_bin_add (GST_BIN (ret), sink);
|
||||||
gst_element_link_filtered (colorspace, sink, caps);
|
if (!gst_element_link_filtered (colorspace, sink, caps))
|
||||||
gst_element_set_state (ret, GST_STATE_PLAYING);
|
goto error;
|
||||||
|
if (gst_element_set_state (ret, GST_STATE_PLAYING) != GST_STATE_SUCCESS)
|
||||||
|
goto error;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
error:
|
error:
|
||||||
|
@ -303,7 +310,7 @@ gst_gdk_animation_iter_may_advance (GstGdkAnimationIter *iter)
|
||||||
g_assert (data_amount >= 0);
|
g_assert (data_amount >= 0);
|
||||||
g_assert (gst_element_query (gst_bin_get_by_name (GST_BIN (iter->pipeline), "source"),
|
g_assert (gst_element_query (gst_bin_get_by_name (GST_BIN (iter->pipeline), "source"),
|
||||||
GST_QUERY_POSITION, &bytes, &offset));
|
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 TRUE;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -315,15 +322,17 @@ gst_gdk_animation_get_more_buffers (GstGdkAnimationIter *iter)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
GST_LOG_OBJECT (iter, "iterating...");
|
GST_LOG_OBJECT (iter, "iterating...");
|
||||||
if (!gst_gdk_animation_iter_may_advance (iter))
|
if (!gst_gdk_animation_iter_may_advance (iter)) {
|
||||||
return FALSE;
|
GST_LOG_OBJECT (iter, "no more data available");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!gst_bin_iterate (GST_BIN (iter->pipeline))) {
|
if (!gst_bin_iterate (GST_BIN (iter->pipeline))) {
|
||||||
GST_LOG_OBJECT (iter, "iterating done, setting EOS");
|
GST_LOG_OBJECT (iter, "iterating done, setting EOS");
|
||||||
iter->eos = TRUE;
|
iter->eos = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (last == g_queue_peek_tail (iter->buffers));
|
} while (last == g_queue_peek_tail (iter->buffers));
|
||||||
return TRUE;
|
return last != g_queue_peek_tail (iter->buffers);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
pixbuf_destroy_notify (guchar *pixels, gpointer data)
|
pixbuf_destroy_notify (guchar *pixels, gpointer data)
|
||||||
|
@ -377,25 +386,38 @@ gst_gdk_animation_iter_create_pixbuf (GstGdkAnimationIter *iter)
|
||||||
static GdkPixbufAnimationIter*
|
static GdkPixbufAnimationIter*
|
||||||
gst_gdk_animation_get_iter (GdkPixbufAnimation *anim, const GTimeVal *start_time)
|
gst_gdk_animation_get_iter (GdkPixbufAnimation *anim, const GTimeVal *start_time)
|
||||||
{
|
{
|
||||||
|
GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
|
||||||
GstGdkAnimationIter *iter;
|
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 = g_object_new (GST_TYPE_GDK_ANIMATION_ITER, NULL);
|
||||||
|
|
||||||
iter->start = *start_time;
|
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);
|
iter->pipeline = gst_gdk_animation_iter_create_pipeline (iter);
|
||||||
if (iter->pipeline == NULL) {
|
if (iter->pipeline == NULL)
|
||||||
g_object_unref (iter);
|
goto error;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_ref (iter->ani);
|
|
||||||
|
|
||||||
gst_gdk_animation_get_more_buffers (iter);
|
|
||||||
gst_gdk_animation_iter_create_pixbuf (iter);
|
|
||||||
|
|
||||||
return GDK_PIXBUF_ANIMATION_ITER (iter);
|
return GDK_PIXBUF_ANIMATION_ITER (iter);
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_object_unref (iter);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_gdk_animation_iter_advance (GdkPixbufAnimationIter *anim_iter, const GTimeVal *current_time)
|
gst_gdk_animation_iter_advance (GdkPixbufAnimationIter *anim_iter, const GTimeVal *current_time)
|
||||||
|
|
|
@ -52,13 +52,13 @@ struct _GstGdkAnimation
|
||||||
gchar * temp_location;
|
gchar * temp_location;
|
||||||
/* file descriptor to temporary file or 0 if we're done writing */
|
/* file descriptor to temporary file or 0 if we're done writing */
|
||||||
int temp_fd;
|
int temp_fd;
|
||||||
/* functions to notify the loader */
|
|
||||||
|
|
||||||
|
|
||||||
/* size of image */
|
/* size of image */
|
||||||
gint width;
|
gint width;
|
||||||
gint height;
|
gint height;
|
||||||
gint bpp;
|
gint bpp;
|
||||||
|
/* static image we use */
|
||||||
|
GdkPixbuf * pixbuf;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstGdkAnimationClass
|
struct _GstGdkAnimationClass
|
||||||
|
@ -66,9 +66,14 @@ struct _GstGdkAnimationClass
|
||||||
GdkPixbufAnimationClass parent_class;
|
GdkPixbufAnimationClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_gdk_animation_get_type (void);
|
GType gst_gdk_animation_get_type (void);
|
||||||
|
|
||||||
GdkPixbufAnimation *gst_gdk_animation_new_from_file (FILE *f, GError **error);
|
GstGdkAnimation * gst_gdk_animation_new (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 ())
|
#define GST_TYPE_GDK_ANIMATION_ITER (gst_gdk_animation_iter_get_type ())
|
||||||
|
|
Loading…
Reference in a new issue