mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-18 20:25:25 +00:00
add initial version of gdkpixbuf loader for gtk that is capable of loading AVI and mpeg videos as GdkPixbufAnimation....
Original commit message from CVS: add initial version of gdkpixbuf loader for gtk that is capable of loading AVI and mpeg videos as GdkPixbufAnimation. I'm not sure if such a thing would be useful or too much trouble, so I'll throw it at enough testers to figure it out ;) We might want to disable it by defualt though in the future. (Currently there is not even a configure switch implemented to disable it.) This includes a fix to not use GError in gstgdkpixbuf's typefind function and to only return GST_TYPE_FIND_MINIMUM when doing typefinding via gdk as this breaks quite a bit with the GStreamer loader installed.
This commit is contained in:
parent
bbd6c00598
commit
8468a02e24
6 changed files with 693 additions and 5 deletions
|
@ -225,6 +225,11 @@ HAVE_GTK=NO
|
||||||
PKG_CHECK_MODULES(GTK2, gtk+-2.0 >= 2.2.0, HAVE_GTK_22=yes, HAVE_GTK_22=no)
|
PKG_CHECK_MODULES(GTK2, gtk+-2.0 >= 2.2.0, HAVE_GTK_22=yes, HAVE_GTK_22=no)
|
||||||
if test "x$HAVE_GTK_22" = "xyes"; then
|
if test "x$HAVE_GTK_22" = "xyes"; then
|
||||||
HAVE_GTK=yes
|
HAVE_GTK=yes
|
||||||
|
AC_PATH_PROG(QUERYLOADERS, gdk-pixbuf-query-loaders, no)
|
||||||
|
GTK_VERSION=`$PKG_CONFIG --variable=gtk_binary_version gtk+-2.0`
|
||||||
|
AC_SUBST(GTK_VERSION)
|
||||||
|
GTK_BASE_DIR=`echo "$QUERYLOADERS" | sed "s/bin\/gdk-pixbuf-query-loaders\$//"`
|
||||||
|
AC_SUBST(GTK_BASE_DIR)
|
||||||
else
|
else
|
||||||
PKG_CHECK_MODULES(GTK2, gtk+-2.0, HAVE_GTK_20=yes, HAVE_GTK_20=no)
|
PKG_CHECK_MODULES(GTK2, gtk+-2.0, HAVE_GTK_20=yes, HAVE_GTK_20=no)
|
||||||
fi
|
fi
|
||||||
|
@ -236,6 +241,7 @@ GTK_LIBS=$GTK2_LIBS
|
||||||
AC_SUBST(GTK_LIBS)
|
AC_SUBST(GTK_LIBS)
|
||||||
AC_SUBST(GTK_CFLAGS)
|
AC_SUBST(GTK_CFLAGS)
|
||||||
AC_SUBST(HAVE_GTK)
|
AC_SUBST(HAVE_GTK)
|
||||||
|
AM_CONDITIONAL(HAVE_GDK_LOADERS, test "x$HAVE_GTK_22" = "xyes")
|
||||||
|
|
||||||
|
|
||||||
dnl Check for X11 extensions
|
dnl Check for X11 extensions
|
||||||
|
|
|
@ -6,5 +6,28 @@ libgstgdkpixbuf_la_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS)
|
||||||
libgstgdkpixbuf_la_LIBADD = $(GTK_LIBS)
|
libgstgdkpixbuf_la_LIBADD = $(GTK_LIBS)
|
||||||
libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = gstgdkpixbuf.h
|
|
||||||
|
|
||||||
|
if HAVE_GDK_LOADERS
|
||||||
|
loaderdir = $(GTK_BASE_DIR)/lib/gtk-2.0/$(GTK_VERSION)/loaders
|
||||||
|
loader_LTLIBRARIES = gst_loader.la
|
||||||
|
|
||||||
|
gst_loader_la_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) -DGDK_PIXBUF_ENABLE_BACKEND
|
||||||
|
gst_loader_la_SOURCES = \
|
||||||
|
gstgdkanimation.c \
|
||||||
|
gst_loader.c
|
||||||
|
gst_loader_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) --avoid-version --module
|
||||||
|
gst_loader_la_LIBADD = $(GTK_LIBS) $(GST_LIBS)
|
||||||
|
|
||||||
|
gst_loader_headers = gstgdkanimation.h
|
||||||
|
|
||||||
|
install-data-hook:
|
||||||
|
$(mkinstalldirs) $(GTK_BASE_DIR)/etc/gtk-2.0 ; \
|
||||||
|
$(QUERYLOADERS) > $(GTK_BASE_DIR)/etc/gtk-2.0/gdk-pixbuf.loaders ;
|
||||||
|
|
||||||
|
else
|
||||||
|
gst_loader_headers =
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
noinst_HEADERS = gstgdkpixbuf.h \
|
||||||
|
$(gst_loader_headers)
|
||||||
|
|
68
ext/gdk_pixbuf/gst_loader.c
Normal file
68
ext/gdk_pixbuf/gst_loader.c
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gst_loader.c: Load GStreamer videos as gdkpixbufs
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gstgdkanimation.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static GdkPixbufAnimation *
|
||||||
|
gst_loader_load_animation (FILE *f, GError **error)
|
||||||
|
{
|
||||||
|
return gst_gdk_animation_new_from_file (f, error);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
fill_vtable (GdkPixbufModule *module)
|
||||||
|
{
|
||||||
|
if (gst_init_check (0, NULL)) {
|
||||||
|
module->load_animation = gst_loader_load_animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void
|
||||||
|
fill_info (GdkPixbufFormat *info)
|
||||||
|
{
|
||||||
|
static GdkPixbufModulePattern signature[] = {
|
||||||
|
{ "RIFF AVI ", " xxxx ", 100 },
|
||||||
|
{ "\000\000\001\272", "", 100 },
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static gchar *mime_types[] = {
|
||||||
|
"video/avi",
|
||||||
|
"video/mpeg",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static gchar *extensions[] = {
|
||||||
|
"avi",
|
||||||
|
"mpeg", "mpe", "mpg",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
info->name = "GStreamer";
|
||||||
|
info->signature = signature;
|
||||||
|
info->description = "GStreamer supported video";
|
||||||
|
info->mime_types = mime_types;
|
||||||
|
info->extensions = extensions;
|
||||||
|
info->flags = 0;
|
||||||
|
}
|
483
ext/gdk_pixbuf/gstgdkanimation.c
Normal file
483
ext/gdk_pixbuf/gstgdkanimation.c
Normal file
|
@ -0,0 +1,483 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "gstgdkanimation.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gst_gdk_animation_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_gdk_animation_debug
|
||||||
|
|
||||||
|
static void gst_gdk_animation_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_gdk_animation_finalize (GObject * object);
|
||||||
|
|
||||||
|
static gboolean gst_gdk_animation_is_static_image (GdkPixbufAnimation * animation);
|
||||||
|
static GdkPixbuf* gst_gdk_animation_get_static_image (GdkPixbufAnimation * animation);
|
||||||
|
static void gst_gdk_animation_get_size (GdkPixbufAnimation * anim,
|
||||||
|
gint * width,
|
||||||
|
gint * height);
|
||||||
|
static GdkPixbufAnimationIter* gst_gdk_animation_get_iter (GdkPixbufAnimation * anim,
|
||||||
|
const GTimeVal * start_time);
|
||||||
|
|
||||||
|
|
||||||
|
static gpointer parent_class;
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_gdk_animation_get_type (void)
|
||||||
|
{
|
||||||
|
static GType object_type = 0;
|
||||||
|
|
||||||
|
if (!object_type) {
|
||||||
|
static const GTypeInfo object_info = {
|
||||||
|
sizeof (GstGdkAnimationClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_gdk_animation_class_init,
|
||||||
|
NULL, /* class_finalize */
|
||||||
|
NULL, /* class_data */
|
||||||
|
sizeof (GstGdkAnimation),
|
||||||
|
0, /* n_preallocs */
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
|
||||||
|
"GstGdkAnimation", &object_info, 0);
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_gdk_animation_debug, "gstloader_animation", 0, "GStreamer GdkPixbuf loader - GdkAnimation class");
|
||||||
|
}
|
||||||
|
|
||||||
|
return object_type;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_gdk_animation_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (g_class);
|
||||||
|
GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
object_class->finalize = gst_gdk_animation_finalize;
|
||||||
|
|
||||||
|
anim_class->is_static_image = gst_gdk_animation_is_static_image;
|
||||||
|
anim_class->get_static_image = gst_gdk_animation_get_static_image;
|
||||||
|
anim_class->get_size = gst_gdk_animation_get_size;
|
||||||
|
anim_class->get_iter = gst_gdk_animation_get_iter;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_gdk_animation_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
GstGdkAnimation *ani = GST_GDK_ANIMATION (object);
|
||||||
|
|
||||||
|
if (ani->temp_fd) {
|
||||||
|
close (ani->temp_fd);
|
||||||
|
}
|
||||||
|
if (ani->temp_location) {
|
||||||
|
remove (ani->temp_location);
|
||||||
|
g_free (ani->temp_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
GdkPixbufAnimation *
|
||||||
|
gst_gdk_animation_new_from_file (FILE *f, 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)
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_gdk_animation_is_static_image (GdkPixbufAnimation *animation)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkPixbuf*
|
||||||
|
gst_gdk_animation_get_static_image (GdkPixbufAnimation *animation)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_gdk_animation_get_size (GdkPixbufAnimation *anim, gint *width, int *height)
|
||||||
|
{
|
||||||
|
GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (ani, "get_size called (%p, %p) %d x %d", width, height, ani->width, ani->height);
|
||||||
|
if (width)
|
||||||
|
*width = ani->width;
|
||||||
|
|
||||||
|
if (height)
|
||||||
|
*height = ani->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_gdk_animation_iter_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_gdk_animation_iter_init (GTypeInstance * instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_gdk_animation_iter_finalize (GObject * object);
|
||||||
|
|
||||||
|
static gint gst_gdk_animation_iter_get_delay_time (GdkPixbufAnimationIter * iter);
|
||||||
|
static GdkPixbuf * gst_gdk_animation_iter_get_pixbuf (GdkPixbufAnimationIter * iter);
|
||||||
|
static gboolean gst_gdk_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter * iter);
|
||||||
|
static gboolean gst_gdk_animation_iter_advance (GdkPixbufAnimationIter * iter,
|
||||||
|
const GTimeVal * current_time);
|
||||||
|
|
||||||
|
static gpointer iter_parent_class;
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_gdk_animation_iter_get_type (void)
|
||||||
|
{
|
||||||
|
static GType object_type = 0;
|
||||||
|
|
||||||
|
if (!object_type) {
|
||||||
|
static const GTypeInfo object_info = {
|
||||||
|
sizeof (GstGdkAnimationIterClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_gdk_animation_iter_class_init,
|
||||||
|
NULL, /* class_finalize */
|
||||||
|
NULL, /* class_data */
|
||||||
|
sizeof (GstGdkAnimationIter),
|
||||||
|
0, /* n_preallocs */
|
||||||
|
gst_gdk_animation_iter_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
|
||||||
|
"GdkPixbufAniAnimIter", &object_info, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return object_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_gdk_animation_iter_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (g_class);
|
||||||
|
GdkPixbufAnimationIterClass *anim_iter_class = GDK_PIXBUF_ANIMATION_ITER_CLASS (g_class);
|
||||||
|
|
||||||
|
iter_parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
object_class->finalize = gst_gdk_animation_iter_finalize;
|
||||||
|
|
||||||
|
anim_iter_class->get_delay_time = gst_gdk_animation_iter_get_delay_time;
|
||||||
|
anim_iter_class->get_pixbuf = gst_gdk_animation_iter_get_pixbuf;
|
||||||
|
anim_iter_class->on_currently_loading_frame = gst_gdk_animation_iter_on_currently_loading_frame;
|
||||||
|
anim_iter_class->advance = gst_gdk_animation_iter_advance;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_gdk_animation_iter_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (instance);
|
||||||
|
|
||||||
|
iter->buffers = g_queue_new ();
|
||||||
|
iter->eos = FALSE;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_gdk_animation_iter_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (object);
|
||||||
|
|
||||||
|
g_object_unref (iter->ani);
|
||||||
|
|
||||||
|
if (iter->pipeline)
|
||||||
|
g_object_unref (iter->pipeline);
|
||||||
|
if (iter->pixbuf)
|
||||||
|
g_object_unref (iter->pixbuf);
|
||||||
|
while (iter->buffers) {
|
||||||
|
GstBuffer *buffer = GST_BUFFER (g_queue_pop_head (iter->buffers));
|
||||||
|
if (buffer) {
|
||||||
|
GST_LOG_OBJECT (iter, "unreffing buffer %p on finalize", buffer);
|
||||||
|
gst_data_unref (GST_DATA (buffer));
|
||||||
|
} else {
|
||||||
|
g_queue_free (iter->buffers);
|
||||||
|
iter->buffers = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
G_OBJECT_CLASS (iter_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
got_handoff (GstElement *fakesink, GstBuffer *buffer, GstGdkAnimationIter *iter)
|
||||||
|
{
|
||||||
|
GST_LOG_OBJECT (iter, "enqueing buffer %p", buffer);
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
g_queue_push_tail (iter->buffers, buffer);
|
||||||
|
}
|
||||||
|
static GstElement *
|
||||||
|
gst_gdk_animation_iter_create_pipeline (GstGdkAnimationIter *iter)
|
||||||
|
{
|
||||||
|
GstElement *ret;
|
||||||
|
GstElement *src, *autoplugger, *sink, *colorspace;
|
||||||
|
GstCaps *caps = GST_CAPS_NEW ("pixbuf_filter",
|
||||||
|
"video/x-raw-rgb",
|
||||||
|
"endianness", GST_PROPS_INT (G_BIG_ENDIAN),
|
||||||
|
"bpp", GST_PROPS_LIST (
|
||||||
|
GST_PROPS_INT (32),
|
||||||
|
GST_PROPS_INT (24)
|
||||||
|
),
|
||||||
|
"red_mask", GST_PROPS_INT (0x000000FF),
|
||||||
|
"green_mask", GST_PROPS_INT (0x0000FF00),
|
||||||
|
"blue_mask", GST_PROPS_INT (0x00FF0000)
|
||||||
|
);
|
||||||
|
|
||||||
|
ret = gst_element_factory_make ("pipeline", "main_pipeline");
|
||||||
|
if (!ret) return NULL;
|
||||||
|
|
||||||
|
if (!(src = gst_element_factory_make ("filesrc", "source")))
|
||||||
|
goto error;
|
||||||
|
gst_bin_add (GST_BIN (ret), src);
|
||||||
|
g_object_set (src, "location", iter->ani->temp_location, NULL);
|
||||||
|
|
||||||
|
if (!(autoplugger = gst_element_factory_make ("spider", "autoplugger")))
|
||||||
|
goto error;
|
||||||
|
gst_bin_add (GST_BIN (ret), autoplugger);
|
||||||
|
gst_element_link (src, autoplugger);
|
||||||
|
|
||||||
|
if (!(colorspace = gst_element_factory_make ("colorspace", "colorspace")))
|
||||||
|
goto error;
|
||||||
|
gst_bin_add (GST_BIN (ret), colorspace);
|
||||||
|
gst_element_link (autoplugger, colorspace);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
error:
|
||||||
|
g_object_unref (ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_gdk_animation_iter_may_advance (GstGdkAnimationIter *iter)
|
||||||
|
{
|
||||||
|
GstFormat bytes = GST_FORMAT_BYTES;
|
||||||
|
gint64 offset;
|
||||||
|
gint64 data_amount;
|
||||||
|
|
||||||
|
if (iter->ani->temp_fd == 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
data_amount = lseek (iter->ani->temp_fd, 0, SEEK_CUR);
|
||||||
|
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 */
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_gdk_animation_get_more_buffers (GstGdkAnimationIter *iter)
|
||||||
|
{
|
||||||
|
GstBuffer *last = g_queue_peek_tail (iter->buffers);
|
||||||
|
|
||||||
|
do {
|
||||||
|
GST_LOG_OBJECT (iter, "iterating...");
|
||||||
|
if (!gst_gdk_animation_iter_may_advance (iter))
|
||||||
|
return FALSE;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
pixbuf_destroy_notify (guchar *pixels, gpointer data)
|
||||||
|
{
|
||||||
|
GST_LOG ("unreffing buffer %p because pixbuf was destroyed", data);
|
||||||
|
gst_data_unref (GST_DATA (data));
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_gdk_animation_iter_create_pixbuf (GstGdkAnimationIter *iter)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
GstGdkAnimation *ani = iter->ani;
|
||||||
|
|
||||||
|
buf = g_queue_pop_head (iter->buffers);
|
||||||
|
g_assert (buf);
|
||||||
|
if (iter->pixbuf) {
|
||||||
|
GST_LOG_OBJECT (iter, "unreffing pixbuf %p", iter->pixbuf);
|
||||||
|
g_object_unref (iter->pixbuf);
|
||||||
|
}
|
||||||
|
if (ani->width == 0) {
|
||||||
|
GstPad *pad;
|
||||||
|
GstCaps *caps;
|
||||||
|
GstElement *fakesink = gst_bin_get_by_name (GST_BIN (iter->pipeline), "sink");
|
||||||
|
g_assert (fakesink);
|
||||||
|
pad = gst_element_get_pad (fakesink, "sink");
|
||||||
|
g_assert (pad);
|
||||||
|
caps = gst_pad_get_caps (pad);
|
||||||
|
g_assert (caps);
|
||||||
|
g_assert (GST_CAPS_IS_FIXED (caps));
|
||||||
|
g_assert (gst_caps_has_fixed_property (caps, "bpp") &&
|
||||||
|
gst_caps_has_fixed_property (caps, "width") &&
|
||||||
|
gst_caps_has_fixed_property (caps, "height"));
|
||||||
|
gst_caps_get_int (caps, "width", &ani->width);
|
||||||
|
gst_caps_get_int (caps, "height", &ani->height);
|
||||||
|
gst_caps_get_int (caps, "bpp", &ani->bpp);
|
||||||
|
GST_DEBUG_OBJECT (ani, "found format (width %d, height %d, bpp %d)", ani->width, ani->height, ani->bpp);
|
||||||
|
}
|
||||||
|
g_assert (GST_BUFFER_SIZE (buf) == ani->width * ani->height * ani->bpp / 8);
|
||||||
|
if (ani->bpp == 32) {
|
||||||
|
gint i;
|
||||||
|
guint32 *data = (guint32 *) GST_BUFFER_DATA (buf);
|
||||||
|
/* ensure opacity */
|
||||||
|
for (i = 0; i < ani->width * ani->height; i++) {
|
||||||
|
data[i] |= 0xFF000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iter->pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buf),
|
||||||
|
GDK_COLORSPACE_RGB, ani->bpp == 32, 8, ani->width, ani->height, ani->width * ani->bpp / 8, pixbuf_destroy_notify, buf);
|
||||||
|
GST_LOG_OBJECT (iter, "created pixbuf %p from buffer %p (refcount %d)", iter->pixbuf, buf, GST_DATA_REFCOUNT_VALUE (buf));
|
||||||
|
}
|
||||||
|
static GdkPixbufAnimationIter*
|
||||||
|
gst_gdk_animation_get_iter (GdkPixbufAnimation *anim, const GTimeVal *start_time)
|
||||||
|
{
|
||||||
|
GstGdkAnimationIter *iter;
|
||||||
|
|
||||||
|
iter = g_object_new (GST_TYPE_GDK_ANIMATION_ITER, NULL);
|
||||||
|
|
||||||
|
iter->start = *start_time;
|
||||||
|
|
||||||
|
iter->ani = GST_GDK_ANIMATION (anim);
|
||||||
|
iter->pipeline = gst_gdk_animation_iter_create_pipeline (iter);
|
||||||
|
if (iter->pipeline == NULL) {
|
||||||
|
g_object_unref (iter);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_gdk_animation_iter_advance (GdkPixbufAnimationIter *anim_iter, const GTimeVal *current_time)
|
||||||
|
{
|
||||||
|
GstClockTime offset;
|
||||||
|
GstBuffer *buffer = NULL;
|
||||||
|
GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
|
||||||
|
|
||||||
|
/* compute timestamp that next buffer must match */
|
||||||
|
GST_DEBUG_OBJECT (iter, "advancing to %ld:%ld (started at %ld:%ld)",
|
||||||
|
current_time->tv_sec, current_time->tv_usec, iter->start.tv_sec, iter->start.tv_usec);
|
||||||
|
offset = ((GstClockTime) current_time->tv_sec - iter->start.tv_sec) * GST_SECOND;
|
||||||
|
if (iter->start.tv_usec > current_time->tv_usec) {
|
||||||
|
offset -= ((GstClockTime) iter->start.tv_usec - current_time->tv_usec) * GST_SECOND / G_USEC_PER_SEC;
|
||||||
|
} else {
|
||||||
|
offset += ((GstClockTime) current_time->tv_usec - iter->start.tv_usec) * GST_SECOND / G_USEC_PER_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
if (g_queue_is_empty (iter->buffers)) {
|
||||||
|
if (iter->eos)
|
||||||
|
return FALSE;
|
||||||
|
if (gst_gdk_animation_get_more_buffers (iter))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (GST_BUFFER_TIMESTAMP (g_queue_peek_head (iter->buffers)) > offset)
|
||||||
|
break;
|
||||||
|
if (buffer) {
|
||||||
|
GST_LOG_OBJECT (iter, "unreffing buffer %p, because timestamp too low (%"G_GUINT64_FORMAT" vs %"G_GUINT64_FORMAT")",
|
||||||
|
buffer, GST_BUFFER_TIMESTAMP (buffer), offset);
|
||||||
|
gst_data_unref (GST_DATA (buffer));
|
||||||
|
}
|
||||||
|
buffer = GST_BUFFER (g_queue_pop_head (iter->buffers));
|
||||||
|
}
|
||||||
|
if (!buffer)
|
||||||
|
return FALSE;
|
||||||
|
iter->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
g_queue_push_head (iter->buffers, buffer);
|
||||||
|
gst_gdk_animation_iter_create_pixbuf (iter);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
gst_gdk_animation_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
|
||||||
|
{
|
||||||
|
gint delay;
|
||||||
|
GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
|
||||||
|
|
||||||
|
while (g_queue_is_empty (iter->buffers)) {
|
||||||
|
if (iter->eos) {
|
||||||
|
GST_LOG_OBJECT (iter, "returning delay of infinite, we're EOS");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!gst_gdk_animation_get_more_buffers (iter))
|
||||||
|
return -1; /* FIXME? */
|
||||||
|
}
|
||||||
|
|
||||||
|
delay = (GST_BUFFER_TIMESTAMP (g_queue_peek_head (iter->buffers)) - iter->last_timestamp) *
|
||||||
|
1000 / GST_SECOND;
|
||||||
|
GST_LOG_OBJECT (iter, "returning delay of %d ms", delay);
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
GdkPixbuf*
|
||||||
|
gst_gdk_animation_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
|
||||||
|
{
|
||||||
|
GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (iter, "returning pixbuf %p", iter->pixbuf);
|
||||||
|
return iter->pixbuf;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_gdk_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
|
||||||
|
{
|
||||||
|
GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
|
||||||
|
|
||||||
|
/* EOS - last frame */
|
||||||
|
if (iter->eos && g_queue_is_empty (iter->buffers))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* can't load more frames */
|
||||||
|
if (!gst_gdk_animation_iter_may_advance (iter))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
109
ext/gdk_pixbuf/gstgdkanimation.h
Normal file
109
ext/gdk_pixbuf/gstgdkanimation.h
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GST_LOADER_H__
|
||||||
|
#define __GST_LOADER_H__
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
#include <gdk-pixbuf/gdk-pixbuf-animation.h>
|
||||||
|
#include <gdk-pixbuf/gdk-pixbuf-io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* how many bytes we need to have available before we dare to start a new iteration */
|
||||||
|
#define GST_GDK_BUFFER_SIZE 102400
|
||||||
|
|
||||||
|
|
||||||
|
#define GST_TYPE_GDK_ANIMATION (gst_gdk_animation_get_type())
|
||||||
|
#define GST_GDK_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_ANIMATION,GstGdkAnimation))
|
||||||
|
#define GST_GDK_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_ANIMATION,GstGdkAnimation))
|
||||||
|
#define GST_IS_GDK_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_ANIMATION))
|
||||||
|
#define GST_IS_GDK_ANIMATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_ANIMATION))
|
||||||
|
|
||||||
|
typedef struct _GstGdkAnimation GstGdkAnimation;
|
||||||
|
typedef struct _GstGdkAnimationClass GstGdkAnimationClass;
|
||||||
|
|
||||||
|
typedef struct _GstGdkAnimationIter GstGdkAnimationIter;
|
||||||
|
typedef struct _GstGdkAnimationIterClass GstGdkAnimationIterClass;
|
||||||
|
|
||||||
|
struct _GstGdkAnimation
|
||||||
|
{
|
||||||
|
GdkPixbufAnimation parent;
|
||||||
|
|
||||||
|
/* name of temporary buffer file */
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstGdkAnimationClass
|
||||||
|
{
|
||||||
|
GdkPixbufAnimationClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_gdk_animation_get_type (void);
|
||||||
|
|
||||||
|
GdkPixbufAnimation *gst_gdk_animation_new_from_file (FILE *f, GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
#define GST_TYPE_GDK_ANIMATION_ITER (gst_gdk_animation_iter_get_type ())
|
||||||
|
#define GST_GDK_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIter))
|
||||||
|
#define GST_IS_GDK_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GST_TYPE_GDK_ANIMATION_ITER))
|
||||||
|
|
||||||
|
#define GST_GDK_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIterClass))
|
||||||
|
#define GST_IS_GDK_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GDK_ANIMATION_ITER))
|
||||||
|
#define GST_GDK_ANIMATION_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIterClass))
|
||||||
|
|
||||||
|
struct _GstGdkAnimationIter {
|
||||||
|
GdkPixbufAnimationIter parent;
|
||||||
|
|
||||||
|
/* our animation */
|
||||||
|
GstGdkAnimation * ani;
|
||||||
|
/* start timeval */
|
||||||
|
GTimeVal start;
|
||||||
|
/* timestamp of last buffer */
|
||||||
|
GstClockTime last_timestamp;
|
||||||
|
|
||||||
|
/* pipeline we're using */
|
||||||
|
GstElement * pipeline;
|
||||||
|
gboolean eos;
|
||||||
|
|
||||||
|
/* current image and the buffers containing the data */
|
||||||
|
GdkPixbuf * pixbuf;
|
||||||
|
GQueue * buffers;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstGdkAnimationIterClass {
|
||||||
|
GdkPixbufAnimationIterClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_gdk_animation_iter_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_GDK_ANIMATION_H__ */
|
|
@ -382,7 +382,6 @@ gst_gdk_pixbuf_type_find (GstTypeFind *tf, gpointer ignore)
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
GdkPixbufLoader *pixbuf_loader;
|
GdkPixbufLoader *pixbuf_loader;
|
||||||
GdkPixbufFormat *format;
|
GdkPixbufFormat *format;
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
data = gst_type_find_peek (tf, 0, GST_GDK_PIXBUF_TYPE_FIND_SIZE);
|
data = gst_type_find_peek (tf, 0, GST_GDK_PIXBUF_TYPE_FIND_SIZE);
|
||||||
if (data == NULL) return;
|
if (data == NULL) return;
|
||||||
|
@ -392,18 +391,18 @@ gst_gdk_pixbuf_type_find (GstTypeFind *tf, gpointer ignore)
|
||||||
pixbuf_loader = gdk_pixbuf_loader_new();
|
pixbuf_loader = gdk_pixbuf_loader_new();
|
||||||
|
|
||||||
gdk_pixbuf_loader_write (pixbuf_loader, data, GST_GDK_PIXBUF_TYPE_FIND_SIZE,
|
gdk_pixbuf_loader_write (pixbuf_loader, data, GST_GDK_PIXBUF_TYPE_FIND_SIZE,
|
||||||
&error);
|
NULL);
|
||||||
|
|
||||||
format = gdk_pixbuf_loader_get_format (pixbuf_loader);
|
format = gdk_pixbuf_loader_get_format (pixbuf_loader);
|
||||||
|
|
||||||
if (format != NULL) {
|
if (format != NULL) {
|
||||||
gchar **mlist = gdk_pixbuf_format_get_mime_types(format);
|
gchar **mlist = gdk_pixbuf_format_get_mime_types(format);
|
||||||
|
|
||||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM,
|
gst_type_find_suggest (tf, GST_TYPE_FIND_MINIMUM,
|
||||||
gst_caps_new ("gdk_pixbuf_type_find", mlist[0], NULL));
|
gst_caps_new ("gdk_pixbuf_type_find", mlist[0], NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
gdk_pixbuf_loader_close (pixbuf_loader, &error);
|
gdk_pixbuf_loader_close (pixbuf_loader, NULL);
|
||||||
g_object_unref (G_OBJECT (pixbuf_loader));
|
g_object_unref (G_OBJECT (pixbuf_loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue