From e4908795d7a54fc29b42eccd621fc63c15f5eff4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Jul 2004 10:56:31 +0000 Subject: [PATCH] ext/libpng/: Added png decoder. Original commit message from CVS: * ext/libpng/Makefile.am: * ext/libpng/gstpng.c: (plugin_init): * ext/libpng/gstpngdec.c: (user_error_fn), (user_warning_fn), (gst_pngdec_get_type), (gst_pngdec_base_init), (gst_pngdec_class_init), (gst_pngdec_sinklink), (gst_pngdec_init), (gst_pngdec_src_getcaps), (user_read_data), (gst_pngdec_chain): * ext/libpng/gstpngdec.h: Added png decoder. --- ChangeLog | 21 +++ ext/libpng/Makefile.am | 4 +- ext/libpng/gstpng.c | 5 + ext/libpng/gstpngdec.c | 342 +++++++++++++++++++++++++++++++++++++++++ ext/libpng/gstpngdec.h | 74 +++++++++ 5 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 ext/libpng/gstpngdec.c create mode 100644 ext/libpng/gstpngdec.h diff --git a/ChangeLog b/ChangeLog index 4f168a0170..d269b64be0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2004-07-16 Wim Taymans + + * ext/libpng/Makefile.am: + * ext/libpng/gstpng.c: (plugin_init): + * ext/libpng/gstpngdec.c: (user_error_fn), (user_warning_fn), + (gst_pngdec_get_type), (gst_pngdec_base_init), + (gst_pngdec_class_init), (gst_pngdec_sinklink), (gst_pngdec_init), + (gst_pngdec_src_getcaps), (user_read_data), (gst_pngdec_chain): + * ext/libpng/gstpngdec.h: + Added png decoder. + 2004-07-16 Julien MOUTTE * sys/ximage/ximagesink.c: (gst_ximagesink_handle_xerror), @@ -15,6 +26,16 @@ data to be coherent with the buffer alloc mechanism. Investigated the image destruction code to be sure that everything gets freed correctly. +2004-07-16 Wim Taymans + + * gst-libs/gst/riff/riff-read.c: + (gst_riff_read_strf_vids_with_data), + (gst_riff_read_strf_auds_with_data): + * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query), + (gst_avi_demux_add_stream), (gst_avi_demux_stream_header): + Make sure we don't create 0 sized subbufers in riff-read. + Signal the no more pads signal after reading the avi header. + 2004-07-16 Wim Taymans * gst/playback/gstdecodebin.c: (gst_decode_bin_get_type), diff --git a/ext/libpng/Makefile.am b/ext/libpng/Makefile.am index 868ec54d5a..0d74514730 100644 --- a/ext/libpng/Makefile.am +++ b/ext/libpng/Makefile.am @@ -1,9 +1,9 @@ plugin_LTLIBRARIES = libgstpng.la -libgstpng_la_SOURCES = gstpng.c gstpngenc.c +libgstpng_la_SOURCES = gstpng.c gstpngdec.c gstpngenc.c libgstpng_la_CFLAGS = $(GST_CFLAGS) libgstpng_la_LIBADD = $(GST_LIBS) $(LIBPNG_LIBS) libgstpng_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstpngenc.h +noinst_HEADERS = gstpngdec.h gstpngenc.h diff --git a/ext/libpng/gstpng.c b/ext/libpng/gstpng.c index dab8d9d923..d9bcd1b6e7 100644 --- a/ext/libpng/gstpng.c +++ b/ext/libpng/gstpng.c @@ -23,11 +23,16 @@ #include #include +#include "gstpngdec.h" #include "gstpngenc.h" static gboolean plugin_init (GstPlugin * plugin) { + if (!gst_element_register (plugin, "pngdec", GST_RANK_PRIMARY, + GST_TYPE_PNGDEC)) + return FALSE; + if (!gst_element_register (plugin, "pngenc", GST_RANK_NONE, GST_TYPE_PNGENC)) return FALSE; diff --git a/ext/libpng/gstpngdec.c b/ext/libpng/gstpngdec.c new file mode 100644 index 0000000000..0916d23704 --- /dev/null +++ b/ext/libpng/gstpngdec.c @@ -0,0 +1,342 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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 +#include +#include "gstpngdec.h" +#include + +static GstElementDetails gst_pngdec_details = { + "PNG decoder", + "Codec/Decoder/Image", + "Decode a png video frame to a raw image", + "Wim Taymans ", +}; + + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0 +}; + +static void gst_pngdec_base_init (gpointer g_class); +static void gst_pngdec_class_init (GstPngDecClass * klass); +static void gst_pngdec_init (GstPngDec * pngdec); + +static void gst_pngdec_chain (GstPad * pad, GstData * _data); + +static GstCaps *gst_pngdec_src_getcaps (GstPad * pad); + +static GstElementClass *parent_class = NULL; + + +static void +user_error_fn (png_structp png_ptr, png_const_charp error_msg) +{ + g_warning ("%s", error_msg); +} + +static void +user_warning_fn (png_structp png_ptr, png_const_charp warning_msg) +{ + g_warning ("%s", warning_msg); +} + + +GType +gst_pngdec_get_type (void) +{ + static GType pngdec_type = 0; + + if (!pngdec_type) { + static const GTypeInfo pngdec_info = { + sizeof (GstPngDecClass), + gst_pngdec_base_init, + NULL, + (GClassInitFunc) gst_pngdec_class_init, + NULL, + NULL, + sizeof (GstPngDec), + 0, + (GInstanceInitFunc) gst_pngdec_init, + }; + + pngdec_type = g_type_register_static (GST_TYPE_ELEMENT, "GstPngDec", + &pngdec_info, 0); + } + return pngdec_type; +} + +static GstStaticPadTemplate gst_pngdec_src_pad_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB) + ); + +static GstStaticPadTemplate gst_pngdec_sink_pad_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-png, " + "width = (int) [ 16, 4096 ], " + "height = (int) [ 16, 4096 ], " "framerate = (double) [ 0.0, MAX ]") + ); + +static void +gst_pngdec_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_pngdec_src_pad_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_pngdec_sink_pad_template)); + gst_element_class_set_details (element_class, &gst_pngdec_details); +} + +static void +gst_pngdec_class_init (GstPngDecClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); +} + + +static GstPadLinkReturn +gst_pngdec_sinklink (GstPad * pad, const GstCaps * caps) +{ + GstPngDec *pngdec; + GstStructure *structure; + + pngdec = GST_PNGDEC (gst_pad_get_parent (pad)); + + structure = gst_caps_get_structure (caps, 0); + gst_structure_get_double (structure, "framerate", &pngdec->fps); + + return TRUE; +} + +static void +gst_pngdec_init (GstPngDec * pngdec) +{ + pngdec->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get + (&gst_pngdec_sink_pad_template), "sink"); + gst_element_add_pad (GST_ELEMENT (pngdec), pngdec->sinkpad); + + pngdec->srcpad = gst_pad_new_from_template (gst_static_pad_template_get + (&gst_pngdec_src_pad_template), "src"); + gst_element_add_pad (GST_ELEMENT (pngdec), pngdec->srcpad); + + gst_pad_set_chain_function (pngdec->sinkpad, gst_pngdec_chain); + gst_pad_set_link_function (pngdec->sinkpad, gst_pngdec_sinklink); + + gst_pad_set_getcaps_function (pngdec->srcpad, gst_pngdec_src_getcaps); + + pngdec->png = NULL; + pngdec->info = NULL; + + pngdec->color_type = -1; + pngdec->width = -1; + pngdec->height = -1; + pngdec->fps = -1; +} + +static GstCaps * +gst_pngdec_src_getcaps (GstPad * pad) +{ + GstPngDec *pngdec; + GstCaps *caps; + gint i; + GstPadTemplate *templ; + GstCaps *inter; + + pngdec = GST_PNGDEC (gst_pad_get_parent (pad)); + templ = gst_static_pad_template_get (&gst_pngdec_src_pad_template); + caps = gst_caps_copy (gst_pad_template_get_caps (templ)); + + if (pngdec->color_type != -1) { + GstCaps *to_inter = NULL; + + switch (pngdec->color_type) { + case PNG_COLOR_TYPE_RGB: + to_inter = gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, 24, NULL); + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + to_inter = gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, 32, NULL); + break; + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + case PNG_COLOR_TYPE_GRAY_ALPHA: + default: + g_warning ("unsupported colortype"); + break; + } + inter = gst_caps_intersect (caps, to_inter); + gst_caps_free (caps); + gst_caps_free (to_inter); + caps = inter; + } + + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstStructure *structure = gst_caps_get_structure (caps, i); + + g_print ("%d %d\n", pngdec->width, pngdec->height); + if (pngdec->width != -1) { + gst_structure_set (structure, "width", G_TYPE_INT, pngdec->width, NULL); + } + + if (pngdec->height != -1) { + gst_structure_set (structure, "height", G_TYPE_INT, pngdec->height, NULL); + } + + if (pngdec->fps != -1) { + gst_structure_set (structure, + "framerate", G_TYPE_DOUBLE, pngdec->fps, NULL); + } + } + + return caps; +} + +static void +user_read_data (png_structp png_ptr, png_bytep data, png_size_t length) +{ + GstPngDec *dec; + + dec = GST_PNGDEC (png_ptr->io_ptr); + + if (GST_BUFFER_SIZE (dec->buffer_in) < dec->offset + length) { + g_warning ("reading past end of buffer"); + } + + memcpy (data, GST_BUFFER_DATA (dec->buffer_in) + dec->offset, length); + + dec->offset += length; +} + +static void +gst_pngdec_chain (GstPad * pad, GstData * _data) +{ + GstBuffer *buf = GST_BUFFER (_data); + GstPngDec *pngdec; + png_uint_32 width, height; + gint depth, color; + png_bytep *rows, inp; + GstBuffer *out; + gint i; + + pngdec = GST_PNGDEC (gst_pad_get_parent (pad)); + + if (!GST_PAD_IS_USABLE (pngdec->srcpad)) { + gst_buffer_unref (buf); + return; + } + + pngdec->buffer_in = buf; + pngdec->offset = 0; + + /* initialize png struct stuff */ + pngdec->png = png_create_read_struct (PNG_LIBPNG_VER_STRING, + (png_voidp) NULL, user_error_fn, user_warning_fn); + + /* FIXME: better error handling */ + if (pngdec->png == NULL) { + g_warning ("Failed to initialize png structure"); + return; + } + + pngdec->info = png_create_info_struct (pngdec->png); + if (pngdec->info == NULL) { + g_warning ("Failed to initialize info structure"); + png_destroy_read_struct (&(pngdec->png), (png_infopp) NULL, + (png_infopp) NULL); + return; + } + + pngdec->endinfo = png_create_info_struct (pngdec->png); + if (pngdec->endinfo == NULL) { + g_warning ("Failed to initialize endinfo structure"); + return; + } + + /* non-0 return is from a longjmp inside of libpng */ + if (setjmp (pngdec->png->jmpbuf) != 0) { + GST_DEBUG ("returning from longjmp"); + png_destroy_read_struct (&pngdec->png, &pngdec->info, &pngdec->endinfo); + return; + } + + png_set_read_fn (pngdec->png, pngdec, user_read_data); + + png_read_info (pngdec->png, pngdec->info); + png_get_IHDR (pngdec->png, pngdec->info, &width, &height, + &depth, &color, NULL, NULL, NULL); + + GST_LOG ("color type: %d\n", pngdec->info->color_type); + + if (pngdec->width != width || + pngdec->height != height || + pngdec->color_type != pngdec->info->color_type) { + pngdec->width = width; + pngdec->height = height; + pngdec->color_type = pngdec->info->color_type; + + if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (pngdec->srcpad))) { + GST_ELEMENT_ERROR (pngdec, CORE, NEGOTIATION, (NULL), (NULL)); + return; + } + } + + rows = (png_bytep *) g_malloc (sizeof (png_bytep) * height); + + out = + gst_pad_alloc_buffer (pngdec->srcpad, GST_BUFFER_OFFSET_NONE, + width * height * 4); + + inp = GST_BUFFER_DATA (out); + for (i = 0; i < height; i++) { + rows[i] = inp; + inp += width * 4; + } + + png_read_image (pngdec->png, rows); + free (rows); + + png_destroy_info_struct (pngdec->png, &pngdec->info); + png_destroy_read_struct (&pngdec->png, &pngdec->info, &pngdec->endinfo); + + pngdec->buffer_in = NULL; + gst_buffer_unref (buf); + + gst_pad_push (pngdec->srcpad, GST_DATA (out)); +} diff --git a/ext/libpng/gstpngdec.h b/ext/libpng/gstpngdec.h new file mode 100644 index 0000000000..1068c260b5 --- /dev/null +++ b/ext/libpng/gstpngdec.h @@ -0,0 +1,74 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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_PNGDEC_H__ +#define __GST_PNGDEC_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_PNGDEC (gst_pngdec_get_type()) +#define GST_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGDEC,GstPngDec)) +#define GST_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGDEC,GstPngDec)) +#define GST_IS_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGDEC)) +#define GST_IS_PNGDEC_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGDEC)) + +typedef struct _GstPngDec GstPngDec; +typedef struct _GstPngDecClass GstPngDecClass; + +struct _GstPngDec +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + + GstBuffer *buffer_in; + gint offset; + + png_structp png; + png_infop info; + png_infop endinfo; + + gint width; + gint height; + gint bpp; + gint color_type; + gdouble fps; +}; + +struct _GstPngDecClass +{ + GstElementClass parent_class; +}; + +GType gst_pngdec_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_PNGDEC_H__ */