diff --git a/gst/videoparsers/Makefile.am b/gst/videoparsers/Makefile.am index 0e88f739ff..823233f501 100644 --- a/gst/videoparsers/Makefile.am +++ b/gst/videoparsers/Makefile.am @@ -5,6 +5,7 @@ libgstvideoparsersbad_la_SOURCES = plugin.c \ gstdiracparse.c dirac_parse.c \ gsth264parse.c gstmpegvideoparse.c \ gstmpeg4videoparse.c \ + gstpngparse.c \ gstvc1parse.c libgstvideoparsersbad_la_CFLAGS = \ @@ -27,6 +28,7 @@ noinst_HEADERS = gsth263parse.h h263parse.h \ gstdiracparse.h dirac_parse.h \ gsth264parse.h gstmpegvideoparse.h \ gstmpeg4videoparse.h \ + gstpngparse.h \ gstvc1parse.h Android.mk: Makefile.am $(BUILT_SOURCES) diff --git a/gst/videoparsers/gstpngparse.c b/gst/videoparsers/gstpngparse.c new file mode 100644 index 0000000000..f4fa84efe6 --- /dev/null +++ b/gst/videoparsers/gstpngparse.c @@ -0,0 +1,192 @@ +/* GStreamer PNG Parser + * Copyright (C) <2013> Collabora Ltd + * @author Olivier Crete + * + * 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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstpngparse.h" + +#include + +#define PNG_SIGNATURE G_GUINT64_CONSTANT (0x89504E470D0A1A0A) + +GST_DEBUG_CATEGORY (png_parse_debug); +#define GST_CAT_DEFAULT png_parse_debug + +static GstStaticPadTemplate srctemplate = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("image/png, width = (int)[1, MAX], height = (int)[1, MAX]," + "parsed = (boolean) true") + ); + +static GstStaticPadTemplate sinktemplate = +GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("image/png") + ); + +#define parent_class gst_png_parse_parent_class +G_DEFINE_TYPE (GstPngParse, gst_png_parse, GST_TYPE_BASE_PARSE); + +static gboolean gst_png_parse_start (GstBaseParse * parse); +static GstFlowReturn gst_png_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); + +static void +gst_png_parse_class_init (GstPngParseClass * klass) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (png_parse_debug, "pngparse", 0, "png parser"); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + gst_element_class_set_static_metadata (gstelement_class, "PNG parser", + "Codec/Parser/Video/Image", + "Parses PNG files", "Olivier Crete "); + + /* Override BaseParse vfuncs */ + parse_class->start = GST_DEBUG_FUNCPTR (gst_png_parse_start); + parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_png_parse_handle_frame); +} + +static void +gst_png_parse_init (GstPngParse * pngparse) +{ +} + +static gboolean +gst_png_parse_start (GstBaseParse * parse) +{ + GstPngParse *pngparse = GST_PNG_PARSE (parse); + + GST_DEBUG_OBJECT (pngparse, "start"); + + /* the start code and at least 2 empty frames (IHDR and IEND) */ + gst_base_parse_set_min_frame_size (parse, 8 + 12 + 12); + + pngparse->width = 0; + pngparse->height = 0; + + return TRUE; +} + + +static GstFlowReturn +gst_png_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) +{ + GstPngParse *pngparse = GST_PNG_PARSE (parse); + GstMapInfo map; + GstByteReader reader; + GstFlowReturn ret = GST_FLOW_OK; + guint64 signature; + + gst_buffer_map (frame->buffer, &map, GST_MAP_READ); + gst_byte_reader_init (&reader, map.data, map.size); + + if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) + goto beach; + + if (signature != PNG_SIGNATURE) { + for (;;) { + guint offset; + + offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, + 0x89504E47, 0, gst_byte_reader_get_remaining (&reader)); + + if (offset == -1) { + *skipsize = gst_byte_reader_get_remaining (&reader) - 4; + goto beach; + } + + gst_byte_reader_skip (&reader, offset); + + if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) + goto beach; + + if (signature == PNG_SIGNATURE) { + /* We're skipping, go out, we'll be back */ + *skipsize = gst_byte_reader_get_pos (&reader); + goto beach; + } + gst_byte_reader_skip (&reader, 4); + } + } + + gst_byte_reader_skip (&reader, 8); + + for (;;) { + guint32 length; + guint32 code; + guint width, height; + + if (!gst_byte_reader_get_uint32_be (&reader, &length)) + goto beach; + if (!gst_byte_reader_get_uint32_le (&reader, &code)) + goto beach; + + if (code == GST_MAKE_FOURCC ('I', 'H', 'D', 'R')) { + if (!gst_byte_reader_get_uint32_be (&reader, &width)) + goto beach; + if (!gst_byte_reader_get_uint32_be (&reader, &height)) + goto beach; + length -= 8; + } + + if (!gst_byte_reader_skip (&reader, length + 4)) + goto beach; + + if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) { + if (pngparse->width != width || pngparse->height != height) { + GstCaps *caps; + + pngparse->height = height; + pngparse->width = width; + + caps = gst_caps_new_simple ("image/png", + "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); + if (!gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps)) { + ret = GST_FLOW_NOT_NEGOTIATED; + } + gst_caps_unref (caps); + + if (ret != GST_FLOW_OK) + goto beach; + } + + + gst_buffer_unmap (frame->buffer, &map); + return gst_base_parse_finish_frame (parse, frame, + gst_byte_reader_get_pos (&reader)); + } + } + +beach: + + gst_buffer_unmap (frame->buffer, &map); + + return ret; +} diff --git a/gst/videoparsers/gstpngparse.h b/gst/videoparsers/gstpngparse.h new file mode 100644 index 0000000000..5fccdf50fe --- /dev/null +++ b/gst/videoparsers/gstpngparse.h @@ -0,0 +1,61 @@ +/* GStreamer PNG Parser + * Copyright (C) <2013> Collabora Ltd + * @author Olivier Crete + * + * 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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_PNG_PARSE_H__ +#define __GST_PNG_PARSE_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_PNG_PARSE \ + (gst_png_parse_get_type()) +#define GST_PNG_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNG_PARSE,GstPngParse)) +#define GST_PNG_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNG_PARSE,GstPngParseClass)) +#define GST_IS_PNG_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNG_PARSE)) +#define GST_IS_PNG_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNG_PARSE)) + +GType gst_png_parse_get_type (void); + +typedef struct _GstPngParse GstPngParse; +typedef struct _GstPngParseClass GstPngParseClass; + +struct _GstPngParse +{ + GstBaseParse baseparse; + + guint width; + guint height; +}; + +struct _GstPngParseClass +{ + GstBaseParseClass parent_class; +}; + +G_END_DECLS + +#endif diff --git a/gst/videoparsers/plugin.c b/gst/videoparsers/plugin.c index 978bdbf6e6..485b0edde0 100644 --- a/gst/videoparsers/plugin.c +++ b/gst/videoparsers/plugin.c @@ -27,6 +27,7 @@ #include "gstdiracparse.h" #include "gstmpegvideoparse.h" #include "gstmpeg4videoparse.h" +#include "gstpngparse.h" #include "gstvc1parse.h" static gboolean @@ -44,6 +45,8 @@ plugin_init (GstPlugin * plugin) GST_RANK_PRIMARY + 1, GST_TYPE_MPEGVIDEO_PARSE); ret |= gst_element_register (plugin, "mpeg4videoparse", GST_RANK_PRIMARY + 1, GST_TYPE_MPEG4VIDEO_PARSE); + ret |= gst_element_register (plugin, "pngparse", + GST_RANK_PRIMARY, GST_TYPE_PNG_PARSE); ret |= gst_element_register (plugin, "vc1parse", GST_RANK_NONE, GST_TYPE_VC1_PARSE);