mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-03 01:02:19 +00:00
Ported multipart mux/demux to 0.9.
Original commit message from CVS: 2005-11-30 Julien MOUTTE <julien@moutte.net> * 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.
This commit is contained in:
parent
4ad25ff08e
commit
f67f9e9203
6 changed files with 239 additions and 243 deletions
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
|||
2005-11-30 Julien MOUTTE <julien@moutte.net>
|
||||
|
||||
* 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 <thomas at apestaart dot org>
|
||||
|
||||
* gst/debug/gstnavigationtest.c: (gst_navigationtest_get_type):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <string.h>
|
||||
|
@ -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");
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstcollectpads.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
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 <wim@fluendo.com>");
|
||||
|
||||
/* 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
|
||||
|
|
Loading…
Reference in a new issue