Commit 8926a8f7 authored by Wim Taymans's avatar Wim Taymans

multipart: port to 0.11

parent caf17606
......@@ -126,23 +126,8 @@ 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);
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>");
}
#define gst_multipart_demux_parent_class parent_class
G_DEFINE_TYPE (GstMultipartDemux, gst_multipart_demux, GST_TYPE_ELEMENT);
static void
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;
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
gst_multipart_demux_init (GstMultipartDemux * multipart,
GstMultipartDemuxClass * g_class)
gst_multipart_demux_init (GstMultipartDemux * multipart)
{
/* create the sink pad */
multipart->sinkpad =
......@@ -392,7 +385,7 @@ multipart_parse_header (GstMultipartDemux * multipart)
guint8 *end, *next;
datalen = gst_adapter_available (multipart->adapter);
data = gst_adapter_peek (multipart->adapter, datalen);
data = gst_adapter_map (multipart->adapter, datalen);
dataend = data + datalen;
/* 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);
pos++);
if (pos >= dataend - 4) {
return MULTIPART_NEED_MORE_DATA;
}
if (pos >= dataend - 4)
goto need_more_data;
if (G_UNLIKELY (pos[0] != '-' || pos[1] != '-')) {
GST_DEBUG_OBJECT (multipart, "No boundary available");
......@@ -411,7 +403,7 @@ multipart_parse_header (GstMultipartDemux * multipart)
/* First the boundary */
if (!get_line_end (pos, dataend, &end, &next))
return MULTIPART_NEED_MORE_DATA;
goto need_more_data;
/* Ignore the leading -- */
boundary_len = end - pos - 2;
......@@ -430,9 +422,9 @@ multipart_parse_header (GstMultipartDemux * multipart)
* 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;
}
!strncmp (boundary + multipart->boundary_len, "--", 2)))
goto eos;
GST_DEBUG_OBJECT (multipart,
"Boundary length doesn't match detected boundary (%d <> %d",
boundary_len, multipart->boundary_len);
......@@ -442,7 +434,6 @@ multipart_parse_header (GstMultipartDemux * multipart)
goto wrong_header;
}
pos = next;
while (get_line_end (pos, dataend, &end, &next)) {
guint len = end - pos;
......@@ -452,6 +443,7 @@ multipart_parse_header (GstMultipartDemux * multipart)
GST_DEBUG_OBJECT (multipart,
"Parsed the header - boundary: %s, mime-type: %s, content-length: %d",
multipart->boundary, multipart->mime_type, multipart->content_length);
gst_adapter_unmap (multipart->adapter, 0);
return next - data;
}
......@@ -471,15 +463,26 @@ multipart_parse_header (GstMultipartDemux * multipart)
}
pos = next;
}
need_more_data:
GST_DEBUG_OBJECT (multipart, "Need more data for the header");
gst_adapter_unmap (multipart->adapter, 0);
return MULTIPART_NEED_MORE_DATA;
wrong_header:
{
GST_ELEMENT_ERROR (multipart, STREAM, DEMUX, (NULL),
("Boundary not found in the multipart header"));
gst_adapter_unmap (multipart->adapter, 0);
return MULTIPART_DATA_ERROR;
}
eos:
{
GST_DEBUG_OBJECT (multipart, "we are EOS");
gst_adapter_unmap (multipart->adapter, 0);
return MULTIPART_DATA_EOS;
}
}
static gint
......@@ -495,14 +498,16 @@ multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
len = multipart->content_length;
if (gst_adapter_available (multipart->adapter) >= len + 2) {
*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] == '\r')
len += 2;
else if (data[len] == '\n')
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 */
return len;
} else {
......@@ -514,7 +519,7 @@ multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
len = gst_adapter_available (multipart->adapter);
if (len == 0)
return MULTIPART_NEED_MORE_DATA;
data = gst_adapter_peek (multipart->adapter, len);
data = gst_adapter_map (multipart->adapter, len);
dataend = data + len;
for (pos = data + multipart->scanpos;
......@@ -530,10 +535,12 @@ multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
len -= 1;
*datalen = len;
gst_adapter_unmap (multipart->adapter, 0);
multipart->scanpos = 0;
return pos - data;
}
}
gst_adapter_unmap (multipart->adapter, 0);
multipart->scanpos = pos - 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);
gst_adapter_flush (adapter, size - datalen);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (srcpad->pad));
if (created) {
GstTagList *tags;
GstSegment segment;
gst_segment_init (&segment, GST_FORMAT_TIME);
/* Push new segment, first buffer has 0 timestamp */
gst_pad_push_event (srcpad->pad,
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
tags =
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,
"pushing buffer with timestamp %" GST_TIME_FORMAT,
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_multipart_combine_flows (multipart, srcpad, res);
if (res != GST_FLOW_OK)
......
......@@ -75,16 +75,12 @@ static const MimeTypeMap mimetypes[] = {
{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 gboolean gst_multipart_mux_handle_src_event (GstPad * pad,
GstEvent * event);
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 *
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,
GValue * value, GParamSpec * pspec);
static GstElementClass *parent_class = NULL;
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>");
}
#define gst_multipart_mux_parent_class parent_class
G_DEFINE_TYPE (GstMultipartMux, gst_multipart_mux, GST_TYPE_ELEMENT);
static void
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->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 */
klass->mimetypes = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; mimetypes[i].key; i++) {
......@@ -205,7 +171,7 @@ gst_multipart_mux_finalize (GObject * object)
static GstPad *
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;
GstPad *newpad;
......@@ -232,6 +198,7 @@ gst_multipart_mux_request_new_pad (GstElement * element,
sizeof (GstMultipartPadData));
/* save a pointer to our data in the pad */
multipartpad->pad = newpad;
gst_pad_set_element_private (newpad, multipartpad);
multipart_mux->numpads++;
}
......@@ -430,6 +397,7 @@ gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
GstBuffer *footerbuf = NULL;
GstBuffer *databuf = NULL;
GstStructure *structure = NULL;
GstCaps *caps;
const gchar *mime;
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 */
if (mux->need_segment) {
GstEvent *event;
GstClockTime time;
GstSegment segment;
if (best->timestamp != -1)
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
* length and the position is 0 */
event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
time, -1, 0);
gst_segment_init (&segment, GST_FORMAT_TIME);
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;
}
structure = gst_caps_get_structure (GST_BUFFER_CAPS (best->buffer), 0);
if (!structure)
caps = gst_pad_get_current_caps (best->pad);
if (caps == NULL)
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 */
mime = gst_multipart_mux_get_mime (mux, structure);
gst_caps_unref (caps);
header = g_strdup_printf ("--%s\r\nContent-Type: %s\r\n"
"Content-Length: %u\r\n\r\n",
mux->boundary, mime, GST_BUFFER_SIZE (best->buffer));
"Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n",
mux->boundary, mime, gst_buffer_get_size (best->buffer));
headerlen = strlen (header);
ret = gst_pad_alloc_buffer_and_set_caps (mux->srcpad, GST_BUFFER_OFFSET_NONE,
headerlen, GST_PAD_CAPS (mux->srcpad), &headerbuf);
if (ret != GST_FLOW_OK)
goto alloc_failed;
memcpy (GST_BUFFER_DATA (headerbuf), header, headerlen);
headerbuf = gst_buffer_new_allocate (NULL, headerlen, 1);
gst_buffer_fill (headerbuf, 0, header, headerlen);
g_free (header);
/* 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
* now. */
databuf = gst_buffer_make_metadata_writable (best->buffer);
databuf = gst_buffer_make_writable (best->buffer);
best->buffer = NULL;
gst_buffer_set_caps (databuf, GST_PAD_CAPS (mux->srcpad));
/* we need to updated the timestamp to match the running_time */
GST_BUFFER_TIMESTAMP (databuf) = best->timestamp;
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_FLAG_SET (databuf, GST_BUFFER_FLAG_DELTA_UNIT);
GST_DEBUG_OBJECT (mux, "pushing %u bytes data buffer",
GST_BUFFER_SIZE (databuf));
GST_DEBUG_OBJECT (mux, "pushing %" G_GSIZE_FORMAT " bytes data buffer",
gst_buffer_get_size (databuf));
ret = gst_pad_push (mux->srcpad, databuf);
if (ret != GST_FLOW_OK)
/* push always takes ownership of the buffer, even after an error, so we
* don't need to unref headerbuf here. */
goto beach;
ret = gst_pad_alloc_buffer_and_set_caps (mux->srcpad, GST_BUFFER_OFFSET_NONE,
2, GST_PAD_CAPS (mux->srcpad), &footerbuf);
if (ret != GST_FLOW_OK)
goto alloc_failed;
memcpy (GST_BUFFER_DATA (footerbuf), "\r\n", 2);
footerbuf = gst_buffer_new_allocate (NULL, 2, 1);
gst_buffer_fill (footerbuf, 0, "\r\n", 2);
/* the footer has the same timestamp as the data buffer and has a
* duration of 0 */
......@@ -590,13 +556,6 @@ no_caps:
ret = GST_FLOW_NOT_NEGOTIATED;
goto beach;
}
alloc_failed:
{
GST_WARNING_OBJECT (mux,
"failed allocating a %" G_GSIZE_FORMAT " bytes buffer", headerlen);
g_free (header);
goto beach;
}
}
static void
......
......@@ -47,6 +47,7 @@ typedef struct
GstBuffer *buffer; /* the queued buffer for this pad */
GstClockTime timestamp; /* its timestamp, converted to running_time so that we can
correctly sort over multiple segments. */
GstPad *pad;
}
GstMultipartPadData;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment