From b55de48843b9947a36a4f966182724e918c035c2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 4 Nov 2013 09:55:17 +0100 Subject: [PATCH] tagdemux: accumulate buffers in adapter Accumulate buffers in an adapter instead of appending them because append causes a lot of memcpys. Keep track of the last tagsize and accumulate enough data before attempting to parse more data. This patch implements a minimal amount of changes in order to not change the behaviour. We should really rewrite the tag handling and trimming using the adapter API instead of merging and trimming into a buffer. --- gst-libs/gst/tag/gsttagdemux.c | 79 ++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/gst-libs/gst/tag/gsttagdemux.c b/gst-libs/gst/tag/gsttagdemux.c index 9b6c478..b1790c2 100644 --- a/gst-libs/gst/tag/gsttagdemux.c +++ b/gst-libs/gst/tag/gsttagdemux.c @@ -75,6 +75,7 @@ #include "gsttagdemux.h" #include +#include #include #include @@ -101,8 +102,10 @@ struct _GstTagDemuxPrivate gint64 upstream_size; GstTagDemuxState state; + GstAdapter *adapter; GstBuffer *collect; gsize collect_size; + guint tagsize; GstCaps *src_caps; GstTagList *event_tags; @@ -266,6 +269,8 @@ gst_tag_demux_reset (GstTagDemux * tagdemux) gst_buffer_replace (buffer_p, NULL); tagdemux->priv->collect_size = 0; + tagdemux->priv->tagsize = 0; + gst_adapter_clear (tagdemux->priv->adapter); gst_caps_replace (caps_p, NULL); if (tagdemux->priv->event_tags) { @@ -328,6 +333,7 @@ gst_tag_demux_init (GstTagDemux * demux, GstTagDemuxClass * gclass) gst_pad_use_fixed_caps (demux->priv->srcpad); gst_element_add_pad (GST_ELEMENT (demux), demux->priv->srcpad); + demux->priv->adapter = gst_adapter_new (); gst_tag_demux_reset (demux); } @@ -337,6 +343,10 @@ gst_tag_demux_dispose (GObject * object) GstTagDemux *tagdemux = GST_TAG_DEMUX (object); gst_tag_demux_reset (tagdemux); + if (tagdemux->priv->adapter) { + g_object_unref (tagdemux->priv->adapter); + tagdemux->priv->adapter = NULL; + } G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -487,17 +497,58 @@ no_out_buffer_start: } static void -gst_tag_demux_chain_parse_tag (GstTagDemux * demux, GstBuffer * collect) +update_collected (GstTagDemux * demux) { + guint avail; + GstBuffer *buf; + + avail = gst_adapter_available (demux->priv->adapter); + if (avail == 0) + return; + + buf = gst_adapter_take_buffer (demux->priv->adapter, avail); + + if (demux->priv->collect == NULL) { + demux->priv->collect = buf; + } else { + demux->priv->collect = gst_buffer_append (demux->priv->collect, buf); + } + demux->priv->collect_size += avail; +} + +static void +gst_tag_demux_chain_parse_tag (GstTagDemux * demux) +{ + GstBuffer *collect; GstTagDemuxResult parse_ret; GstTagDemuxClass *klass; guint tagsize = 0; guint available; - g_assert (gst_buffer_is_writable (collect)); + available = + demux->priv->collect_size + gst_adapter_available (demux->priv->adapter); klass = GST_TAG_DEMUX_CLASS (G_OBJECT_GET_CLASS (demux)); + if (available < klass->min_start_size) { + GST_DEBUG_OBJECT (demux, "Only %u bytes available, but %u needed " + "to identify tag", available, klass->min_start_size); + return; /* wait for more data */ + } + + if (available < demux->priv->tagsize) { + GST_DEBUG_OBJECT (demux, "Only %u bytes available, but %u needed " + "to parse tag", available, demux->priv->tagsize); + return; /* wait for more data */ + } + + update_collected (demux); + demux->priv->collect = gst_buffer_make_writable (demux->priv->collect); + collect = demux->priv->collect; + + g_assert (gst_buffer_is_writable (collect)); + + /* If we receive a buffer that's from the middle of the file, * we can't read tags so move to typefinding */ if (GST_BUFFER_OFFSET_IS_VALID (collect) && GST_BUFFER_OFFSET (collect) != 0) { @@ -510,20 +561,14 @@ gst_tag_demux_chain_parse_tag (GstTagDemux * demux, GstBuffer * collect) g_assert (klass->identify_tag != NULL); g_assert (klass->parse_tag != NULL); - available = gst_buffer_get_size (collect); - - if (available < klass->min_start_size) { - GST_DEBUG_OBJECT (demux, "Only %u bytes available, but %u needed " - "to identify tag", available, klass->min_start_size); - return; /* wait for more data */ - } - if (!klass->identify_tag (demux, collect, TRUE, &tagsize)) { GST_DEBUG_OBJECT (demux, "Could not identify start tag"); demux->priv->state = GST_TAG_DEMUX_TYPEFINDING; return; } + demux->priv->tagsize = tagsize; + /* need to set offset of first buffer to 0 or trimming won't work */ if (!GST_BUFFER_OFFSET_IS_VALID (collect)) { GST_WARNING_OBJECT (demux, "Fixing up first buffer without offset"); @@ -599,18 +644,12 @@ gst_tag_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) demux->priv->segment.position += GST_BUFFER_DURATION (buf); } - if (demux->priv->collect == NULL) { - demux->priv->collect = buf; - } else { - demux->priv->collect = gst_buffer_append (demux->priv->collect, buf); - } - demux->priv->collect_size += size; + gst_adapter_push (demux->priv->adapter, buf); buf = NULL; switch (demux->priv->state) { case GST_TAG_DEMUX_READ_START_TAG: - demux->priv->collect = gst_buffer_make_writable (demux->priv->collect); - gst_tag_demux_chain_parse_tag (demux, demux->priv->collect); + gst_tag_demux_chain_parse_tag (demux); if (demux->priv->state != GST_TAG_DEMUX_TYPEFINDING) break; /* Fall-through */ @@ -620,6 +659,8 @@ gst_tag_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) gsize typefind_size; GstCaps *caps; + update_collected (demux); + if (demux->priv->collect_size < TYPE_FIND_MIN_SIZE + demux->priv->strip_start) break; /* Go get more data first */ @@ -672,6 +713,8 @@ gst_tag_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) GstBuffer *outbuf = NULL; gsize outbuf_size; + update_collected (demux); + /* Trim the buffer and adjust offset */ if (demux->priv->collect) { outbuf = demux->priv->collect; -- 2.7.4