summaryrefslogtreecommitdiffstats
path: root/gst/multipart
diff options
context:
space:
mode:
authorSjoerd Simons <sjoerd@luon.net>2006-07-28 16:17:17 +0000
committerWim Taymans <wim.taymans@gmail.com>2006-07-28 16:17:17 +0000
commit4441dc23ee2a222b947dd001d31728064ca91ad3 (patch)
tree79c1e5a6d920571189cf5bf3b7c0554904e2f43d /gst/multipart
parentda5c3416e7f3f518e6dca76179914186131bd65c (diff)
gst/multipart/multipartdemux.c: Uses GstAdapter instead of own buffering.
Original commit message from CVS: Patch by: Sjoerd Simons <sjoerd at luon dot net> * gst/multipart/multipartdemux.c: (gst_multipart_demux_base_init), (gst_multipart_demux_class_init), (gst_multipart_demux_init), (gst_multipart_demux_finalize), (get_line_end), (multipart_parse_header), (multipart_find_boundary), (gst_multipart_demux_chain), (gst_multipart_demux_change_state), (gst_multipart_set_property), (gst_multipart_get_property): Uses GstAdapter instead of own buffering. Actually parses the mime-type correctly (In tests the mime-type was always "" with the old version). Uses the Content-length header if available to speed up things. Reliably autoscans the boundary name by default. Fixes #349068. * gst/multipart/multipartmux.c: (gst_multipart_mux_collected): Don't start the stream with a \n.
Diffstat (limited to 'gst/multipart')
-rw-r--r--gst/multipart/multipartdemux.c464
-rw-r--r--gst/multipart/multipartmux.c19
2 files changed, 276 insertions, 207 deletions
diff --git a/gst/multipart/multipartdemux.c b/gst/multipart/multipartdemux.c
index 18fc332f..714d2079 100644
--- a/gst/multipart/multipartdemux.c
+++ b/gst/multipart/multipartdemux.c
@@ -1,4 +1,5 @@
/* GStreamer
+ * Copyright (C) 2006 Sjoerd Simons <sjoerd@luon.net>
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
*
* gstmultipartdemux.c: multipart stream demuxer
@@ -46,8 +47,8 @@
* </para>
* <para>
* the content in multipart files is separated with a boundary string that can be
- * configured specifically with the "boundary" property or can be autodetected by
- * setting the "autoscan" property to TRUE.
+ * configured specifically with the "boundary" property otherwise it will be
+ * autodetected.
* </para>
* </refsect2>
*/
@@ -57,6 +58,7 @@
#endif
#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
#include <string.h>
@@ -69,7 +71,9 @@
typedef struct _GstMultipartDemux GstMultipartDemux;
typedef struct _GstMultipartDemuxClass GstMultipartDemuxClass;
-#define MAX_LINE_LEN 500
+#define MULTIPART_NEED_MORE_DATA -1
+#define MULTIPART_DATA_ERROR -2
+#define MULTIPART_DATA_EOS -3
/* all information needed for one multipart stream */
typedef struct
@@ -77,11 +81,6 @@ typedef struct
GstPad *pad; /* reference for this pad is held by element we belong to */
gchar *mime;
-
- guint64 offset; /* end offset of last buffer */
- guint64 known_offset; /* last known offset */
-
- guint flags;
}
GstMultipartPad;
@@ -100,17 +99,20 @@ struct _GstMultipartDemux
GSList *srcpads;
gint numpads;
- gchar *parsing_mime;
- gchar *buffer;
- gint maxlen;
- gint bufsize;
- gint scanpos;
- gint lastpos;
+ GstAdapter *adapter;
- gchar *prefix;
- gint prefixLen;
- gboolean first_frame;
+ /* Header information of the current frame */
+ gboolean header_completed;
+ gchar *boundary;
+ guint boundary_len;
+ gchar *mime_type;
+ gint content_length;
+
+ /* deprecated, unused */
gboolean autoscan;
+
+ /* Index inside the current data when manually looking for the boundary */
+ gint scanpos;
};
struct _GstMultipartDemuxClass
@@ -126,7 +128,7 @@ static const GstElementDetails gst_multipart_demux_details =
GST_ELEMENT_DETAILS ("Multipart demuxer",
"Codec/Demuxer",
"demux multipart streams",
- "Wim Taymans <wim@fluendo.com>");
+ "Wim Taymans <wim@fluendo.com>, Sjoerd Simons <sjoerd@luon.net>");
/* signals and args */
@@ -136,14 +138,14 @@ enum
LAST_SIGNAL
};
-#define DEFAULT_BOUNDARY "ThisRandomString"
-#define DEFAULT_AUTOSCAN FALSE
+#define DEFAULT_AUTOSCAN FALSE
+#define DEFAULT_BOUNDARY NULL
+
enum
{
PROP_0,
- PROP_BOUNDARY,
- PROP_AUTOSCAN
- /* FILL ME */
+ PROP_AUTOSCAN,
+ PROP_BOUNDARY
};
static GstStaticPadTemplate multipart_demux_src_template_factory =
@@ -172,7 +174,6 @@ static void gst_multipart_get_property (GObject * object, guint prop_id,
static void gst_multipart_demux_finalize (GObject * object);
-
GST_BOILERPLATE (GstMultipartDemux, gst_multipart_demux, GstElement,
GST_TYPE_ELEMENT);
@@ -180,37 +181,35 @@ static void
gst_multipart_demux_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
-
- gst_element_class_set_details (element_class, &gst_multipart_demux_details);
- gobject_class->set_property = gst_multipart_set_property;
- gobject_class->get_property = gst_multipart_get_property;
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&multipart_demux_sink_template_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&multipart_demux_src_template_factory));
-
- g_object_class_install_property (gobject_class, PROP_BOUNDARY,
- g_param_spec_string ("boundary", "Boundary",
- "The boundary string separating data", DEFAULT_BOUNDARY,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (gobject_class, PROP_AUTOSCAN,
- g_param_spec_boolean ("autoscan", "autoscan",
- "Try to autofind the prefix", DEFAULT_AUTOSCAN,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
+ gst_element_class_set_details (element_class, &gst_multipart_demux_details);
}
static void
gst_multipart_demux_class_init (GstMultipartDemuxClass * klass)
{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- gstelement_class->change_state = gst_multipart_demux_change_state;
gobject_class->finalize = gst_multipart_demux_finalize;
+ gobject_class->set_property = gst_multipart_set_property;
+ gobject_class->get_property = gst_multipart_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_BOUNDARY,
+ g_param_spec_string ("boundary", "Boundary",
+ "The boundary string separating data, automatic if NULL",
+ DEFAULT_BOUNDARY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class, PROP_AUTOSCAN,
+ g_param_spec_boolean ("autoscan", "autoscan",
+ "Try to autofind the prefix (deprecated unused, see boundary)",
+ DEFAULT_AUTOSCAN, G_PARAM_READWRITE));
+
+ gstelement_class->change_state = gst_multipart_demux_change_state;
}
static void
@@ -225,15 +224,24 @@ gst_multipart_demux_init (GstMultipartDemux * multipart,
gst_pad_set_chain_function (multipart->sinkpad,
GST_DEBUG_FUNCPTR (gst_multipart_demux_chain));
- multipart->maxlen = 4096;
+ multipart->adapter = gst_adapter_new ();
+ multipart->boundary = DEFAULT_BOUNDARY;
+ multipart->mime_type = NULL;
+ multipart->content_length = -1;
+ multipart->header_completed = FALSE;
+ multipart->scanpos = 0;
+ multipart->autoscan = DEFAULT_AUTOSCAN;
}
+
static void
gst_multipart_demux_finalize (GObject * object)
{
GstMultipartDemux *demux = GST_MULTIPART_DEMUX (object);
- g_free (demux->prefix);
+ g_object_unref (demux->adapter);
+ g_free (demux->boundary);
+ g_free (demux->mime_type);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -292,162 +300,226 @@ gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime,
}
}
-static GstFlowReturn
-gst_multipart_demux_chain (GstPad * pad, GstBuffer * buf)
+static gboolean
+get_line_end (const guint8 * data, const guint8 * dataend, guint8 ** end,
+ guint8 ** next)
{
- GstMultipartDemux *multipart;
- gint size, matchpos;
- guchar *data;
- GstFlowReturn ret = GST_FLOW_OK;
-
- multipart = GST_MULTIPART_DEMUX (gst_pad_get_parent (pad));
-
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
-
- /* first make sure our buffer is long enough */
- if (multipart->bufsize + size > multipart->maxlen) {
- gint newsize = (multipart->bufsize + size) * 2;
+ guint8 *x;
+ gboolean foundr = FALSE;
+
+ for (x = (guint8 *) data; x < dataend; x++) {
+ if (*x == '\r') {
+ foundr = TRUE;
+ } else if (*x == '\n') {
+ *end = x - (foundr ? 1 : 0);
+ *next = x + 1;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
- multipart->buffer = g_realloc (multipart->buffer, newsize);
- multipart->maxlen = newsize;
+static gint
+multipart_parse_header (GstMultipartDemux * multipart)
+{
+ const guint8 *data;
+ const guint8 *dataend;
+ gchar *boundary;
+ int boundary_len;
+ int datalen;
+ guint8 *pos;
+ guint8 *end, *next;
+
+ datalen = gst_adapter_available (multipart->adapter);
+ data = gst_adapter_peek (multipart->adapter, datalen);
+ dataend = data + datalen;
+
+ /* First the boundary */
+ if (!get_line_end (data, dataend, &end, &next))
+ return MULTIPART_NEED_MORE_DATA;
+
+ /* Ignore the leading -- */
+ boundary_len = end - data - 2;
+ boundary = (gchar *) data + 2;
+ if (boundary_len < 1) {
+ GST_DEBUG_OBJECT (multipart, "No boundary available");
+ goto wrong_header;
}
- /* copy bytes into the buffer */
- memcpy (multipart->buffer + multipart->bufsize, data, size);
- multipart->bufsize += size;
- if (multipart->first_frame && multipart->autoscan) {
- /* find the prefix if this is the first buffer */
- /* the prefix is like --prefix\r\n */
- size_t i, start;
+ if (G_UNLIKELY (multipart->boundary == NULL)) {
+ /* First time we see the boundary, copy it */
+ multipart->boundary = g_strndup (boundary, boundary_len);
+ multipart->boundary_len = boundary_len;
+ } else if (G_UNLIKELY (boundary_len != multipart->boundary_len)) {
+ /* Something odd is going on, either the boundary indicated EOS or it's
+ * invalid */
+ if (G_UNLIKELY (boundary_len == multipart->boundary_len + 2 &&
+ !strncmp (boundary, multipart->boundary, multipart->boundary_len) &&
+ !strncmp (boundary + multipart->boundary_len, "--", 2))) {
+ return MULTIPART_DATA_EOS;
+ }
+ GST_DEBUG_OBJECT (multipart,
+ "Boundary length doesn't match detected boundary (%d <> %d",
+ boundary_len, multipart->boundary_len);
+ goto wrong_header;
+ } else if (G_UNLIKELY (strncmp (boundary, multipart->boundary, boundary_len))) {
+ GST_DEBUG_OBJECT (multipart, "Boundary doesn't match previous boundary");
+ goto wrong_header;
+ }
- i = 0;
- start = -1;
- while ((i + 1) < multipart->bufsize) {
+ pos = next;
+ while (get_line_end (pos, dataend, &end, &next)) {
+ guint len = end - pos;
- if (-1 == start) {
- if ((multipart->buffer[i] == '-') && (multipart->buffer[i + 1] == '-')) {
- start = i + 2; /* discart -- */
- }
- } else {
- /* look for \r\n or \n\n */
- if ((multipart->buffer[i] == '\n') ||
- ((multipart->buffer[i] == '\r') &&
- (multipart->buffer[i + 1] == '\n'))) {
-
- /* found first \r\n, the prefix is from 0 to i */
-
- g_free (multipart->prefix);
- multipart->prefix =
- g_strndup (multipart->buffer + start, (i - start));
- multipart->prefixLen = strlen (multipart->prefix);
- GST_DEBUG_OBJECT (multipart,
- "set prefix to [%s]\n", multipart->prefix);
-
- multipart->first_frame = FALSE;
- break;
- }
- }
+ if (len == 0) {
+ /* empty line, data starts behind us */
+ GST_DEBUG_OBJECT (multipart,
+ "Parsed the header - boundary: %s, mime-type: %s, content-length: %d",
+ multipart->boundary, multipart->mime_type, multipart->content_length);
+ return next - data;
+ }
- i++;
+ if (len >= 14 && !g_ascii_strncasecmp ("content-type:", (gchar *) pos, 13)) {
+ g_free (multipart->mime_type);
+ multipart->mime_type = g_strndup ((gchar *) pos + 14, len - 14);
+ } else if (len >= 15 &&
+ !g_ascii_strncasecmp ("content-length:", (gchar *) pos, 15)) {
+ multipart->content_length =
+ g_ascii_strtoull ((gchar *) pos + 15, NULL, 10);
}
+ pos = next;
+ }
+ GST_DEBUG_OBJECT (multipart, "Need more data for the header");
+ return MULTIPART_NEED_MORE_DATA;
+wrong_header:
+ {
+ GST_ELEMENT_ERROR (multipart, STREAM, DEMUX, (NULL),
+ ("Boundary not found in the multipart header"));
+ return MULTIPART_DATA_ERROR;
}
+}
+static gint
+multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
+{
+ /* Adaptor is positioned at the start of the data */
+ const guint8 *data, *pos;
+ const guint8 *dataend;
+ gint len;
+
+ if (multipart->content_length >= 0) {
+ /* fast path, known content length :) */
+ len = multipart->content_length;
+ if (gst_adapter_available (multipart->adapter) >= len + 2) {
+ *datalen = len;
+ data = gst_adapter_peek (multipart->adapter, len + 1);
+
+ /* If data[len] contains \r then assume a newline is \r\n */
+ if (data[len] == '\r')
+ len += 2;
+ else if (data[len] == '\n')
+ len += 1;
+ /* Don't check if boundary is actually there, but let the header parsing
+ * bail out if it isn't */
+ return len;
+ } else {
+ /* need more data */
+ return MULTIPART_NEED_MORE_DATA;
+ }
+ }
+ len = gst_adapter_available (multipart->adapter);
+ if (len == 0)
+ return MULTIPART_NEED_MORE_DATA;
+ data = gst_adapter_peek (multipart->adapter, len);
+ dataend = data + len;
+
+ for (pos = data + multipart->scanpos;
+ pos <= dataend - multipart->boundary_len - 2; pos++) {
+ if (*pos == '-' && pos[1] == '-' &&
+ !strncmp ((gchar *) pos + 2,
+ multipart->boundary, multipart->boundary_len)) {
+ /* Found the boundary! Check if there was a newline before the boundary */
+ len = pos - data;
+ if (pos - 2 > data && pos[-2] == '\r')
+ len -= 2;
+ else if (pos - 1 > data && pos[-1] == '\n')
+ len -= 1;
+ *datalen = len;
- /* find \n */
- while (multipart->scanpos < multipart->bufsize) {
- if (multipart->buffer[multipart->scanpos] == '\n') {
- break;
+ multipart->scanpos = 0;
+ return pos - data;
}
- multipart->scanpos++;
}
+ multipart->scanpos = pos - data;
+ return MULTIPART_NEED_MORE_DATA;
+}
- /* then scan for the boundary */
- for (matchpos = 0;
- multipart->scanpos + multipart->prefixLen + MAX_LINE_LEN - matchpos <
- multipart->bufsize; multipart->scanpos++) {
- if (multipart->buffer[multipart->scanpos] == multipart->prefix[matchpos]) {
-
- matchpos++;
- if (matchpos == multipart->prefixLen) {
- int datalen;
- int i, start;
- gchar *mime_type;
-
- multipart->scanpos++;
-
- start = multipart->scanpos;
- /* find \n */
- for (i = 0; i < MAX_LINE_LEN; i++) {
- if (multipart->buffer[multipart->scanpos] == '\n')
- break;
- multipart->scanpos++;
- matchpos++;
- }
- mime_type =
- g_strndup (multipart->buffer + start, multipart->scanpos - start);
- multipart->scanpos += 2;
- matchpos += 3;
-
- datalen = multipart->scanpos - matchpos;
- if (datalen > 0 && multipart->parsing_mime) {
- GstBuffer *outbuf;
- GstMultipartPad *srcpad;
- gboolean created = FALSE;
-
- srcpad =
- gst_multipart_find_pad_by_mime (multipart,
- multipart->parsing_mime, &created);
- if (srcpad != NULL) {
- ret =
- gst_pad_alloc_buffer_and_set_caps (srcpad->pad,
- GST_BUFFER_OFFSET_NONE, datalen, GST_PAD_CAPS (srcpad->pad),
- &outbuf);
- if (ret != GST_FLOW_OK) {
- GST_WARNING_OBJECT (multipart, "failed allocating a %d bytes "
- "buffer", datalen);
- } else {
- memcpy (GST_BUFFER_DATA (outbuf), multipart->buffer, datalen);
- if (created) {
- GstEvent *event;
-
- /* Push new segment */
- event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
- 0, -1, 0);
- if (GST_IS_EVENT (event)) {
- gst_pad_push_event (srcpad->pad, event);
- }
- GST_BUFFER_TIMESTAMP (outbuf) = 0;
- } else {
- GST_BUFFER_TIMESTAMP (outbuf) = -1;
- }
- ret = gst_pad_push (srcpad->pad, outbuf);
- }
- }
- }
- /* move rest downward */
- multipart->bufsize -= multipart->scanpos;
- memmove (multipart->buffer, multipart->buffer + multipart->scanpos,
- multipart->bufsize);
-
- g_free (multipart->parsing_mime);
- multipart->parsing_mime = mime_type;
- multipart->scanpos = 0;
+static GstFlowReturn
+gst_multipart_demux_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstMultipartDemux *multipart;
+ GstAdapter *adapter;
+ gint size = 1;
+
+ multipart = GST_MULTIPART_DEMUX (gst_pad_get_parent (pad));
+ adapter = multipart->adapter;
+
+ if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
+ gst_adapter_clear (adapter);
+ }
+ gst_adapter_push (adapter, buf);
+
+ while (gst_adapter_available (adapter) > 0) {
+ GstMultipartPad *srcpad;
+ GstBuffer *outbuf;
+ gboolean created;
+ gint datalen;
+
+ if (G_UNLIKELY (!multipart->header_completed)) {
+ if ((size = multipart_parse_header (multipart)) < 0) {
+ goto nodata;
+ } else {
+ gst_adapter_flush (adapter, size);
+ multipart->header_completed = TRUE;
}
+ }
+ if ((size = multipart_find_boundary (multipart, &datalen)) < 0) {
+ goto nodata;
+ }
+ srcpad =
+ gst_multipart_find_pad_by_mime (multipart,
+ multipart->mime_type, &created);
+ outbuf = gst_adapter_take_buffer (adapter, datalen);
+ gst_adapter_flush (adapter, size - datalen);
+
+ /* Invalidate header info */
+ multipart->header_completed = FALSE;
+ multipart->content_length = -1;
+
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (srcpad->pad));
+ if (created) {
+ GstEvent *event;
+
+ /* Push new segment, first buffer has 0 timestamp */
+ event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0);
+ gst_pad_push_event (srcpad->pad, event);
+ GST_BUFFER_TIMESTAMP (outbuf) = 0;
} else {
- matchpos = 0;
+ GST_BUFFER_TIMESTAMP (outbuf) = -1;
}
- if (ret != GST_FLOW_OK)
- break;
+ gst_pad_push (srcpad->pad, outbuf);
}
- gst_buffer_unref (buf);
+nodata:
gst_object_unref (multipart);
-
- return ret;
+ if (G_UNLIKELY (size == MULTIPART_DATA_ERROR))
+ return GST_FLOW_ERROR;
+ if (G_UNLIKELY (size == MULTIPART_DATA_EOS))
+ return GST_FLOW_UNEXPECTED;
+ return GST_FLOW_OK;
}
static GstStateChangeReturn
@@ -459,23 +531,6 @@ gst_multipart_demux_change_state (GstElement * element,
multipart = GST_MULTIPART_DEMUX (element);
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- multipart->buffer = g_malloc (multipart->maxlen);
- multipart->first_frame = TRUE;
- multipart->parsing_mime = NULL;
- multipart->numpads = 0;
- multipart->scanpos = 0;
- multipart->lastpos = 0;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
@@ -484,10 +539,12 @@ gst_multipart_demux_change_state (GstElement * element,
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- g_free (multipart->parsing_mime);
- multipart->parsing_mime = NULL;
- g_free (multipart->buffer);
- multipart->buffer = NULL;
+ multipart->header_completed = FALSE;
+ g_free (multipart->boundary);
+ multipart->boundary = NULL;
+ g_free (multipart->mime_type);
+ multipart->mime_type = NULL;
+ gst_adapter_clear (multipart->adapter);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
@@ -509,9 +566,12 @@ gst_multipart_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_BOUNDARY:
- g_free (filter->prefix);
- filter->prefix = g_value_dup_string (value);
- filter->prefixLen = strlen (filter->prefix);
+ /* Not really that usefull anymore as we can reliably autoscan */
+ g_free (filter->boundary);
+ filter->boundary = g_value_dup_string (value);
+ if (filter->boundary != NULL) {
+ filter->boundary_len = strlen (filter->boundary);
+ }
break;
case PROP_AUTOSCAN:
filter->autoscan = g_value_get_boolean (value);
@@ -533,7 +593,7 @@ gst_multipart_get_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_BOUNDARY:
- g_value_set_string (value, filter->prefix);
+ g_value_set_string (value, filter->boundary);
break;
case PROP_AUTOSCAN:
g_value_set_boolean (value, filter->autoscan);
diff --git a/gst/multipart/multipartmux.c b/gst/multipart/multipartmux.c
index 1cc61a9a..bc79fab5 100644
--- a/gst/multipart/multipartmux.c
+++ b/gst/multipart/multipartmux.c
@@ -445,6 +445,8 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
size_t newlen, headerlen;
GstBuffer *newbuf = NULL;
GstStructure *structure = NULL;
+ guint8 *data;
+ guint datasize;
GST_DEBUG_OBJECT (mux, "all pads are collected");
@@ -483,11 +485,14 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
goto beach;
}
- header = g_strdup_printf ("\n--%s\nContent-type: %s\n\n",
+ header = g_strdup_printf ("--%s\nContent-type: %s\n\n",
mux->boundary, gst_structure_get_name (structure));
+ datasize = GST_BUFFER_SIZE (best->buffer);
+
headerlen = strlen (header);
- newlen = headerlen + GST_BUFFER_SIZE (best->buffer);
+ /* header, data, trailing \n */
+ newlen = headerlen + datasize + 1;
ret =
gst_pad_alloc_buffer_and_set_caps (mux->srcpad, GST_BUFFER_OFFSET_NONE,
@@ -498,9 +503,13 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
goto beach;
}
- memcpy (GST_BUFFER_DATA (newbuf), header, headerlen);
- memcpy (GST_BUFFER_DATA (newbuf) + headerlen,
- GST_BUFFER_DATA (best->buffer), GST_BUFFER_SIZE (best->buffer));
+ data = GST_BUFFER_DATA (newbuf);
+
+ memcpy (data, header, headerlen);
+ memcpy (data + headerlen, GST_BUFFER_DATA (best->buffer), datasize);
+
+ /* trailing \n */
+ data[headerlen + datasize] = '\n';
gst_buffer_stamp (newbuf, best->buffer);
GST_BUFFER_OFFSET (newbuf) = mux->offset;