mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
multipart: port to 0.11
This commit is contained in:
parent
caf1760694
commit
8926a8f753
3 changed files with 80 additions and 114 deletions
|
@ -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,13 +498,15 @@ 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;
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue