From 73a6055bdf16990ff6abaed612b8527db439a9f8 Mon Sep 17 00:00:00 2001 From: Edgard Lima Date: Fri, 24 Feb 2006 19:51:29 +0000 Subject: [PATCH] I'm too lazy to comment this Original commit message from CVS: Gdkpixbuf ported from 0.8 to 0.10 by Renato Filho . gst_loader and gdkpixbufanimation still need port. --- ChangeLog | 13 + configure.ac | 10 + ext/Makefile.am | 9 +- ext/gdk_pixbuf/Makefile.am | 39 +-- ext/gdk_pixbuf/gstgdkpixbuf.c | 352 ++++++++++---------- ext/gdk_pixbuf/gstgdkpixbuf.h | 14 +- ext/gdk_pixbuf/pixbufscale.c | 585 +++++++++++++++++----------------- ext/gdk_pixbuf/pixbufscale.h | 29 +- 8 files changed, 546 insertions(+), 505 deletions(-) diff --git a/ChangeLog b/ChangeLog index de476b11ad..83b55a44bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2006-02-24 Edgard Lima + + * configure.ac: + * ext/Makefile.am: + * ext/gdk_pixbuf/Makefile.am: + * ext/gdk_pixbuf/gstgdkpixbuf.c: + * ext/gdk_pixbuf/gstgdkpixbuf.h: + * ext/gdk_pixbuf/pixbufscale.c: + * ext/gdk_pixbuf/pixbufscale.h: + Gdkpixbuf ported from 0.8 to 0.10 by + Renato Filho . + gst_loader and gdkpixbufanimation still need port. + 2006-02-24 Michael Smith * configure.ac: diff --git a/configure.ac b/configure.ac index 87b8d6956a..4fac20d5c9 100644 --- a/configure.ac +++ b/configure.ac @@ -232,6 +232,9 @@ if test "x$HAVE_GTK_22" = "xyes"; then AC_SUBST(GTK_VERSION) GTK_PREFIX=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0` AC_SUBST(GTK_BASE_DIR) + GDK_PIXBUF_LIBDIR=`$PKG_CONFIG --variable=libdir gdk-pixbuf-2.0` + GDK_PIXBUF_PREFIXDIR=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0` + AC_SUBST(GTK_BASE_DIR) else PKG_CHECK_MODULES(GTK2, gtk+-2.0, HAVE_GTK_20=yes, HAVE_GTK_20=no) fi @@ -399,6 +402,12 @@ GST_CHECK_FEATURE(GCONF, [GConf libraries], , [ AC_SUBST(GCONF_LIBS) ]) +dnl *** GDK pixbuf *** +translit(dnm, m, l) AM_CONDITIONAL(USE_GDK_PIXBUF, true) +GST_CHECK_FEATURE(GDK_PIXBUF, [GDK pixbuf], gdkpixbufsrc, [ + if test $HAVE_GTK_22 = "yes"; then HAVE_GDK_PIXBUF=yes; fi; +]) + dnl *** HAL *** translit(dnm, m, l) AM_CONDITIONAL(USE_HAL, true) GST_CHECK_FEATURE(HAL, [HAL libraries], , [ @@ -639,6 +648,7 @@ ext/dv/Makefile ext/esd/Makefile ext/flac/Makefile ext/gconf/Makefile +ext/gdk_pixbuf/Makefile ext/hal/Makefile ext/ladspa/Makefile ext/libcaca/Makefile diff --git a/ext/Makefile.am b/ext/Makefile.am index e8bdd8c544..bfc10ccfb0 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -40,11 +40,11 @@ else GCONF_DIR = endif -# if USE_GDK_PIXBUF -# GDK_PIXBUF_DIR = gdk_pixbuf -# else +if USE_GDK_PIXBUF +GDK_PIXBUF_DIR = gdk_pixbuf +else GDK_PIXBUF_DIR = -# endif +endif if USE_HAL HAL_DIR = hal @@ -141,6 +141,7 @@ DIST_SUBDIRS = \ esd \ flac \ gconf \ + gdk_pixbuf \ hal \ jpeg \ ladspa \ diff --git a/ext/gdk_pixbuf/Makefile.am b/ext/gdk_pixbuf/Makefile.am index ac18389a27..8d5abb0385 100644 --- a/ext/gdk_pixbuf/Makefile.am +++ b/ext/gdk_pixbuf/Makefile.am @@ -1,30 +1,31 @@ plugin_LTLIBRARIES = libgstgdkpixbuf.la libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c pixbufscale.c -libgstgdkpixbuf_la_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) -libgstgdkpixbuf_la_LIBADD = $(GST_LIBS) $(GTK_LIBS) +libgstgdkpixbuf_la_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) $(GST_BASE_CFLAGS) +libgstgdkpixbuf_la_LIBADD = $(GTK_LIBS) $(GST_BASE_LIBS) libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -if HAVE_GDK_LOADERS -loaderdir = $(DESTDIR)$(GDK_PIXBUF_LOADER_DIR) -loader_LTLIBRARIES = gst_loader.la -install-data-hook: - if test -z "$(DESTDIR)" ; then \ - $(mkinstalldirs) $(DESTDIR)$(GDK_PIXBUF_CONF_DIR) ; \ - $(QUERYLOADERS) > $(DESTDIR)$(GDK_PIXBUF_CONF_DIR)/gdk-pixbuf.loaders ; \ - fi - -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) -gst_loader_la_LIBADD = $(GTK_LIBS) $(GST_LIBS) -else +#if +#loaderdir = $(DESTDIR)$(GDK_PIXBUF_LOADER_DIR) +#loader_LTLIBRARIES = gst_loader.la +# +#install-data-hook: +# if test -z "$(DESTDIR)" ; then \ +# $(mkinstalldirs) $(DESTDIR)$(GDK_PIXBUF_CONF_DIR) ; \ +# $(QUERYLOADERS) > $(DESTDIR)$(GDK_PIXBUF_CONF_DIR)/gdk-pixbuf.loaders ; \ +# fi +# +#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) +#else install-data-hook: true -endif +#endif noinst_HEADERS = gstgdkpixbuf.h \ pixbufscale.h \ diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.c b/ext/gdk_pixbuf/gstgdkpixbuf.c index 34a1678e8b..34dcae948c 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.c +++ b/ext/gdk_pixbuf/gstgdkpixbuf.c @@ -37,7 +37,7 @@ static GstElementDetails plugin_details = { "GdkPixbuf image decoder", "Codec/Decoder/Image", "Decodes images in a video stream using GdkPixbuf", - "David A. Schleef ", + "David A. Schleef , Renato Filho ", }; /* Filter signals and args */ @@ -53,6 +53,8 @@ enum ARG_SILENT }; + + static GstStaticPadTemplate gst_gdk_pixbuf_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -88,46 +90,53 @@ gboolean pixbufscale_init (GstPlugin * plugin); static void gst_gdk_pixbuf_base_init (gpointer g_class); static void gst_gdk_pixbuf_class_init (GstGdkPixbufClass * klass); -static void gst_gdk_pixbuf_init (GstGdkPixbuf * filter); +static void gst_gdk_pixbuf_init (GstGdkPixbuf * filter, + GstGdkPixbufClass * klass); static void gst_gdk_pixbuf_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_gdk_pixbuf_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_gdk_pixbuf_chain (GstPad * pad, GstData * _data); +static GstFlowReturn gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_gdk_pixbuf_event (GstPad * pad, GstEvent * event); #ifdef enable_typefind static void gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore); #endif -static GstElementClass *parent_class = NULL; -static GstPadLinkReturn -gst_gdk_pixbuf_sink_link (GstPad * pad, const GstCaps * caps) +GST_BOILERPLATE (GstGdkPixbuf, gst_gdk_pixbuf, GstElement, GST_TYPE_ELEMENT) + + static gboolean gst_gdk_pixbuf_sink_setcaps (GstPad * pad, GstCaps * caps) { GstGdkPixbuf *filter; - const GValue *fps; + const GValue *framerate; + GstStructure *s; filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad)); - g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED); - g_return_val_if_fail (GST_IS_GDK_PIXBUF (filter), GST_PAD_LINK_REFUSED); + s = gst_caps_get_structure (caps, 0); - fps = gst_structure_get_value (gst_caps_get_structure (caps, 0), "framerate"); - if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) { - filter->fps_n = gst_value_get_fraction_numerator (fps); - filter->fps_d = gst_value_get_fraction_denominator (fps); - } else - return GST_PAD_LINK_REFUSED; + filter->framerate_numerator = 0; + filter->framerate_denominator = 1; + if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) { + filter->framerate_numerator = gst_value_get_fraction_numerator (framerate); + filter->framerate_denominator = + gst_value_get_fraction_denominator (framerate); + GST_DEBUG ("got framerate of %d/%d fps => packetized mode", + filter->framerate_numerator, filter->framerate_denominator); + } - return GST_PAD_LINK_OK; + return TRUE; } + #if GDK_PIXBUF_MAJOR == 2 && GDK_PIXBUF_MINOR < 2 /* gdk-pixbuf prior to 2.2 didn't have gdk_pixbuf_get_formats(). * These are just the formats that gdk-pixbuf is known to support. * But maybe not -- it may have been compiled without an external * library. */ + static GstCaps * gst_gdk_pixbuf_get_capslist (void) { @@ -162,7 +171,7 @@ gst_gdk_pixbuf_get_capslist (void) return_caps = gst_caps_intersect (capslist, gst_static_caps_get (&gst_gdk_pixbuf_sink_template.static_caps)); - gst_caps_free (capslist); + gst_caps_unref (capslist); return return_caps; } #endif @@ -179,30 +188,6 @@ gst_gdk_pixbuf_sink_getcaps (GstPad * pad) return gst_gdk_pixbuf_get_capslist (); } -GType -gst_gdk_pixbuf_get_type (void) -{ - static GType plugin_type = 0; - - if (!plugin_type) { - static const GTypeInfo plugin_info = { - sizeof (GstGdkPixbufClass), - gst_gdk_pixbuf_base_init, - NULL, - (GClassInitFunc) gst_gdk_pixbuf_class_init, - NULL, - NULL, - sizeof (GstGdkPixbuf), - 0, - (GInstanceInitFunc) gst_gdk_pixbuf_init, - }; - - plugin_type = g_type_register_static (GST_TYPE_ELEMENT, - "GstGdkPixbuf", &plugin_info, 0); - } - return plugin_type; -} - static void gst_gdk_pixbuf_base_init (gpointer g_class) { @@ -227,161 +212,189 @@ gst_gdk_pixbuf_class_init (GstGdkPixbufClass * klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + gobject_class->set_property = gst_gdk_pixbuf_set_property; + gobject_class->get_property = gst_gdk_pixbuf_get_property; + + g_object_class_install_property (gobject_class, ARG_SILENT, g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?", FALSE, G_PARAM_READWRITE)); - gobject_class->set_property = gst_gdk_pixbuf_set_property; - gobject_class->get_property = gst_gdk_pixbuf_get_property; } static void -gst_gdk_pixbuf_init (GstGdkPixbuf * filter) +gst_gdk_pixbuf_init (GstGdkPixbuf * filter, GstGdkPixbufClass * klass) { filter->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&gst_gdk_pixbuf_sink_template), "sink"); - gst_pad_set_link_function (filter->sinkpad, gst_gdk_pixbuf_sink_link); + gst_pad_set_setcaps_function (filter->sinkpad, gst_gdk_pixbuf_sink_setcaps); gst_pad_set_getcaps_function (filter->sinkpad, gst_gdk_pixbuf_sink_getcaps); - filter->srcpad = - gst_pad_new_from_template (gst_static_pad_template_get - (&gst_gdk_pixbuf_src_template), "src"); - gst_pad_use_explicit_caps (filter->srcpad); + gst_pad_set_chain_function (filter->sinkpad, + (GstPadChainFunction) gst_gdk_pixbuf_chain); + + gst_pad_set_event_function (filter->sinkpad, gst_gdk_pixbuf_event); + gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); - gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); - gst_pad_set_chain_function (filter->sinkpad, gst_gdk_pixbuf_chain); - GST_OBJECT_FLAG_SET (GST_ELEMENT (filter), GST_ELEMENT_EVENT_AWARE); + + filter->srcpad = gst_pad_new_from_template (gst_static_pad_template_get + (&gst_gdk_pixbuf_src_template), "src"); + + gst_pad_use_fixed_caps (filter->srcpad); + gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); + + filter->last_timestamp = GST_CLOCK_TIME_NONE; + filter->pixbuf_loader = NULL; } -static void -gst_gdk_pixbuf_chain (GstPad * pad, GstData * _data) +static GstFlowReturn +gst_gdk_pixbuf_flush (GstGdkPixbuf * filter) +{ + GstBuffer *outbuf; + GdkPixbuf *pixbuf; + int y; + guint8 *out_pix; + guint8 *in_pix; + int in_rowstride; + GstFlowReturn ret; + GstCaps *caps = NULL; + + pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader); + if (pixbuf == NULL) { + GST_DEBUG ("error geting pixbuf"); + return GST_FLOW_ERROR; + } + + if (filter->image_size == 0) { + filter->width = gdk_pixbuf_get_width (pixbuf); + filter->height = gdk_pixbuf_get_height (pixbuf); + filter->rowstride = gdk_pixbuf_get_rowstride (pixbuf); + filter->image_size = filter->rowstride * filter->height; + + if (gdk_pixbuf_get_rowstride (pixbuf) / filter->width == 4) { + caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBA); + } else if (gdk_pixbuf_get_rowstride (pixbuf) / filter->width == 3) { + caps = gst_caps_from_string (GST_VIDEO_CAPS_RGB); + } else { + GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), + ("Bpp %d not supported", gdk_pixbuf_get_bits_per_sample (pixbuf))); + return GST_FLOW_ERROR; + } + gst_caps_set_simple (caps, + "width", G_TYPE_INT, filter->width, + "height", G_TYPE_INT, filter->height, + "framerate", GST_TYPE_FRACTION, filter->framerate_numerator, + filter->framerate_denominator, NULL); + + GST_DEBUG ("Set size to %dx%d", filter->width, filter->height); + gst_pad_set_caps (filter->srcpad, caps); + gst_caps_unref (caps); + } + + ret = gst_pad_alloc_buffer_and_set_caps (filter->srcpad, + GST_BUFFER_OFFSET_NONE, + filter->image_size, GST_PAD_CAPS (filter->srcpad), &outbuf); + + if (ret != GST_FLOW_OK) { + GST_DEBUG ("Failed to create outbuffer - %d", ret); + return GST_FLOW_ERROR; + } + + gst_caps_unref (caps); + caps = gst_pad_get_negotiated_caps (filter->srcpad); + GST_DEBUG ("Caps negotiated %s", gst_caps_to_string (caps)); + gst_caps_unref (caps); + + GST_BUFFER_TIMESTAMP (outbuf) = filter->last_timestamp; + GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; + + in_pix = gdk_pixbuf_get_pixels (pixbuf); + in_rowstride = gdk_pixbuf_get_rowstride (pixbuf); + out_pix = GST_BUFFER_DATA (outbuf); + + for (y = 0; y < filter->height; y++) { + memcpy (out_pix, in_pix, filter->rowstride); + in_pix += in_rowstride; + out_pix += filter->rowstride; + } + + GST_DEBUG ("pushing... %d bytes", GST_BUFFER_SIZE (outbuf)); + return gst_pad_push (filter->srcpad, outbuf); +} + +static gboolean +gst_gdk_pixbuf_event (GstPad * pad, GstEvent * event) +{ + GstFlowReturn res = GST_FLOW_OK; + gboolean ret = TRUE; + GstGdkPixbuf *pixbuf; + + pixbuf = GST_GDK_PIXBUF (gst_pad_get_parent (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL); + res = gst_gdk_pixbuf_flush (pixbuf); + g_object_unref (G_OBJECT (pixbuf->pixbuf_loader)); + break; + case GST_EVENT_NEWSEGMENT: + case GST_EVENT_FLUSH_STOP: + if (pixbuf->pixbuf_loader != NULL) { + gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL); + g_object_unref (G_OBJECT (pixbuf->pixbuf_loader)); + pixbuf->pixbuf_loader = NULL; + } + break; + default: + break; + } + + if (res == GST_FLOW_OK) { + ret = gst_pad_event_default (pad, event); + } else { + ret = FALSE; + } + + gst_object_unref (pixbuf); + + return ret; +} + +static GstFlowReturn +gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf) { - GstBuffer *buf = GST_BUFFER (_data); GstGdkPixbuf *filter; + GstFlowReturn ret = GST_FLOW_OK; GError *error = NULL; - gboolean push_buffer = FALSE; - gboolean dump_buffer = FALSE; - gboolean got_eos = FALSE; + GstClockTime timestamp; GST_DEBUG ("gst_gdk_pixbuf_chain"); + filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad)); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); + timestamp = GST_BUFFER_TIMESTAMP (buf); - filter = GST_GDK_PIXBUF (GST_OBJECT_PARENT (pad)); - g_return_if_fail (GST_IS_GDK_PIXBUF (filter)); - - if (GST_IS_EVENT (_data)) { - GstEvent *event = GST_EVENT (buf); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - push_buffer = TRUE; - got_eos = TRUE; - break; - case GST_EVENT_DISCONTINUOUS: - dump_buffer = TRUE; - break; - default: - gst_pad_event_default (pad, event); - return; - } + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + filter->last_timestamp = timestamp; } - if (filter->last_timestamp != GST_BUFFER_TIMESTAMP (buf)) { - push_buffer = TRUE; + if (filter->pixbuf_loader == NULL) { + filter->pixbuf_loader = gdk_pixbuf_loader_new (); } - if (push_buffer) { - if (filter->pixbuf_loader != NULL) { - GstBuffer *outbuf; - GdkPixbuf *pixbuf; - GError *error = NULL; - - if (!gdk_pixbuf_loader_close (filter->pixbuf_loader, &error)) { - GST_ELEMENT_ERROR (filter, LIBRARY, SHUTDOWN, (NULL), (error->message)); - g_error_free (error); - return; - } - - pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader); - - if (filter->image_size == 0) { - GstCaps *caps; - - filter->width = gdk_pixbuf_get_width (pixbuf); - filter->height = gdk_pixbuf_get_height (pixbuf); - /* gdk_pixbuf likes to pad rowstride to 4 byte boundaries which we can't do - * at the moment - */ - filter->rowstride = filter->width * 3; - filter->image_size = filter->rowstride * filter->height; - - caps = gst_caps_copy (gst_pad_get_pad_template_caps (filter->srcpad)); - gst_caps_set_simple (caps, - "width", G_TYPE_INT, filter->width, - "height", G_TYPE_INT, filter->height, - "framerate", G_TYPE_DOUBLE, filter->framerate, NULL); - - gst_pad_set_explicit_caps (filter->srcpad, caps); - } - - outbuf = - gst_pad_alloc_buffer_and_set_caps (filter->srcpad, - GST_BUFFER_OFFSET_NONE, filter->image_size); - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); - GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf); - - { - int y; - guint8 *out_pix; - guint8 *in_pix; - int in_rowstride; - - in_pix = gdk_pixbuf_get_pixels (pixbuf); - in_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - out_pix = GST_BUFFER_DATA (outbuf); - - for (y = 0; y < filter->height; y++) { - memcpy (out_pix, in_pix, filter->rowstride); - in_pix += in_rowstride; - out_pix += filter->rowstride; - } - } - - gst_pad_push (filter->srcpad, GST_DATA (outbuf)); - - g_object_unref (G_OBJECT (filter->pixbuf_loader)); - filter->pixbuf_loader = NULL; - dump_buffer = FALSE; - } + GST_DEBUG ("Writing buffer size %d", GST_BUFFER_SIZE (buf)); + if (gdk_pixbuf_loader_write (filter->pixbuf_loader, GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf), &error) == FALSE) { + GST_DEBUG ("gst_gdk_pixbuf_chain ERROR: %s", error->message); + ret = GST_FLOW_ERROR; + goto need_more_data; } - if (dump_buffer) { - if (filter->pixbuf_loader != NULL) { - gdk_pixbuf_loader_close (filter->pixbuf_loader, NULL); - g_object_unref (G_OBJECT (filter->pixbuf_loader)); - filter->pixbuf_loader = NULL; - } - } - - if (GST_IS_BUFFER (_data)) { - if (filter->pixbuf_loader == NULL) { - filter->pixbuf_loader = gdk_pixbuf_loader_new (); - filter->last_timestamp = GST_BUFFER_TIMESTAMP (buf); - } - - gdk_pixbuf_loader_write (filter->pixbuf_loader, GST_BUFFER_DATA (buf), - GST_BUFFER_SIZE (buf), &error); - gst_buffer_unref (buf); - } - - if (got_eos) { - gst_pad_event_default (pad, GST_EVENT (_data)); - } +need_more_data: + gst_object_unref (filter); + return ret; } static void @@ -395,7 +408,7 @@ gst_gdk_pixbuf_set_property (GObject * object, guint prop_id, switch (prop_id) { case ARG_SILENT: - //filter->silent = g_value_get_boolean (value); + /* filter->silent = g_value_get_boolean (value); */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -414,7 +427,7 @@ gst_gdk_pixbuf_get_property (GObject * object, guint prop_id, switch (prop_id) { case ARG_SILENT: - //g_value_set_boolean (value, filter->silent); + /* g_value_set_boolean (value, filter->silent); */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -496,10 +509,11 @@ plugin_init (GstPlugin * plugin) return TRUE; } + /* this is the structure that gst-register looks for * so keep the name plugin_desc, or you cannot get your plug-in registered */ GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "gdkpixbuf", - "GDK Pixbuf decoder & scaler", plugin_init, VERSION, "LGPL", - GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) + "GDK Pixbuf decoder & scaler", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.h b/ext/gdk_pixbuf/gstgdkpixbuf.h index 4a1f9a3dc3..a6f527a2df 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.h +++ b/ext/gdk_pixbuf/gstgdkpixbuf.h @@ -28,15 +28,15 @@ G_BEGIN_DECLS /* #define's don't like whitespacey bits */ -#define GST_TYPE_GDK_PIXBUF \ +#define GST_TYPE_GDK_PIXBUF \ (gst_gdk_pixbuf_get_type()) -#define GST_GDK_PIXBUF(obj) \ +#define GST_GDK_PIXBUF(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF,GstGdkPixbuf)) -#define GST_GDK_PIXBUF_CLASS(klass) \ +#define GST_GDK_PIXBUF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF,GstGdkPixbuf)) -#define GST_IS_GDK_PIXBUF(obj) \ +#define GST_IS_GDK_PIXBUF(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF)) -#define GST_IS_GDK_PIXBUF_CLASS(obj) \ +#define GST_IS_GDK_PIXBUF_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF)) typedef struct _GstGdkPixbuf GstGdkPixbuf; @@ -56,8 +56,8 @@ struct _GstGdkPixbuf int rowstride; unsigned int image_size; - gint fps_n; - gint fps_d; + gint framerate_numerator; + gint framerate_denominator; }; struct _GstGdkPixbufClass diff --git a/ext/gdk_pixbuf/pixbufscale.c b/ext/gdk_pixbuf/pixbufscale.c index 6b52b426af..77b955bc78 100644 --- a/ext/gdk_pixbuf/pixbufscale.c +++ b/ext/gdk_pixbuf/pixbufscale.c @@ -36,7 +36,6 @@ #define GST_RGB24_SIZE(width,height) ((height)*GST_RGB24_ROWSTRIDE(width)) -/* debug variable definition */ GST_DEBUG_CATEGORY (pixbufscale_debug); #define GST_CAT_DEFAULT pixbufscale_debug @@ -45,7 +44,9 @@ static GstElementDetails pixbufscale_details = GST_ELEMENT_DETAILS ("Gdk Pixbuf scaler", "Filter/Effect/Video", "Resizes video", - "Jan Schmidt \nWim Taymans "); + "Jan Schmidt \n" + "Wim Taymans \n" + "Renato Filho "); /* GstPixbufScale signals and args */ enum @@ -81,10 +82,10 @@ gst_pixbufscale_method_get_type (void) { static GType pixbufscale_method_type = 0; static GEnumValue pixbufscale_methods[] = { - {GST_PIXBUFSCALE_NEAREST, "Nearest Neighbour", "nearest"}, - {GST_PIXBUFSCALE_TILES, "Tiles", "tiles"}, - {GST_PIXBUFSCALE_BILINEAR, "Bilinear", "bilinear"}, - {GST_PIXBUFSCALE_HYPER, "Hyper", "hyper"}, + {GST_PIXBUFSCALE_NEAREST, "0", "Nearest Neighbour"}, + {GST_PIXBUFSCALE_TILES, "1", "Tiles"}, + {GST_PIXBUFSCALE_BILINEAR, "2", "Bilinear"}, + {GST_PIXBUFSCALE_HYPER, "3", "Hyper"}, {0, NULL, NULL}, }; @@ -97,46 +98,33 @@ gst_pixbufscale_method_get_type (void) static void gst_pixbufscale_base_init (gpointer g_class); static void gst_pixbufscale_class_init (GstPixbufScaleClass * klass); -static void gst_pixbufscale_init (GstPixbufScale * pixbufscale); -static gboolean gst_pixbufscale_handle_src_event (GstPad * pad, - GstEvent * event); - +static void gst_pixbufscale_init (GstPixbufScale * pixbufscale, + GstPixbufScaleClass * kclass); static void gst_pixbufscale_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_pixbufscale_chain (GstPad * pad, GstData * _data); +static GstCaps *gst_pixbufscale_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps); +static gboolean gst_pixbufscale_set_caps (GstBaseTransform * trans, + GstCaps * in, GstCaps * out); +static gboolean gst_pixbufscale_get_unit_size (GstBaseTransform * trans, + GstCaps * caps, guint * size); +static void gst_pixbufscale_fixate_caps (GstBaseTransform * base, + GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); +static GstFlowReturn gst_pixbufscale_transform (GstBaseTransform * trans, + GstBuffer * in, GstBuffer * out); +static gboolean gst_pixbufscale_handle_src_event (GstPad * pad, + GstEvent * event); -static GstElementClass *parent_class = NULL; -GType -gst_pixbufscale_get_type (void) -{ - static GType pixbufscale_type = 0; +static gboolean parse_caps (GstCaps * caps, gint * width, gint * height); - if (!pixbufscale_type) { - static const GTypeInfo pixbufscale_info = { - sizeof (GstPixbufScaleClass), - gst_pixbufscale_base_init, - NULL, - (GClassInitFunc) gst_pixbufscale_class_init, - NULL, - NULL, - sizeof (GstPixbufScale), - 0, - (GInstanceInitFunc) gst_pixbufscale_init, - }; +GST_BOILERPLATE (GstPixbufScale, gst_pixbufscale, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM) - pixbufscale_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstPixbufScale", - &pixbufscale_info, 0); - } - return pixbufscale_type; -} - -static void -gst_pixbufscale_base_init (gpointer g_class) + static void gst_pixbufscale_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); @@ -151,279 +139,45 @@ static void gst_pixbufscale_class_init (GstPixbufScaleClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; + GstBaseTransformClass *trans_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; + trans_class = (GstBaseTransformClass *) klass; - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD, + gobject_class->set_property = gst_pixbufscale_set_property; + gobject_class->get_property = gst_pixbufscale_get_property; + + g_object_class_install_property (gobject_class, + ARG_METHOD, g_param_spec_enum ("method", "method", "method", GST_TYPE_PIXBUFSCALE_METHOD, GST_PIXBUFSCALE_BILINEAR, G_PARAM_READWRITE)); - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + trans_class->transform_caps = + GST_DEBUG_FUNCPTR (gst_pixbufscale_transform_caps); + trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_set_caps); + trans_class->get_unit_size = + GST_DEBUG_FUNCPTR (gst_pixbufscale_get_unit_size); + trans_class->transform = GST_DEBUG_FUNCPTR (gst_pixbufscale_transform); + trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_fixate_caps); + trans_class->passthrough_on_same_caps = TRUE; - gobject_class->set_property = gst_pixbufscale_set_property; - gobject_class->get_property = gst_pixbufscale_get_property; -} - -static GstCaps * -gst_pixbufscale_getcaps (GstPad * pad) -{ - GstPixbufScale *pixbufscale; - GstCaps *othercaps; - GstCaps *caps; - GstPad *otherpad; - int i; - - pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad)); - - otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad : - pixbufscale->srcpad; - othercaps = gst_pad_get_allowed_caps (otherpad); - - caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad)); - gst_caps_free (othercaps); - - for (i = 0; i < gst_caps_get_size (caps); i++) { - GstStructure *structure = gst_caps_get_structure (caps, i); - - gst_structure_set (structure, - "width", GST_TYPE_INT_RANGE, 16, 4096, - "height", GST_TYPE_INT_RANGE, 16, 4096, NULL); - gst_structure_remove_field (structure, "pixel-aspect-ratio"); - } - - GST_DEBUG ("getcaps are: %" GST_PTR_FORMAT, caps); - return caps; -} - -static GstPadLinkReturn -gst_pixbufscale_link (GstPad * pad, const GstCaps * caps) -{ - GstPixbufScale *pixbufscale; - GstPadLinkReturn ret; - GstPad *otherpad; - GstStructure *structure; - int height, width; - gchar *caps_string; - - caps_string = gst_caps_to_string (caps); - GST_DEBUG ("gst_pixbufscale_link %s\n", caps_string); - g_free (caps_string); - - pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad)); - - otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad : - pixbufscale->srcpad; - - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", &width); - ret &= gst_structure_get_int (structure, "height", &height); - - ret = gst_pad_try_set_caps (otherpad, caps); - if (ret == GST_PAD_LINK_OK) { - /* cool, we can use passthru */ - - pixbufscale->to_width = width; - pixbufscale->to_height = height; - pixbufscale->from_width = width; - pixbufscale->from_height = height; - - pixbufscale->from_buf_size = GST_RGB24_SIZE (width, height); - pixbufscale->to_buf_size = GST_RGB24_SIZE (width, height); - pixbufscale->from_stride = GST_RGB24_ROWSTRIDE (width); - pixbufscale->to_stride = GST_RGB24_ROWSTRIDE (width); - - pixbufscale->inited = TRUE; - - return GST_PAD_LINK_OK; - } - - if (gst_pad_is_negotiated (otherpad)) { - GstCaps *newcaps = gst_caps_copy (caps); - - if (pad == pixbufscale->srcpad) { - gst_caps_set_simple (newcaps, - "width", G_TYPE_INT, pixbufscale->from_width, - "height", G_TYPE_INT, pixbufscale->from_height, NULL); - } else { - gst_caps_set_simple (newcaps, - "width", G_TYPE_INT, pixbufscale->to_width, - "height", G_TYPE_INT, pixbufscale->to_height, NULL); - } - ret = gst_pad_try_set_caps (otherpad, newcaps); - if (GST_PAD_LINK_FAILED (ret)) { - return GST_PAD_LINK_REFUSED; - } - } - - pixbufscale->passthru = FALSE; - - if (pad == pixbufscale->srcpad) { - pixbufscale->to_width = width; - pixbufscale->to_height = height; - } else { - pixbufscale->from_width = width; - pixbufscale->from_height = height; - } - - if (gst_pad_is_negotiated (otherpad)) { - pixbufscale->from_buf_size = - GST_RGB24_SIZE (pixbufscale->from_width, pixbufscale->from_height); - pixbufscale->to_buf_size = - GST_RGB24_SIZE (pixbufscale->to_width, pixbufscale->to_height); - pixbufscale->from_stride = GST_RGB24_ROWSTRIDE (pixbufscale->from_width); - pixbufscale->to_stride = GST_RGB24_ROWSTRIDE (pixbufscale->to_width); - pixbufscale->inited = TRUE; - } - - return GST_PAD_LINK_OK; + parent_class = g_type_class_peek_parent (klass); } static void -gst_pixbufscale_init (GstPixbufScale * pixbufscale) +gst_pixbufscale_init (GstPixbufScale * pixbufscale, + GstPixbufScaleClass * kclass) { GST_DEBUG_OBJECT (pixbufscale, "_init"); - pixbufscale->sinkpad = - gst_pad_new_from_template (gst_static_pad_template_get - (&gst_pixbufscale_sink_template), "sink"); - gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->sinkpad); - gst_pad_set_chain_function (pixbufscale->sinkpad, gst_pixbufscale_chain); - gst_pad_set_link_function (pixbufscale->sinkpad, gst_pixbufscale_link); - gst_pad_set_getcaps_function (pixbufscale->sinkpad, gst_pixbufscale_getcaps); + GstBaseTransform *trans = GST_BASE_TRANSFORM (pixbufscale); - pixbufscale->srcpad = - gst_pad_new_from_template (gst_static_pad_template_get - (&gst_pixbufscale_src_template), "src"); - gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->srcpad); - gst_pad_set_event_function (pixbufscale->srcpad, - gst_pixbufscale_handle_src_event); - gst_pad_set_link_function (pixbufscale->srcpad, gst_pixbufscale_link); - gst_pad_set_getcaps_function (pixbufscale->srcpad, gst_pixbufscale_getcaps); - - pixbufscale->inited = FALSE; + gst_pad_set_event_function (trans->srcpad, gst_pixbufscale_handle_src_event); pixbufscale->method = GST_PIXBUFSCALE_TILES; pixbufscale->gdk_method = GDK_INTERP_TILES; } -static gboolean -gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event) -{ - GstPixbufScale *pixbufscale; - double a; - GstStructure *structure; - GstEvent *new_event; - - pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NAVIGATION: - structure = gst_structure_copy (event->event_data.structure.structure); - if (gst_structure_get_double (event->event_data.structure.structure, - "pointer_x", &a)) { - gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, - a * pixbufscale->from_width / pixbufscale->to_width, NULL); - } - if (gst_structure_get_double (event->event_data.structure.structure, - "pointer_y", &a)) { - gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, - a * pixbufscale->from_height / pixbufscale->to_height, NULL); - } - gst_event_unref (event); - new_event = gst_event_new (GST_EVENT_NAVIGATION); - new_event->event_data.structure.structure = structure; - return gst_pad_event_default (pad, new_event); - break; - default: - return gst_pad_event_default (pad, event); - break; - } -} - -static void -pixbufscale_scale (GstPixbufScale * scale, unsigned char *dest, - unsigned char *src) -{ - GdkPixbuf *src_pixbuf, *dest_pixbuf; - - src_pixbuf = gdk_pixbuf_new_from_data - (src, GDK_COLORSPACE_RGB, FALSE, - 8, scale->from_width, scale->from_height, - GST_RGB24_ROWSTRIDE (scale->from_width), NULL, NULL); - dest_pixbuf = gdk_pixbuf_new_from_data - (dest, GDK_COLORSPACE_RGB, FALSE, - 8, scale->to_width, scale->to_height, - GST_RGB24_ROWSTRIDE (scale->to_width), NULL, NULL); - gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0, scale->to_width, - scale->to_height, 0, 0, - (double) scale->to_width / scale->from_width, - (double) scale->to_height / scale->from_height, scale->gdk_method); - - dest_pixbuf = gdk_pixbuf_scale_simple - (src_pixbuf, scale->to_width, scale->to_height, scale->gdk_method); - - g_object_unref (src_pixbuf); - g_object_unref (dest_pixbuf); -} - -static void -gst_pixbufscale_chain (GstPad * pad, GstData * _data) -{ - GstBuffer *buf = GST_BUFFER (_data); - GstPixbufScale *pixbufscale; - guchar *data; - gulong size; - GstBuffer *outbuf; - - g_return_if_fail (pad != NULL); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); - - pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad)); - g_return_if_fail (pixbufscale->inited); - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - if (pixbufscale->passthru) { - GST_LOG_OBJECT (pixbufscale, "passing through buffer of %ld bytes in '%s'", - size, GST_OBJECT_NAME (pixbufscale)); - gst_pad_push (pixbufscale->srcpad, GST_DATA (buf)); - return; - } - - GST_LOG_OBJECT (pixbufscale, "got buffer of %ld bytes in '%s'", size, - GST_OBJECT_NAME (pixbufscale)); - GST_LOG_OBJECT (pixbufscale, - "size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d", - size, pixbufscale->from_width, pixbufscale->from_height, - pixbufscale->to_width, pixbufscale->to_height, size, - pixbufscale->from_buf_size, pixbufscale->to_buf_size); - - if (size != pixbufscale->from_buf_size) { - GST_ERROR ("Incoming RGB data is %d bytes (expected: %d bytes) (%dx%d)\n", - size, pixbufscale->from_buf_size, pixbufscale->from_width, - pixbufscale->from_height); - return; - } - - outbuf = gst_pad_alloc_buffer_and_set_caps (pixbufscale->srcpad, - GST_BUFFER_OFFSET_NONE, pixbufscale->to_buf_size); - - gst_buffer_stamp (outbuf, buf); - - pixbufscale_scale (pixbufscale, GST_BUFFER_DATA (outbuf), data); - - GST_DEBUG_OBJECT (pixbufscale, "pushing buffer of %d bytes in '%s'", - GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (pixbufscale)); - - gst_pad_push (pixbufscale->srcpad, GST_DATA (outbuf)); - - gst_buffer_unref (buf); -} - static void gst_pixbufscale_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -476,6 +230,255 @@ gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value, } +static GstCaps * +gst_pixbufscale_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps) +{ + GstPixbufScale *pixbufscale; + GstCaps *ret; + int i; + + pixbufscale = GST_PIXBUFSCALE (trans); + ret = gst_caps_copy (caps); + + for (i = 0; i < gst_caps_get_size (ret); i++) { + GstStructure *structure = gst_caps_get_structure (ret, i); + + gst_structure_set (structure, + "width", GST_TYPE_INT_RANGE, 16, 4096, + "height", GST_TYPE_INT_RANGE, 16, 4096, NULL); + gst_structure_remove_field (structure, "pixel-aspect-ratio"); + } + + GST_DEBUG_OBJECT (trans, "returning caps: %", ret); + return ret; +} + +static gboolean +parse_caps (GstCaps * caps, gint * width, gint * height) +{ + gboolean ret; + GstStructure *structure; + + structure = gst_caps_get_structure (caps, 0); + ret = gst_structure_get_int (structure, "width", width); + ret &= gst_structure_get_int (structure, "height", height); + + return ret; +} + +static gboolean +gst_pixbufscale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) +{ + GstPixbufScale *pixbufscale; + gboolean ret; + + pixbufscale = GST_PIXBUFSCALE (trans); + ret = parse_caps (in, &pixbufscale->from_width, &pixbufscale->from_height); + ret &= parse_caps (out, &pixbufscale->to_width, &pixbufscale->to_height); + if (!ret) + goto done; + + pixbufscale->from_stride = GST_ROUND_UP_4 (pixbufscale->from_width * 3); + pixbufscale->from_buf_size = + pixbufscale->from_stride * pixbufscale->from_height; + + pixbufscale->to_stride = GST_ROUND_UP_4 (pixbufscale->to_width * 3); + pixbufscale->to_buf_size = pixbufscale->to_stride * pixbufscale->to_height; + + GST_DEBUG_OBJECT (pixbufscale, "from=%dx%d, size %d -> to=%dx%d, size %d", + pixbufscale->from_width, pixbufscale->from_height, + pixbufscale->from_buf_size, pixbufscale->to_width, pixbufscale->to_height, + pixbufscale->to_buf_size); + +done: + return ret; +} + + +static gboolean +gst_pixbufscale_get_unit_size (GstBaseTransform * trans, + GstCaps * caps, guint * size) +{ + GstPixbufScale *pixbufscale; + gint width, height; + + g_return_val_if_fail (size, FALSE); + + pixbufscale = GST_PIXBUFSCALE (trans); + + if (!parse_caps (caps, &width, &height)) + return FALSE; + + *size = GST_ROUND_UP_4 (width * 3) * height; + + return TRUE; +} + +static void +gst_pixbufscale_fixate_caps (GstBaseTransform * base, GstPadDirection direction, + GstCaps * caps, GstCaps * othercaps) +{ + GstStructure *ins, *outs; + const GValue *from_par, *to_par; + + g_return_if_fail (gst_caps_is_fixed (caps)); + + GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT + " based on caps %" GST_PTR_FORMAT, othercaps, caps); + + ins = gst_caps_get_structure (caps, 0); + outs = gst_caps_get_structure (othercaps, 0); + + from_par = gst_structure_get_value (ins, "pixel-aspect-ratio"); + to_par = gst_structure_get_value (outs, "pixel-aspect-ratio"); + + if (from_par && to_par) { + GValue to_ratio = { 0, }; /* w/h of output video */ + int from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d; + int count = 0, w = 0, h = 0, num, den; + + /* if both width and height are already fixed, we can't do anything + * * about it anymore */ + if (gst_structure_get_int (outs, "width", &w)) + ++count; + if (gst_structure_get_int (outs, "height", &h)) + ++count; + if (count == 2) { + GST_DEBUG_OBJECT (base, "dimensions already set to %dx%d, not fixating", + w, h); + return; + } + + gst_structure_get_int (ins, "width", &from_w); + gst_structure_get_int (ins, "height", &from_h); + from_par_n = gst_value_get_fraction_numerator (from_par); + from_par_d = gst_value_get_fraction_denominator (from_par); + to_par_n = gst_value_get_fraction_numerator (to_par); + to_par_d = gst_value_get_fraction_denominator (to_par); + + g_value_init (&to_ratio, GST_TYPE_FRACTION); + gst_value_set_fraction (&to_ratio, from_w * from_par_n * to_par_d, + from_h * from_par_d * to_par_n); + num = gst_value_get_fraction_numerator (&to_ratio); + den = gst_value_get_fraction_denominator (&to_ratio); + GST_DEBUG_OBJECT (base, + "scaling input with %dx%d and PAR %d/%d to output PAR %d/%d", + from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d); + GST_DEBUG_OBJECT (base, + "resulting output should respect ratio of %d/%d", num, den); + + /* now find a width x height that respects this display ratio. + * * prefer those that have one of w/h the same as the incoming video + * * using wd / hd = num / den */ + + /* start with same height, because of interlaced video */ + /* check hd / den is an integer scale factor, and scale wd with the PAR */ + if (from_h % den == 0) { + GST_DEBUG_OBJECT (base, "keeping video height"); + h = from_h; + w = h * num / den; + } else if (from_w % num == 0) { + GST_DEBUG_OBJECT (base, "keeping video width"); + w = from_w; + h = w * den / num; + } else { + GST_DEBUG_OBJECT (base, "approximating but keeping video height"); + h = from_h; + w = h * num / den; + } + GST_DEBUG_OBJECT (base, "scaling to %dx%d", w, h); + /* now fixate */ + gst_structure_fixate_field_nearest_int (outs, "width", w); + gst_structure_fixate_field_nearest_int (outs, "height", h); + } else { + gint width, height; + + if (gst_structure_get_int (ins, "width", &width)) { + if (gst_structure_has_field (outs, "width")) { + gst_structure_fixate_field_nearest_int (outs, "width", width); + } + } + if (gst_structure_get_int (ins, "height", &height)) { + if (gst_structure_has_field (outs, "height")) { + gst_structure_fixate_field_nearest_int (outs, "height", height); + } + } + } + + GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps); +} + +static GstFlowReturn +gst_pixbufscale_transform (GstBaseTransform * trans, + GstBuffer * in, GstBuffer * out) +{ + GstPixbufScale *scale; + GdkPixbuf *src_pixbuf, *dest_pixbuf; + + scale = GST_PIXBUFSCALE (trans); + + src_pixbuf = + gdk_pixbuf_new_from_data (GST_BUFFER_DATA (in), GDK_COLORSPACE_RGB, FALSE, + 8, scale->from_width, scale->from_height, + GST_RGB24_ROWSTRIDE (scale->from_width), NULL, NULL); + + dest_pixbuf = + gdk_pixbuf_new_from_data (GST_BUFFER_DATA (out), GDK_COLORSPACE_RGB, + FALSE, 8, scale->to_width, scale->to_height, + GST_RGB24_ROWSTRIDE (scale->to_width), NULL, NULL); + + gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0, + scale->to_width, + scale->to_height, 0, 0, + (double) scale->to_width / scale->from_width, + (double) scale->to_height / scale->from_height, scale->gdk_method); + + g_object_unref (src_pixbuf); + g_object_unref (dest_pixbuf); + + return GST_FLOW_OK; +} + +static gboolean +gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event) +{ + GstPixbufScale *pixbufscale; + gboolean ret; + double a; + GstStructure *structure; + + pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (pixbufscale, "handling %s event", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NAVIGATION: + event = + GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); + + structure = (GstStructure *) gst_event_get_structure (event); + if (gst_structure_get_double (structure, "pointer_x", &a)) { + gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, + a * pixbufscale->from_width / pixbufscale->to_width, NULL); + } + if (gst_structure_get_double (structure, "pointer_y", &a)) { + gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, + a * pixbufscale->from_height / pixbufscale->to_height, NULL); + } + break; + default: + break; + } + + ret = gst_pad_event_default (pad, event); + + gst_object_unref (pixbufscale); + + return ret; +} + gboolean pixbufscale_init (GstPlugin * plugin) { diff --git a/ext/gdk_pixbuf/pixbufscale.h b/ext/gdk_pixbuf/pixbufscale.h index 0d9b10fe1f..275a0b72f9 100644 --- a/ext/gdk_pixbuf/pixbufscale.h +++ b/ext/gdk_pixbuf/pixbufscale.h @@ -25,9 +25,21 @@ #include #include +#include G_BEGIN_DECLS +#define GST_TYPE_PIXBUFSCALE \ + (gst_pixbufscale_get_type()) +#define GST_PIXBUFSCALE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PIXBUFSCALE,GstPixbufScale)) +#define GST_PIXBUFSCALE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PIXBUFSCALE,GstPixbufScale)) +#define GST_IS_PIXBUFSCALE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PIXBUFSCALE)) +#define GST_IS_PIXBUFSCALE_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PIXBUFSCALE)) + typedef enum { GST_PIXBUFSCALE_NEAREST, GST_PIXBUFSCALE_TILES, @@ -35,27 +47,14 @@ typedef enum { GST_PIXBUFSCALE_HYPER } GstPixbufScaleMethod; -#define GST_TYPE_PIXBUFSCALE \ - (gst_pixbufscale_get_type()) -#define GST_PIXBUFSCALE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PIXBUFSCALE,GstPixbufScale)) -#define GST_PIXBUFSCALE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PIXBUFSCALE,GstPixbufScale)) -#define GST_IS_PIXBUFSCALE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PIXBUFSCALE)) -#define GST_IS_PIXBUFSCALE_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PIXBUFSCALE)) typedef struct _GstPixbufScale GstPixbufScale; typedef struct _GstPixbufScaleClass GstPixbufScaleClass; struct _GstPixbufScale { - GstElement element; - - GstPad *sinkpad,*srcpad; + GstBaseTransform element; /* video state */ - gboolean inited; gint to_width; gint to_height; gint from_width; @@ -73,7 +72,7 @@ struct _GstPixbufScale { }; struct _GstPixbufScaleClass { - GstElementClass parent_class; + GstBaseTransformClass parent_class; }; static GType gst_pixbufscale_get_type(void);