diff --git a/ChangeLog b/ChangeLog index 13b7525f63..87224d35e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2005-11-30 Julien MOUTTE + + * configure.ac: + * PORTED_O9: + * gst/multipart/Makefile.am: + * gst/multipart/multipartdemux.c: (gst_multipart_demux_base_init), + (gst_multipart_demux_class_init), (gst_multipart_demux_init), + (gst_multipart_find_pad_by_mime), (gst_multipart_demux_chain), + (gst_multipart_demux_change_state), + (gst_multipart_demux_plugin_init): + * gst/multipart/multipartmux.c: (gst_multipart_mux_class_init), + (gst_multipart_mux_init), (gst_multipart_mux_finalize), + (gst_multipart_mux_sinkconnect), + (gst_multipart_mux_request_new_pad), + (gst_multipart_mux_handle_src_event), + (gst_multipart_mux_queue_pads), (gst_multipart_mux_collected), + (gst_multipart_mux_change_state): Ported multipart mux/demux to + 0.9. + 2005-11-30 Thomas Vander Stichele * gst/debug/gstnavigationtest.c: (gst_navigationtest_get_type): diff --git a/PORTED_09 b/PORTED_09 index 169985bc5a..f96297ddc7 100644 --- a/PORTED_09 +++ b/PORTED_09 @@ -11,6 +11,7 @@ libcaca (zeeshan) law (wim) shout2 (zaheer) - not fully tested esdsink (arwed) +multipart (dolphy) osssink is partially done in the threaded branch (wim) diff --git a/configure.ac b/configure.ac index a733368101..9b6fb920f3 100644 --- a/configure.ac +++ b/configure.ac @@ -78,6 +78,7 @@ GST_PLUGINS_ALL="\ law \ level \ matroska \ + multipart \ rtp \ rtsp \ smpte \ @@ -534,6 +535,7 @@ gst/goom/Makefile gst/law/Makefile gst/level/Makefile gst/matroska/Makefile +gst/multipart/Makefile gst/rtp/Makefile gst/rtsp/Makefile gst/smpte/Makefile diff --git a/gst/multipart/Makefile.am b/gst/multipart/Makefile.am index 7dfb9c2bf0..a142f461d0 100644 --- a/gst/multipart/Makefile.am +++ b/gst/multipart/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgstmultipart.la libgstmultipart_la_SOURCES = multipart.c multipartdemux.c multipartmux.c -libgstmultipart_la_CFLAGS = $(GST_CFLAGS) -libgstmultipart_la_LIBADD = $(GST_LIBS) +libgstmultipart_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) +libgstmultipart_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) libgstmultipart_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/gst/multipart/multipartdemux.c b/gst/multipart/multipartdemux.c index bbd60c83eb..0138f26365 100644 --- a/gst/multipart/multipartdemux.c +++ b/gst/multipart/multipartdemux.c @@ -22,6 +22,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif + #include #include @@ -114,13 +115,10 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS ("multipart/x-mixed-replace") ); - -static void gst_multipart_demux_finalize (GObject * object); - -static void gst_multipart_demux_chain (GstPad * pad, GstData * buffer); +static GstFlowReturn gst_multipart_demux_chain (GstPad * pad, GstBuffer * buf); static GstStateChangeReturn gst_multipart_demux_change_state (GstElement * - element); + element, GstStateChange transition); GST_BOILERPLATE (GstMultipartDemux, gst_multipart_demux, GstElement, @@ -144,11 +142,8 @@ static void gst_multipart_demux_class_init (GstMultipartDemuxClass * klass) { GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gstelement_class->change_state = gst_multipart_demux_change_state; - - gobject_class->finalize = gst_multipart_demux_finalize; } static void @@ -163,8 +158,6 @@ gst_multipart_demux_init (GstMultipartDemux * multipart, gst_pad_set_chain_function (multipart->sinkpad, GST_DEBUG_FUNCPTR (gst_multipart_demux_chain)); - GST_OBJECT_FLAG_SET (multipart, GST_ELEMENT_EVENT_AWARE); - multipart->maxlen = 4096; multipart->parsing_mime = NULL; multipart->numpads = 0; @@ -172,31 +165,9 @@ gst_multipart_demux_init (GstMultipartDemux * multipart, multipart->lastpos = 0; } -static void -gst_multipart_demux_finalize (GObject * object) -{ - GstMultipartDemux *multipart; - - multipart = GST_MULTIPART_DEMUX (object); -} - -static void -gst_multipart_demux_handle_event (GstPad * pad, GstEvent * event) -{ - //GstMultipartDemux *multipart = GST_MULTIPART_DEMUX (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_DISCONTINUOUS: - case GST_EVENT_EOS: - default: - gst_pad_event_default (pad, event); - break; - } - return; -} - static GstMultipartPad * -gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime) +gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime, + gboolean * created) { GSList *walk; @@ -205,12 +176,15 @@ gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime) GstMultipartPad *pad = (GstMultipartPad *) walk->data; if (!strcmp (pad->mime, mime)) { + if (created) { + *created = FALSE; + } return pad; } walk = walk->next; } - // pad not found, create it + /* pad not found, create it */ { GstPad *pad; GstMultipartPad *mppad; @@ -224,8 +198,8 @@ gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime) (&multipart_demux_src_template_factory), name); g_free (name); caps = gst_caps_from_string (mime); - gst_pad_use_explicit_caps (pad); - gst_pad_set_explicit_caps (pad, caps); + gst_pad_use_fixed_caps (pad); + gst_pad_set_caps (pad, caps); mppad->pad = pad; mppad->mime = g_strdup (mime); @@ -235,41 +209,39 @@ gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime) gst_element_add_pad (GST_ELEMENT (demux), pad); + if (created) { + *created = TRUE; + } + return mppad; } } -static void -gst_multipart_demux_chain (GstPad * pad, GstData * buffer) +static GstFlowReturn +gst_multipart_demux_chain (GstPad * pad, GstBuffer * buf) { GstMultipartDemux *multipart; - gint size; - gchar *data; - gint matchpos; - - /* handle events */ - if (GST_IS_EVENT (buffer)) { - gst_multipart_demux_handle_event (pad, GST_EVENT (buffer)); - return; - } + gint size, matchpos; + guchar *data; + GstFlowReturn ret = GST_FLOW_OK; multipart = GST_MULTIPART_DEMUX (gst_pad_get_parent (pad)); - data = GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); - // first make sure our buffer is long enough + /* first make sure our buffer is long enough */ if (multipart->bufsize + size > multipart->maxlen) { gint newsize = (multipart->bufsize + size) * 2; multipart->buffer = g_realloc (multipart->buffer, newsize); multipart->maxlen = newsize; } - // copy bytes into the buffer + /* copy bytes into the buffer */ memcpy (multipart->buffer + multipart->bufsize, data, size); multipart->bufsize += size; - // find \n + /* find \n */ while (multipart->scanpos < multipart->bufsize) { if (multipart->buffer[multipart->scanpos] == '\n') { break; @@ -277,7 +249,7 @@ gst_multipart_demux_chain (GstPad * pad, GstData * buffer) multipart->scanpos++; } - // then scan for the boundary + /* then scan for the boundary */ for (matchpos = 0; multipart->scanpos + toFindLen + MAX_LINE_LEN - matchpos < multipart->bufsize; multipart->scanpos++) { @@ -291,7 +263,7 @@ gst_multipart_demux_chain (GstPad * pad, GstData * buffer) multipart->scanpos++; start = multipart->scanpos; - // find \n + /* find \n */ for (i = 0; i < MAX_LINE_LEN; i++) { if (multipart->buffer[multipart->scanpos] == '\n') break; @@ -307,19 +279,37 @@ gst_multipart_demux_chain (GstPad * pad, GstData * buffer) if (datalen > 0 && multipart->parsing_mime) { GstBuffer *outbuf; GstMultipartPad *srcpad; + gboolean created = FALSE; srcpad = gst_multipart_find_pad_by_mime (multipart, - multipart->parsing_mime); + multipart->parsing_mime, &created); if (srcpad != NULL) { - outbuf = gst_buffer_new_and_alloc (datalen); + ret = gst_pad_alloc_buffer (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; - memcpy (GST_BUFFER_DATA (outbuf), multipart->buffer, datalen); - GST_BUFFER_TIMESTAMP (outbuf) = 0; - gst_pad_push (srcpad->pad, GST_DATA (outbuf)); + /* 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; + } + gst_pad_push (srcpad->pad, outbuf); + } } } - // move rest downward + /* move rest downward */ multipart->bufsize -= multipart->scanpos; memmove (multipart->buffer, multipart->buffer + multipart->scanpos, multipart->bufsize); @@ -333,7 +323,10 @@ gst_multipart_demux_chain (GstPad * pad, GstData * buffer) } } - gst_buffer_unref (buffer); + gst_buffer_unref (buf); + gst_object_unref (multipart); + + return ret; } static GstStateChangeReturn @@ -341,6 +334,7 @@ gst_multipart_demux_change_state (GstElement * element, GstStateChange transition) { GstMultipartDemux *multipart; + GstStateChangeReturn ret; multipart = GST_MULTIPART_DEMUX (element); @@ -352,6 +346,15 @@ gst_multipart_demux_change_state (GstElement * element, 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; + + switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: @@ -366,11 +369,11 @@ gst_multipart_demux_change_state (GstElement * element, break; } - return parent_class->change_state (element, transition); + return ret; } gboolean -gst_multipart_demux_plugin_init (GstPlugin * plugin, GstPluginClass * g_class) +gst_multipart_demux_plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (gst_multipart_demux_debug, "multipartdemux", 0, "multipart demuxer"); diff --git a/gst/multipart/multipartmux.c b/gst/multipart/multipartmux.c index 5f55e628f2..1c588b69b9 100644 --- a/gst/multipart/multipartmux.c +++ b/gst/multipart/multipartmux.c @@ -22,6 +22,8 @@ #endif #include +#include + #include GST_DEBUG_CATEGORY_STATIC (gst_multipart_mux_debug); @@ -39,14 +41,9 @@ typedef struct _GstMultipartMuxClass GstMultipartMuxClass; /* all information needed for one multipart stream */ typedef struct { - GstPad *pad; /* reference for this pad is held by element we belong to */ + GstCollectData collect; /* we extend the CollectData */ GstBuffer *buffer; /* the queued buffer for this pad */ - - gboolean eos; - const gchar *mimetype; - - guint state; /* state of the pad */ } GstMultipartPad; @@ -57,8 +54,9 @@ struct _GstMultipartMux /* pad */ GstPad *srcpad; - /* sinkpads, a GSList of GstMultipartPads */ - GSList *sinkpads; + /* sinkpads */ + GstCollectPads *collect; + gint numpads; /* offset in stream */ @@ -82,18 +80,13 @@ GST_ELEMENT_DETAILS ("multipart muxer", "mux multipart streams", "Wim Taymans "); -/* MultipartMux signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - #define DEFAULT_BOUNDARY "ThisRandomString" + enum { ARG_0, - ARG_BOUNDARY, + ARG_BOUNDARY + /* FILL ME */ }; static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", @@ -112,22 +105,25 @@ 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_loop (GstElement * element); +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); +static GstStateChangeReturn gst_multipart_mux_change_state (GstElement * + element, GstStateChange transition); + +static GstFlowReturn gst_multipart_mux_collected (GstCollectPads * pads, + GstMultipartMux * mux); + static void gst_multipart_mux_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_multipart_mux_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_multipart_mux_change_state (GstElement * - element); static GstElementClass *parent_class = NULL; -/*static guint gst_multipart_mux_signals[LAST_SIGNAL] = { 0 }; */ - GType gst_multipart_mux_get_type (void) { @@ -177,28 +173,16 @@ gst_multipart_mux_class_init (GstMultipartMuxClass * klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); - gstelement_class->request_new_pad = gst_multipart_mux_request_new_pad; - - gstelement_class->change_state = gst_multipart_mux_change_state; - - gstelement_class->get_property = gst_multipart_mux_get_property; - gstelement_class->set_property = gst_multipart_mux_set_property; + gobject_class->finalize = gst_multipart_mux_finalize; + gobject_class->get_property = gst_multipart_mux_get_property; + gobject_class->set_property = gst_multipart_mux_set_property; g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BOUNDARY, g_param_spec_string ("boundary", "Boundary", "Boundary string", DEFAULT_BOUNDARY, G_PARAM_READWRITE)); -} - -static const GstEventMask * -gst_multipart_mux_get_sink_event_masks (GstPad * pad) -{ - static const GstEventMask gst_multipart_mux_sink_event_masks[] = { - {GST_EVENT_EOS, 0}, - {0,} - }; - - return gst_multipart_mux_sink_event_masks; + gstelement_class->request_new_pad = gst_multipart_mux_request_new_pad; + gstelement_class->change_state = gst_multipart_mux_change_state; } static void @@ -213,52 +197,51 @@ gst_multipart_mux_init (GstMultipartMux * multipart_mux) gst_multipart_mux_handle_src_event); gst_element_add_pad (GST_ELEMENT (multipart_mux), multipart_mux->srcpad); - GST_OBJECT_FLAG_SET (GST_ELEMENT (multipart_mux), GST_ELEMENT_EVENT_AWARE); - - multipart_mux->sinkpads = NULL; multipart_mux->boundary = g_strdup (DEFAULT_BOUNDARY); multipart_mux->negotiated = FALSE; - gst_element_set_loop_function (GST_ELEMENT (multipart_mux), - gst_multipart_mux_loop); + multipart_mux->collect = gst_collect_pads_new (); + gst_collect_pads_set_function (multipart_mux->collect, + (GstCollectPadsFunction) gst_multipart_mux_collected, multipart_mux); +} + +static void +gst_multipart_mux_finalize (GObject * object) +{ + GstMultipartMux *multipart_mux; + + multipart_mux = GST_MULTIPART_MUX (object); + + if (multipart_mux->collect) { + gst_object_unref (multipart_mux->collect); + multipart_mux->collect = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); } static GstPadLinkReturn -gst_multipart_mux_sinkconnect (GstPad * pad, const GstCaps * vscaps) +gst_multipart_mux_sinkconnect (GstPad * pad, GstPad * peer) { GstMultipartMux *multipart_mux; GstMultipartPad *mppad; - GstStructure *structure; + gchar *pad_name = NULL; multipart_mux = GST_MULTIPART_MUX (gst_pad_get_parent (pad)); mppad = (GstMultipartPad *) gst_pad_get_element_private (pad); - GST_DEBUG ("multipart_mux: sinkconnect triggered on %s", - gst_pad_get_name (pad)); + pad_name = gst_pad_get_name (pad); - structure = gst_caps_get_structure (vscaps, 0); - mppad->mimetype = gst_structure_get_name (structure); + GST_DEBUG_OBJECT (multipart_mux, "sinkconnect triggered on %s", pad_name); + + g_free (pad_name); + + gst_object_unref (multipart_mux); return GST_PAD_LINK_OK; } -static void -gst_multipart_mux_pad_link (GstPad * pad, GstPad * peer, gpointer data) -{ - //GstMultipartMux *multipart_mux = GST_MULTIPART_MUX (data); - - GST_DEBUG ("pad '%s' connected", gst_pad_get_name (pad)); -} - -static void -gst_multipart_mux_pad_unlink (GstPad * pad, GstPad * peer, gpointer data) -{ - //GstMultipartMux *multipart_mux = GST_MULTIPART_MUX (data); - - GST_DEBUG ("pad '%s' unlinked", gst_pad_get_name (pad)); -} - static GstPad * gst_multipart_mux_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * req_name) @@ -289,16 +272,14 @@ gst_multipart_mux_request_new_pad (GstElement * element, /* construct our own wrapper data structure for the pad to * keep track of its status */ { - GstMultipartPad *multipartpad = g_new0 (GstMultipartPad, 1); + GstMultipartPad *multipartpad; - multipartpad->pad = newpad; - multipartpad->eos = FALSE; + multipartpad = (GstMultipartPad *) + gst_collect_pads_add_pad (multipart_mux->collect, newpad, + sizeof (GstMultipartPad)); /* save a pointer to our data in the pad */ gst_pad_set_element_private (newpad, multipartpad); - /* store our data for the pad */ - multipart_mux->sinkpads = - g_slist_prepend (multipart_mux->sinkpads, multipartpad); multipart_mux->numpads++; } } else { @@ -306,15 +287,9 @@ gst_multipart_mux_request_new_pad (GstElement * element, return NULL; } - g_signal_connect (newpad, "linked", - G_CALLBACK (gst_multipart_mux_pad_link), (gpointer) multipart_mux); - g_signal_connect (newpad, "unlinked", - G_CALLBACK (gst_multipart_mux_pad_unlink), (gpointer) multipart_mux); - /* setup some pad functions */ gst_pad_set_link_function (newpad, gst_multipart_mux_sinkconnect); - gst_pad_set_event_mask_function (newpad, - gst_multipart_mux_get_sink_event_masks); + /* dd the pad to the element */ gst_element_add_pad (element, newpad); @@ -340,39 +315,11 @@ gst_multipart_mux_handle_src_event (GstPad * pad, GstEvent * event) break; } + gst_object_unref (multipart_mux); + return gst_pad_event_default (pad, event); } -static GstBuffer * -gst_multipart_mux_next_buffer (GstMultipartPad * pad) -{ - GstData *data = NULL; - - while (data == NULL) { - GST_LOG ("muxer: pulling %s:%s", GST_DEBUG_PAD_NAME (pad->pad)); - data = gst_pad_pull (pad->pad); - /* if it's an event, handle it */ - if (GST_IS_EVENT (data)) { - GstEventType type; - GstMultipartMux *multipart_mux; - GstEvent *event = GST_EVENT (data); - - multipart_mux = GST_MULTIPART_MUX (gst_pad_get_parent (pad->pad)); - type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; - - switch (type) { - case GST_EVENT_EOS: - return NULL; - default: - gst_pad_event_default (pad->pad, event); - break; - } - data = NULL; - } - } - return GST_BUFFER (data); -} - /* * Given two pads, compare the buffers queued on it and return 0 if they have * an equal priority, 1 if the new pad is better, -1 if the old pad is better @@ -414,38 +361,44 @@ gst_multipart_mux_compare_pads (GstMultipartMux * multipart_mux, /* make sure a buffer is queued on all pads, returns a pointer to an multipartpad * that holds the best buffer or NULL when no pad was usable */ static GstMultipartPad * -gst_multipart_mux_queue_pads (GstMultipartMux * multipart_mux) +gst_multipart_mux_queue_pads (GstMultipartMux * mux) { + GSList *walk = NULL; GstMultipartPad *bestpad = NULL; - GSList *walk; + + g_return_val_if_fail (GST_IS_MULTIPART_MUX (mux), NULL); /* try to make sure we have a buffer from each usable pad first */ - walk = multipart_mux->sinkpads; + walk = mux->collect->data; while (walk) { - GstMultipartPad *pad = (GstMultipartPad *) walk->data; + GstCollectData *data = (GstCollectData *) walk->data; + GstMultipartPad *pad = (GstMultipartPad *) data; - walk = walk->next; + walk = g_slist_next (walk); /* try to get a new buffer for this pad if needed and possible */ - if (pad->buffer == NULL && GST_PAD_IS_USABLE (pad->pad)) { - pad->buffer = gst_multipart_mux_next_buffer (pad); - /* no next buffer, try another pad */ - if (pad->buffer == NULL) - continue; + if (pad->buffer == NULL) { + GstBuffer *buf = NULL; + + buf = gst_collect_pads_pop (mux->collect, data); + + /* Adjust timestamp with segment_start and preroll */ + if (buf) { + GST_BUFFER_TIMESTAMP (buf) -= data->segment.start; + } + + pad->buffer = buf; } - /* skip unusable pads */ - if (!GST_PAD_IS_USABLE (pad->pad)) - continue; - - /* we should have a buffer now, see if it is the best pad to + /* we should have a buffer now, see if it is the best stream to * pull on */ if (pad->buffer != NULL) { - if (gst_multipart_mux_compare_pads (multipart_mux, bestpad, pad) > 0) { + if (gst_multipart_mux_compare_pads (mux, bestpad, pad) > 0) { bestpad = pad; } } } + return bestpad; } @@ -455,75 +408,85 @@ gst_multipart_mux_queue_pads (GstMultipartMux * multipart_mux) * looking at the buffers to decide which one should be muxed first. * 2) push buffer on best pad, go to 1 */ -static void -gst_multipart_mux_loop (GstElement * element) +static GstFlowReturn +gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux) { - GstMultipartMux *mux; - GstMultipartPad *pad; - GstBuffer *newbuf, *buf; - gchar *header; - gint headerlen; - gint newlen; + GstMultipartPad *best; + GstFlowReturn ret = GST_FLOW_OK; + gchar *header = NULL; + size_t newlen, headerlen; + GstBuffer *newbuf = NULL; + GstStructure *structure = NULL; - mux = GST_MULTIPART_MUX (element); + GST_DEBUG_OBJECT (mux, "all pads are collected"); - /* we don't know which pad to pull on, find one */ - pad = gst_multipart_mux_queue_pads (mux); - if (pad == NULL) { - /* no pad to pull on, send EOS */ - if (GST_PAD_IS_USABLE (mux->srcpad)) - gst_pad_push (mux->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); - gst_element_set_eos (element); - return; + /* queue buffers on all pads; find a buffer with the lowest timestamp */ + best = gst_multipart_mux_queue_pads (mux); + if (best && !best->buffer) + goto beach; + + /* EOS */ + if (!best) { + GST_DEBUG_OBJECT (mux, "Pushing EOS"); + gst_pad_push_event (mux->srcpad, gst_event_new_eos ()); + ret = GST_FLOW_WRONG_STATE; + goto beach; } - /* now see if we have a buffer */ - buf = pad->buffer; - if (buf == NULL) { - /* no buffer, get one */ - buf = gst_multipart_mux_next_buffer (pad); - if (buf == NULL) { - /* data exhausted on this pad (EOS) */ - return; - } - } - - /* FIXME, negotiated is not set to FALSE properly after - * reconnect */ + /* If not negotiated yet set caps on src pad */ if (!mux->negotiated) { GstCaps *newcaps; newcaps = gst_caps_new_simple ("multipart/x-mixed-replace", "boundary", G_TYPE_STRING, mux->boundary, NULL); - if (GST_PAD_LINK_FAILED (gst_pad_try_set_caps (mux->srcpad, newcaps))) { + if (gst_pad_set_caps (mux->srcpad, newcaps)) { + mux->negotiated = TRUE; + } else { GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL)); - return; + ret = GST_FLOW_UNEXPECTED; + goto beach; } - mux->negotiated = TRUE; + } + + structure = gst_caps_get_structure (GST_BUFFER_CAPS (best->buffer), 0); + if (!structure) { + GST_WARNING_OBJECT (mux, "no caps on the incoming buffer %p", best->buffer); + goto beach; } header = g_strdup_printf ("\n--%s\nContent-type: %s\n\n", - mux->boundary, pad->mimetype); + mux->boundary, gst_structure_get_name (structure)); + headerlen = strlen (header); - newlen = headerlen + GST_BUFFER_SIZE (buf); - newbuf = gst_pad_alloc_buffer (mux->srcpad, GST_BUFFER_OFFSET_NONE, newlen); + newlen = headerlen + GST_BUFFER_SIZE (best->buffer); + + ret = gst_pad_alloc_buffer (mux->srcpad, GST_BUFFER_OFFSET_NONE, newlen, + GST_PAD_CAPS (mux->srcpad), &newbuf); + if (ret != GST_FLOW_OK) { + GST_WARNING_OBJECT (mux, "failed allocating a %d bytes buffer", newlen); + g_free (header); + goto beach; + } memcpy (GST_BUFFER_DATA (newbuf), header, headerlen); memcpy (GST_BUFFER_DATA (newbuf) + headerlen, - GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (buf); - GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf); + GST_BUFFER_DATA (best->buffer), GST_BUFFER_SIZE (best->buffer)); + + gst_buffer_stamp (newbuf, best->buffer); GST_BUFFER_OFFSET (newbuf) = mux->offset; g_free (header); mux->offset += newlen; - gst_pad_push (mux->srcpad, GST_DATA (newbuf)); + gst_pad_push (mux->srcpad, newbuf); - gst_buffer_unref (buf); - pad->buffer = NULL; + gst_buffer_unref (best->buffer); + best->buffer = NULL; + +beach: + return ret; } static void @@ -567,29 +530,37 @@ static GstStateChangeReturn gst_multipart_mux_change_state (GstElement * element, GstStateChange transition) { GstMultipartMux *multipart_mux; - - g_return_val_if_fail (GST_IS_MULTIPART_MUX (element), - GST_STATE_CHANGE_FAILURE); + GstStateChangeReturn ret; multipart_mux = GST_MULTIPART_MUX (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - case GST_STATE_CHANGE_READY_TO_PAUSED: - multipart_mux->offset = 0; multipart_mux->negotiated = FALSE; break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + case GST_STATE_CHANGE_READY_TO_PAUSED: + multipart_mux->offset = 0; + GST_DEBUG_OBJECT (multipart_mux, "starting collect pads"); + gst_collect_pads_start (multipart_mux->collect); + break; case GST_STATE_CHANGE_PAUSED_TO_READY: - case GST_STATE_CHANGE_READY_TO_NULL: + GST_DEBUG_OBJECT (multipart_mux, "stopping collect pads"); + gst_collect_pads_stop (multipart_mux->collect); + break; + default: break; } - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; - return GST_STATE_CHANGE_SUCCESS; + switch (transition) { + default: + break; + } + + return ret; } gboolean