pngparse: optimise reading of png files

Read PNG data chunk in one go by letting the parser
base class know the size we need, so that it doesn't
drip-feed us small chunks of data (causing a lot of
reallocs and memcpy in the process) until we have
everything.

Improves parsing performance of very large PNG files
(65MB) from ~13 seconds to a couple of millisecs.

https://bugzilla.gnome.org/show_bug.cgi?id=736176
This commit is contained in:
Tim-Philipp Müller 2014-11-09 20:53:34 +00:00
parent f07de37ad1
commit 6e3518dfd6

View file

@ -49,6 +49,7 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
G_DEFINE_TYPE (GstPngParse, gst_png_parse, GST_TYPE_BASE_PARSE); G_DEFINE_TYPE (GstPngParse, gst_png_parse, GST_TYPE_BASE_PARSE);
static gboolean gst_png_parse_start (GstBaseParse * parse); static gboolean gst_png_parse_start (GstBaseParse * parse);
static gboolean gst_png_parse_event (GstBaseParse * parse, GstEvent * event);
static GstFlowReturn gst_png_parse_handle_frame (GstBaseParse * parse, static GstFlowReturn gst_png_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, gint * skipsize); GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_png_parse_pre_push_frame (GstBaseParse * parse, static GstFlowReturn gst_png_parse_pre_push_frame (GstBaseParse * parse,
@ -72,6 +73,7 @@ gst_png_parse_class_init (GstPngParseClass * klass)
/* Override BaseParse vfuncs */ /* Override BaseParse vfuncs */
parse_class->start = GST_DEBUG_FUNCPTR (gst_png_parse_start); parse_class->start = GST_DEBUG_FUNCPTR (gst_png_parse_start);
parse_class->sink_event = GST_DEBUG_FUNCPTR (gst_png_parse_event);
parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_png_parse_handle_frame); parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_png_parse_handle_frame);
parse_class->pre_push_frame = parse_class->pre_push_frame =
GST_DEBUG_FUNCPTR (gst_png_parse_pre_push_frame); GST_DEBUG_FUNCPTR (gst_png_parse_pre_push_frame);
@ -100,6 +102,24 @@ gst_png_parse_start (GstBaseParse * parse)
return TRUE; return TRUE;
} }
static gboolean
gst_png_parse_event (GstBaseParse * parse, GstEvent * event)
{
gboolean res;
res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
/* the start code and at least 2 empty frames (IHDR and IEND) */
gst_base_parse_set_min_frame_size (parse, 8 + 12 + 12);
break;
default:
break;
}
return res;
}
static GstFlowReturn static GstFlowReturn
gst_png_parse_handle_frame (GstBaseParse * parse, gst_png_parse_handle_frame (GstBaseParse * parse,
@ -155,18 +175,27 @@ gst_png_parse_handle_frame (GstBaseParse * parse,
if (!gst_byte_reader_get_uint32_le (&reader, &code)) if (!gst_byte_reader_get_uint32_le (&reader, &code))
goto beach; goto beach;
GST_INFO_OBJECT (parse, "%" GST_FOURCC_FORMAT " chunk, %u bytes",
GST_FOURCC_ARGS (code), length);
if (code == GST_MAKE_FOURCC ('I', 'H', 'D', 'R')) { if (code == GST_MAKE_FOURCC ('I', 'H', 'D', 'R')) {
if (!gst_byte_reader_get_uint32_be (&reader, &width)) if (!gst_byte_reader_get_uint32_be (&reader, &width))
goto beach; goto beach;
if (!gst_byte_reader_get_uint32_be (&reader, &height)) if (!gst_byte_reader_get_uint32_be (&reader, &height))
goto beach; goto beach;
length -= 8; length -= 8;
} else if (code == GST_MAKE_FOURCC ('I', 'D', 'A', 'T')) {
gst_base_parse_set_min_frame_size (parse,
gst_byte_reader_get_pos (&reader) + 4 + length + 12);
} }
if (!gst_byte_reader_skip (&reader, length + 4)) if (!gst_byte_reader_skip (&reader, length + 4))
goto beach; goto beach;
if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) { if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) {
/* the start code and at least 2 empty frames (IHDR and IEND) */
gst_base_parse_set_min_frame_size (parse, 8 + 12 + 12);
if (pngparse->width != width || pngparse->height != height) { if (pngparse->width != width || pngparse->height != height) {
GstCaps *caps, *sink_caps; GstCaps *caps, *sink_caps;