videoparsers: Add png file parser
authorOlivier Crête <olivier.crete@collabora.com>
Tue, 29 Jan 2013 03:42:44 +0000 (22:42 -0500)
committerOlivier Crête <olivier.crete@collabora.com>
Tue, 12 Feb 2013 22:04:38 +0000 (17:04 -0500)
https://bugzilla.gnome.org/show_bug.cgi?id=690639

gst/videoparsers/Makefile.am
gst/videoparsers/gstpngparse.c [new file with mode: 0644]
gst/videoparsers/gstpngparse.h [new file with mode: 0644]
gst/videoparsers/plugin.c

index 0e88f73..823233f 100644 (file)
@@ -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 (file)
index 0000000..f4fa84e
--- /dev/null
@@ -0,0 +1,192 @@
+/* GStreamer PNG Parser
+ * Copyright (C) <2013> Collabora Ltd
+ *  @author Olivier Crete <olivier.crete@collabora.com>
+ *
+ * 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 <gst/base/gstbytereader.h>
+
+#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 <olivier.crete@collabora.com>");
+
+  /* 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 (file)
index 0000000..5fccdf5
--- /dev/null
@@ -0,0 +1,61 @@
+/* GStreamer PNG Parser
+ * Copyright (C) <2013> Collabora Ltd
+ *  @author Olivier Crete <olivier.crete@collabora.com>
+ *
+ * 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 <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstbaseparse.h>
+
+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
index 978bdbf..485b0ed 100644 (file)
@@ -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);