multipart: port to 0.11

This commit is contained in:
Wim Taymans 2011-07-10 12:46:03 +02:00
parent caf1760694
commit 8926a8f753
3 changed files with 80 additions and 114 deletions

View file

@ -126,23 +126,8 @@ static void gst_multipart_get_property (GObject * object, guint prop_id,
static void gst_multipart_demux_finalize (GObject * object); static void gst_multipart_demux_finalize (GObject * object);
GST_BOILERPLATE (GstMultipartDemux, gst_multipart_demux, GstElement, #define gst_multipart_demux_parent_class parent_class
GST_TYPE_ELEMENT); G_DEFINE_TYPE (GstMultipartDemux, gst_multipart_demux, GST_TYPE_ELEMENT);
static void
gst_multipart_demux_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
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));
gst_element_class_set_details_simple (element_class, "Multipart demuxer",
"Codec/Demuxer",
"demux multipart streams",
"Wim Taymans <wim.taymans@gmail.com>, Sjoerd Simons <sjoerd@luon.net>");
}
static void static void
gst_multipart_demux_class_init (GstMultipartDemuxClass * klass) gst_multipart_demux_class_init (GstMultipartDemuxClass * klass)
@ -189,11 +174,19 @@ gst_multipart_demux_class_init (GstMultipartDemuxClass * klass)
} }
gstelement_class->change_state = gst_multipart_demux_change_state; gstelement_class->change_state = gst_multipart_demux_change_state;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&multipart_demux_sink_template_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&multipart_demux_src_template_factory));
gst_element_class_set_details_simple (gstelement_class, "Multipart demuxer",
"Codec/Demuxer",
"demux multipart streams",
"Wim Taymans <wim.taymans@gmail.com>, Sjoerd Simons <sjoerd@luon.net>");
} }
static void static void
gst_multipart_demux_init (GstMultipartDemux * multipart, gst_multipart_demux_init (GstMultipartDemux * multipart)
GstMultipartDemuxClass * g_class)
{ {
/* create the sink pad */ /* create the sink pad */
multipart->sinkpad = multipart->sinkpad =
@ -392,7 +385,7 @@ multipart_parse_header (GstMultipartDemux * multipart)
guint8 *end, *next; guint8 *end, *next;
datalen = gst_adapter_available (multipart->adapter); datalen = gst_adapter_available (multipart->adapter);
data = gst_adapter_peek (multipart->adapter, datalen); data = gst_adapter_map (multipart->adapter, datalen);
dataend = data + datalen; dataend = data + datalen;
/* Skip leading whitespace, pos endposition should at least leave space for /* Skip leading whitespace, pos endposition should at least leave space for
@ -400,9 +393,8 @@ multipart_parse_header (GstMultipartDemux * multipart)
for (pos = (guint8 *) data; pos < dataend - 4 && g_ascii_isspace (*pos); for (pos = (guint8 *) data; pos < dataend - 4 && g_ascii_isspace (*pos);
pos++); pos++);
if (pos >= dataend - 4) { if (pos >= dataend - 4)
return MULTIPART_NEED_MORE_DATA; goto need_more_data;
}
if (G_UNLIKELY (pos[0] != '-' || pos[1] != '-')) { if (G_UNLIKELY (pos[0] != '-' || pos[1] != '-')) {
GST_DEBUG_OBJECT (multipart, "No boundary available"); GST_DEBUG_OBJECT (multipart, "No boundary available");
@ -411,7 +403,7 @@ multipart_parse_header (GstMultipartDemux * multipart)
/* First the boundary */ /* First the boundary */
if (!get_line_end (pos, dataend, &end, &next)) if (!get_line_end (pos, dataend, &end, &next))
return MULTIPART_NEED_MORE_DATA; goto need_more_data;
/* Ignore the leading -- */ /* Ignore the leading -- */
boundary_len = end - pos - 2; boundary_len = end - pos - 2;
@ -430,9 +422,9 @@ multipart_parse_header (GstMultipartDemux * multipart)
* invalid */ * invalid */
if (G_UNLIKELY (boundary_len == multipart->boundary_len + 2 && if (G_UNLIKELY (boundary_len == multipart->boundary_len + 2 &&
!strncmp (boundary, multipart->boundary, multipart->boundary_len) && !strncmp (boundary, multipart->boundary, multipart->boundary_len) &&
!strncmp (boundary + multipart->boundary_len, "--", 2))) { !strncmp (boundary + multipart->boundary_len, "--", 2)))
return MULTIPART_DATA_EOS; goto eos;
}
GST_DEBUG_OBJECT (multipart, GST_DEBUG_OBJECT (multipart,
"Boundary length doesn't match detected boundary (%d <> %d", "Boundary length doesn't match detected boundary (%d <> %d",
boundary_len, multipart->boundary_len); boundary_len, multipart->boundary_len);
@ -442,7 +434,6 @@ multipart_parse_header (GstMultipartDemux * multipart)
goto wrong_header; goto wrong_header;
} }
pos = next; pos = next;
while (get_line_end (pos, dataend, &end, &next)) { while (get_line_end (pos, dataend, &end, &next)) {
guint len = end - pos; guint len = end - pos;
@ -452,6 +443,7 @@ multipart_parse_header (GstMultipartDemux * multipart)
GST_DEBUG_OBJECT (multipart, GST_DEBUG_OBJECT (multipart,
"Parsed the header - boundary: %s, mime-type: %s, content-length: %d", "Parsed the header - boundary: %s, mime-type: %s, content-length: %d",
multipart->boundary, multipart->mime_type, multipart->content_length); multipart->boundary, multipart->mime_type, multipart->content_length);
gst_adapter_unmap (multipart->adapter, 0);
return next - data; return next - data;
} }
@ -471,15 +463,26 @@ multipart_parse_header (GstMultipartDemux * multipart)
} }
pos = next; pos = next;
} }
need_more_data:
GST_DEBUG_OBJECT (multipart, "Need more data for the header"); GST_DEBUG_OBJECT (multipart, "Need more data for the header");
gst_adapter_unmap (multipart->adapter, 0);
return MULTIPART_NEED_MORE_DATA; return MULTIPART_NEED_MORE_DATA;
wrong_header: wrong_header:
{ {
GST_ELEMENT_ERROR (multipart, STREAM, DEMUX, (NULL), GST_ELEMENT_ERROR (multipart, STREAM, DEMUX, (NULL),
("Boundary not found in the multipart header")); ("Boundary not found in the multipart header"));
gst_adapter_unmap (multipart->adapter, 0);
return MULTIPART_DATA_ERROR; return MULTIPART_DATA_ERROR;
} }
eos:
{
GST_DEBUG_OBJECT (multipart, "we are EOS");
gst_adapter_unmap (multipart->adapter, 0);
return MULTIPART_DATA_EOS;
}
} }
static gint static gint
@ -495,14 +498,16 @@ multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
len = multipart->content_length; len = multipart->content_length;
if (gst_adapter_available (multipart->adapter) >= len + 2) { if (gst_adapter_available (multipart->adapter) >= len + 2) {
*datalen = len; *datalen = len;
data = gst_adapter_peek (multipart->adapter, len + 1); data = gst_adapter_map (multipart->adapter, len + 1);
/* If data[len] contains \r then assume a newline is \r\n */ /* If data[len] contains \r then assume a newline is \r\n */
if (data[len] == '\r') if (data[len] == '\r')
len += 2; len += 2;
else if (data[len] == '\n') else if (data[len] == '\n')
len += 1; len += 1;
/* Don't check if boundary is actually there, but let the header parsing
gst_adapter_unmap (multipart->adapter, 0);
/* Don't check if boundary is actually there, but let the header parsing
* bail out if it isn't */ * bail out if it isn't */
return len; return len;
} else { } else {
@ -514,7 +519,7 @@ multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
len = gst_adapter_available (multipart->adapter); len = gst_adapter_available (multipart->adapter);
if (len == 0) if (len == 0)
return MULTIPART_NEED_MORE_DATA; return MULTIPART_NEED_MORE_DATA;
data = gst_adapter_peek (multipart->adapter, len); data = gst_adapter_map (multipart->adapter, len);
dataend = data + len; dataend = data + len;
for (pos = data + multipart->scanpos; for (pos = data + multipart->scanpos;
@ -530,10 +535,12 @@ multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
len -= 1; len -= 1;
*datalen = len; *datalen = len;
gst_adapter_unmap (multipart->adapter, 0);
multipart->scanpos = 0; multipart->scanpos = 0;
return pos - data; return pos - data;
} }
} }
gst_adapter_unmap (multipart->adapter, 0);
multipart->scanpos = pos - data; multipart->scanpos = pos - data;
return MULTIPART_NEED_MORE_DATA; return MULTIPART_NEED_MORE_DATA;
} }
@ -591,13 +598,14 @@ gst_multipart_demux_chain (GstPad * pad, GstBuffer * buf)
outbuf = gst_adapter_take_buffer (adapter, datalen); outbuf = gst_adapter_take_buffer (adapter, datalen);
gst_adapter_flush (adapter, size - datalen); gst_adapter_flush (adapter, size - datalen);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (srcpad->pad));
if (created) { if (created) {
GstTagList *tags; GstTagList *tags;
GstSegment segment;
gst_segment_init (&segment, GST_FORMAT_TIME);
/* Push new segment, first buffer has 0 timestamp */ /* Push new segment, first buffer has 0 timestamp */
gst_pad_push_event (srcpad->pad, gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
tags = tags =
gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "Multipart", NULL); gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "Multipart", NULL);
@ -610,8 +618,6 @@ gst_multipart_demux_chain (GstPad * pad, GstBuffer * buf)
GST_DEBUG_OBJECT (multipart, GST_DEBUG_OBJECT (multipart,
"pushing buffer with timestamp %" GST_TIME_FORMAT, "pushing buffer with timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
GST_DEBUG_OBJECT (multipart, "buffer has caps %" GST_PTR_FORMAT,
GST_BUFFER_CAPS (outbuf));
res = gst_pad_push (srcpad->pad, outbuf); res = gst_pad_push (srcpad->pad, outbuf);
res = gst_multipart_combine_flows (multipart, srcpad, res); res = gst_multipart_combine_flows (multipart, srcpad, res);
if (res != GST_FLOW_OK) if (res != GST_FLOW_OK)

View file

@ -75,16 +75,12 @@ static const MimeTypeMap mimetypes[] = {
{NULL, NULL} {NULL, NULL}
}; };
static void gst_multipart_mux_base_init (gpointer g_class);
static void gst_multipart_mux_class_init (GstMultipartMuxClass * klass);
static void gst_multipart_mux_init (GstMultipartMux * multipart_mux);
static void gst_multipart_mux_finalize (GObject * object); static void gst_multipart_mux_finalize (GObject * object);
static gboolean gst_multipart_mux_handle_src_event (GstPad * pad, static gboolean gst_multipart_mux_handle_src_event (GstPad * pad,
GstEvent * event); GstEvent * event);
static GstPad *gst_multipart_mux_request_new_pad (GstElement * element, static GstPad *gst_multipart_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name); GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static GstStateChangeReturn gst_multipart_mux_change_state (GstElement * static GstStateChangeReturn gst_multipart_mux_change_state (GstElement *
element, GstStateChange transition); element, GstStateChange transition);
@ -96,46 +92,8 @@ static void gst_multipart_mux_set_property (GObject * object, guint prop_id,
static void gst_multipart_mux_get_property (GObject * object, guint prop_id, static void gst_multipart_mux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static GstElementClass *parent_class = NULL; #define gst_multipart_mux_parent_class parent_class
G_DEFINE_TYPE (GstMultipartMux, gst_multipart_mux, GST_TYPE_ELEMENT);
GType
gst_multipart_mux_get_type (void)
{
static GType multipart_mux_type = 0;
if (!multipart_mux_type) {
static const GTypeInfo multipart_mux_info = {
sizeof (GstMultipartMuxClass),
gst_multipart_mux_base_init,
NULL,
(GClassInitFunc) gst_multipart_mux_class_init,
NULL,
NULL,
sizeof (GstMultipartMux),
0,
(GInstanceInitFunc) gst_multipart_mux_init,
};
multipart_mux_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstMultipartMux",
&multipart_mux_info, 0);
}
return multipart_mux_type;
}
static void
gst_multipart_mux_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details_simple (element_class, "Multipart muxer",
"Codec/Muxer", "mux multipart streams", "Wim Taymans <wim@fluendo.com>");
}
static void static void
gst_multipart_mux_class_init (GstMultipartMuxClass * klass) gst_multipart_mux_class_init (GstMultipartMuxClass * klass)
@ -160,6 +118,14 @@ gst_multipart_mux_class_init (GstMultipartMuxClass * klass)
gstelement_class->request_new_pad = gst_multipart_mux_request_new_pad; gstelement_class->request_new_pad = gst_multipart_mux_request_new_pad;
gstelement_class->change_state = gst_multipart_mux_change_state; gstelement_class->change_state = gst_multipart_mux_change_state;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details_simple (gstelement_class, "Multipart muxer",
"Codec/Muxer", "mux multipart streams", "Wim Taymans <wim@fluendo.com>");
/* populate mime types */ /* populate mime types */
klass->mimetypes = g_hash_table_new (g_str_hash, g_str_equal); klass->mimetypes = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; mimetypes[i].key; i++) { for (i = 0; mimetypes[i].key; i++) {
@ -205,7 +171,7 @@ gst_multipart_mux_finalize (GObject * object)
static GstPad * static GstPad *
gst_multipart_mux_request_new_pad (GstElement * element, gst_multipart_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * req_name) GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
{ {
GstMultipartMux *multipart_mux; GstMultipartMux *multipart_mux;
GstPad *newpad; GstPad *newpad;
@ -232,6 +198,7 @@ gst_multipart_mux_request_new_pad (GstElement * element,
sizeof (GstMultipartPadData)); sizeof (GstMultipartPadData));
/* save a pointer to our data in the pad */ /* save a pointer to our data in the pad */
multipartpad->pad = newpad;
gst_pad_set_element_private (newpad, multipartpad); gst_pad_set_element_private (newpad, multipartpad);
multipart_mux->numpads++; multipart_mux->numpads++;
} }
@ -430,6 +397,7 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
GstBuffer *footerbuf = NULL; GstBuffer *footerbuf = NULL;
GstBuffer *databuf = NULL; GstBuffer *databuf = NULL;
GstStructure *structure = NULL; GstStructure *structure = NULL;
GstCaps *caps;
const gchar *mime; const gchar *mime;
GST_DEBUG_OBJECT (mux, "all pads are collected"); GST_DEBUG_OBJECT (mux, "all pads are collected");
@ -460,8 +428,8 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
/* see if we need to push a segment */ /* see if we need to push a segment */
if (mux->need_segment) { if (mux->need_segment) {
GstEvent *event;
GstClockTime time; GstClockTime time;
GstSegment segment;
if (best->timestamp != -1) if (best->timestamp != -1)
time = best->timestamp; time = best->timestamp;
@ -470,32 +438,35 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
/* for the segment, we take the first timestamp we see, we don't know the /* for the segment, we take the first timestamp we see, we don't know the
* length and the position is 0 */ * length and the position is 0 */
event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, gst_segment_init (&segment, GST_FORMAT_TIME);
time, -1, 0); segment.start = time;
gst_pad_push_event (mux->srcpad, event); gst_pad_push_event (mux->srcpad, gst_event_new_segment (&segment));
mux->need_segment = FALSE; mux->need_segment = FALSE;
} }
structure = gst_caps_get_structure (GST_BUFFER_CAPS (best->buffer), 0); caps = gst_pad_get_current_caps (best->pad);
if (!structure) if (caps == NULL)
goto no_caps; goto no_caps;
structure = gst_caps_get_structure (caps, 0);
if (!structure) {
gst_caps_unref (caps);
goto no_caps;
}
/* get the mime type for the structure */ /* get the mime type for the structure */
mime = gst_multipart_mux_get_mime (mux, structure); mime = gst_multipart_mux_get_mime (mux, structure);
gst_caps_unref (caps);
header = g_strdup_printf ("--%s\r\nContent-Type: %s\r\n" header = g_strdup_printf ("--%s\r\nContent-Type: %s\r\n"
"Content-Length: %u\r\n\r\n", "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n",
mux->boundary, mime, GST_BUFFER_SIZE (best->buffer)); mux->boundary, mime, gst_buffer_get_size (best->buffer));
headerlen = strlen (header); headerlen = strlen (header);
ret = gst_pad_alloc_buffer_and_set_caps (mux->srcpad, GST_BUFFER_OFFSET_NONE, headerbuf = gst_buffer_new_allocate (NULL, headerlen, 1);
headerlen, GST_PAD_CAPS (mux->srcpad), &headerbuf); gst_buffer_fill (headerbuf, 0, header, headerlen);
if (ret != GST_FLOW_OK)
goto alloc_failed;
memcpy (GST_BUFFER_DATA (headerbuf), header, headerlen);
g_free (header); g_free (header);
/* the header has the same timestamp as the data buffer (which we will push /* the header has the same timestamp as the data buffer (which we will push
@ -516,31 +487,26 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
/* take best->buffer, we don't need to unref it later as we will push it /* take best->buffer, we don't need to unref it later as we will push it
* now. */ * now. */
databuf = gst_buffer_make_metadata_writable (best->buffer); databuf = gst_buffer_make_writable (best->buffer);
best->buffer = NULL; best->buffer = NULL;
gst_buffer_set_caps (databuf, GST_PAD_CAPS (mux->srcpad));
/* we need to updated the timestamp to match the running_time */ /* we need to updated the timestamp to match the running_time */
GST_BUFFER_TIMESTAMP (databuf) = best->timestamp; GST_BUFFER_TIMESTAMP (databuf) = best->timestamp;
GST_BUFFER_OFFSET (databuf) = mux->offset; GST_BUFFER_OFFSET (databuf) = mux->offset;
mux->offset += GST_BUFFER_SIZE (databuf); mux->offset += gst_buffer_get_size (databuf);
GST_BUFFER_OFFSET_END (databuf) = mux->offset; GST_BUFFER_OFFSET_END (databuf) = mux->offset;
GST_BUFFER_FLAG_SET (databuf, GST_BUFFER_FLAG_DELTA_UNIT); GST_BUFFER_FLAG_SET (databuf, GST_BUFFER_FLAG_DELTA_UNIT);
GST_DEBUG_OBJECT (mux, "pushing %u bytes data buffer", GST_DEBUG_OBJECT (mux, "pushing %" G_GSIZE_FORMAT " bytes data buffer",
GST_BUFFER_SIZE (databuf)); gst_buffer_get_size (databuf));
ret = gst_pad_push (mux->srcpad, databuf); ret = gst_pad_push (mux->srcpad, databuf);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
/* push always takes ownership of the buffer, even after an error, so we /* push always takes ownership of the buffer, even after an error, so we
* don't need to unref headerbuf here. */ * don't need to unref headerbuf here. */
goto beach; goto beach;
ret = gst_pad_alloc_buffer_and_set_caps (mux->srcpad, GST_BUFFER_OFFSET_NONE, footerbuf = gst_buffer_new_allocate (NULL, 2, 1);
2, GST_PAD_CAPS (mux->srcpad), &footerbuf); gst_buffer_fill (footerbuf, 0, "\r\n", 2);
if (ret != GST_FLOW_OK)
goto alloc_failed;
memcpy (GST_BUFFER_DATA (footerbuf), "\r\n", 2);
/* the footer has the same timestamp as the data buffer and has a /* the footer has the same timestamp as the data buffer and has a
* duration of 0 */ * duration of 0 */
@ -590,13 +556,6 @@ no_caps:
ret = GST_FLOW_NOT_NEGOTIATED; ret = GST_FLOW_NOT_NEGOTIATED;
goto beach; goto beach;
} }
alloc_failed:
{
GST_WARNING_OBJECT (mux,
"failed allocating a %" G_GSIZE_FORMAT " bytes buffer", headerlen);
g_free (header);
goto beach;
}
} }
static void static void

View file

@ -47,6 +47,7 @@ typedef struct
GstBuffer *buffer; /* the queued buffer for this pad */ GstBuffer *buffer; /* the queued buffer for this pad */
GstClockTime timestamp; /* its timestamp, converted to running_time so that we can GstClockTime timestamp; /* its timestamp, converted to running_time so that we can
correctly sort over multiple segments. */ correctly sort over multiple segments. */
GstPad *pad;
} }
GstMultipartPadData; GstMultipartPadData;