From 1fa5624762c49261bc69dadc06486cac7f70233b Mon Sep 17 00:00:00 2001 From: Gil Pedersen Date: Thu, 12 Apr 2012 14:17:14 +0200 Subject: [PATCH] hlsdemux: port to 0.11 --- configure.ac | 2 +- gst-plugins-bad.spec.in | 2 +- gst/hls/gstfragment.c | 124 +++++++++++++------- gst/hls/gstfragment.h | 5 +- gst/hls/gsthlsdemux.c | 231 +++++++++++++++++-------------------- gst/hls/gsthlsdemux.h | 8 +- gst/hls/gsturidownloader.c | 54 +++++---- 7 files changed, 230 insertions(+), 196 deletions(-) diff --git a/configure.ac b/configure.ac index 447400ca48..ef884402ef 100644 --- a/configure.ac +++ b/configure.ac @@ -304,7 +304,7 @@ GST_PLUGINS_NONPORTED=" aiff asfmux \ camerabin cdxaparse coloreffects \ dccp faceoverlay festival \ fieldanalysis freeverb freeze frei0r gaudieffects \ - hdvparse hls id3tag inter interlace ivfparse jpegformat jp2kdecimator \ + hdvparse id3tag inter interlace ivfparse jpegformat jp2kdecimator \ kate liveadder legacyresample librfb mpegtsmux \ mpegpsmux mve mxf mythtv nsf nuvdemux \ patchdetect pnm real \ diff --git a/gst-plugins-bad.spec.in b/gst-plugins-bad.spec.in index 3fcf8f6c72..2964e00421 100644 --- a/gst-plugins-bad.spec.in +++ b/gst-plugins-bad.spec.in @@ -258,7 +258,7 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS='' # %{_libdir}/gstreamer-%{majorminor}/libgstdecklink.so %{_libdir}/gstreamer-%{majorminor}/libgstdvbsuboverlay.so # %{_libdir}/gstreamer-%{majorminor}/libgstfieldanalysis.so -# %{_libdir}/gstreamer-%{majorminor}/libgstfragmented.so +%{_libdir}/gstreamer-%{majorminor}/libgstfragmented.so # %{_libdir}/gstreamer-%{majorminor}/libgstinterlace.so # %{_libdir}/gstreamer-%{majorminor}/libgstjp2kdecimator.so # %{_libdir}/gstreamer-%{majorminor}/libgstlinsys.so diff --git a/gst/hls/gstfragment.c b/gst/hls/gstfragment.c index 00a3b4ce34..e21c14010b 100644 --- a/gst/hls/gstfragment.c +++ b/gst/hls/gstfragment.c @@ -20,6 +20,7 @@ */ #include +#include #include "gstfragmented.h" #include "gstfragment.h" @@ -34,15 +35,16 @@ enum PROP_NAME, PROP_DURATION, PROP_DISCONTINOUS, - PROP_BUFFER_LIST, + PROP_BUFFER, + PROP_CAPS, PROP_LAST }; struct _GstFragmentPrivate { - GstBufferList *buffer_list; - GstBufferListIterator *buffer_iterator; - gboolean headers_set; + GstBuffer *buffer; + GstCaps *caps; + GMutex lock; }; G_DEFINE_TYPE (GstFragment, gst_fragment, G_TYPE_OBJECT); @@ -50,6 +52,24 @@ G_DEFINE_TYPE (GstFragment, gst_fragment, G_TYPE_OBJECT); static void gst_fragment_dispose (GObject * object); static void gst_fragment_finalize (GObject * object); +static void +gst_fragment_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec) +{ + GstFragment *fragment = GST_FRAGMENT (object); + + switch (property_id) { + case PROP_CAPS: + gst_fragment_set_caps (fragment, g_value_get_boxed (value)); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + static void gst_fragment_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) @@ -73,8 +93,12 @@ gst_fragment_get_property (GObject * object, g_value_set_boolean (value, fragment->discontinuous); break; - case PROP_BUFFER_LIST: - g_value_set_object (value, gst_fragment_get_buffer_list (fragment)); + case PROP_BUFFER: + g_value_set_boxed (value, gst_fragment_get_buffer (fragment)); + break; + + case PROP_CAPS: + g_value_set_boxed (value, gst_fragment_get_caps (fragment)); break; default: @@ -84,6 +108,8 @@ gst_fragment_get_property (GObject * object, } } + + static void gst_fragment_class_init (GstFragmentClass * klass) { @@ -91,6 +117,7 @@ gst_fragment_class_init (GstFragmentClass * klass) g_type_class_add_private (klass, sizeof (GstFragmentPrivate)); + gobject_class->set_property = gst_fragment_set_property; gobject_class->get_property = gst_fragment_get_property; gobject_class->dispose = gst_fragment_dispose; gobject_class->finalize = gst_fragment_finalize; @@ -112,10 +139,15 @@ gst_fragment_class_init (GstFragmentClass * klass) g_param_spec_uint64 ("duration", "Fragment duration", "Duration of the fragment", 0, G_MAXUINT64, 0, G_PARAM_READABLE)); - g_object_class_install_property (gobject_class, PROP_BUFFER_LIST, - g_param_spec_object ("buffer-list", "Buffer List", - "A list with the fragment's buffers", GST_TYPE_FRAGMENT, - G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, PROP_BUFFER, + g_param_spec_boxed ("buffer", "Buffer", + "The fragment's buffer", GST_TYPE_BUFFER, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_CAPS, + g_param_spec_boxed ("caps", "Fragment caps", + "The caps of the fragment's buffer. (NULL = detect)", GST_TYPE_CAPS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -125,10 +157,8 @@ gst_fragment_init (GstFragment * fragment) fragment->priv = priv = GST_FRAGMENT_GET_PRIVATE (fragment); - priv->buffer_list = gst_buffer_list_new (); - priv->buffer_iterator = gst_buffer_list_iterate (priv->buffer_list); - gst_buffer_list_iterator_add_group (priv->buffer_iterator); - priv->headers_set = FALSE; + g_mutex_init (&fragment->priv->lock); + priv->buffer = NULL; fragment->download_start_time = g_get_real_time (); fragment->start_time = 0; fragment->stop_time = 0; @@ -150,6 +180,7 @@ gst_fragment_finalize (GObject * gobject) GstFragment *fragment = GST_FRAGMENT (gobject); g_free (fragment->name); + g_mutex_clear (&fragment->priv->lock); G_OBJECT_CLASS (gst_fragment_parent_class)->finalize (gobject); } @@ -159,45 +190,57 @@ gst_fragment_dispose (GObject * object) { GstFragmentPrivate *priv = GST_FRAGMENT (object)->priv; - if (priv->buffer_list != NULL) { - gst_buffer_list_iterator_free (priv->buffer_iterator); - gst_buffer_list_unref (priv->buffer_list); - priv->buffer_list = NULL; + if (priv->buffer != NULL) { + gst_buffer_unref (priv->buffer); + priv->buffer = NULL; + } + + if (priv->caps != NULL) { + gst_caps_unref (priv->caps); + priv->caps = NULL; } G_OBJECT_CLASS (gst_fragment_parent_class)->dispose (object); } -GstBufferList * -gst_fragment_get_buffer_list (GstFragment * fragment) +GstBuffer * +gst_fragment_get_buffer (GstFragment * fragment) { g_return_val_if_fail (fragment != NULL, NULL); if (!fragment->completed) return NULL; - gst_buffer_list_ref (fragment->priv->buffer_list); - return fragment->priv->buffer_list; + gst_buffer_ref (fragment->priv->buffer); + return fragment->priv->buffer; } -gboolean -gst_fragment_set_headers (GstFragment * fragment, GstBuffer ** buffer, - guint count) +void +gst_fragment_set_caps (GstFragment * fragment, GstCaps * caps) { - guint i; + g_return_if_fail (fragment != NULL); - g_return_val_if_fail (fragment != NULL, FALSE); - g_return_val_if_fail (buffer != NULL, FALSE); + g_mutex_lock (&fragment->priv->lock); + gst_caps_replace (&fragment->priv->caps, caps); + g_mutex_unlock (&fragment->priv->lock); +} - if (fragment->priv->headers_set) - return FALSE; +GstCaps * +gst_fragment_get_caps (GstFragment * fragment) +{ + g_return_val_if_fail (fragment != NULL, NULL); - for (i = 0; i < count; i++) { - /* We steal the buffers you pass in */ - gst_buffer_list_iterator_add (fragment->priv->buffer_iterator, buffer[i]); - gst_buffer_list_iterator_add_group (fragment->priv->buffer_iterator); - } - return TRUE; + if (!fragment->completed) + return NULL; + + g_mutex_lock (&fragment->priv->lock); + if (fragment->priv->caps == NULL) + fragment->priv->caps = + gst_type_find_helper_for_buffer (NULL, fragment->priv->buffer, NULL); + gst_caps_ref (fragment->priv->caps); + g_mutex_unlock (&fragment->priv->lock); + + return fragment->priv->caps; } gboolean @@ -211,12 +254,11 @@ gst_fragment_add_buffer (GstFragment * fragment, GstBuffer * buffer) return FALSE; } - /* if this is the first buffer forbid setting the headers anymore */ - if (G_UNLIKELY (fragment->priv->headers_set == FALSE)) - fragment->priv->headers_set = TRUE; - GST_DEBUG ("Adding new buffer to the fragment"); /* We steal the buffers you pass in */ - gst_buffer_list_iterator_add (fragment->priv->buffer_iterator, buffer); + if (fragment->priv->buffer == NULL) + fragment->priv->buffer = buffer; + else + fragment->priv->buffer = gst_buffer_append (fragment->priv->buffer, buffer); return TRUE; } diff --git a/gst/hls/gstfragment.h b/gst/hls/gstfragment.h index 9ea018606e..0cc905f3e8 100644 --- a/gst/hls/gstfragment.h +++ b/gst/hls/gstfragment.h @@ -60,8 +60,9 @@ struct _GstFragmentClass GType gst_fragment_get_type (void); -GstBufferList * gst_fragment_get_buffer_list (GstFragment *fragment); -gboolean gst_fragment_set_headers (GstFragment *fragment, GstBuffer **buffer, guint count); +GstBuffer * gst_fragment_get_buffer (GstFragment *fragment); +void gst_fragment_set_caps (GstFragment * fragment, GstCaps * caps); +GstCaps * gst_fragment_get_caps (GstFragment * fragment); gboolean gst_fragment_add_buffer (GstFragment *fragment, GstBuffer *buffer); GstFragment * gst_fragment_new (void); diff --git a/gst/hls/gsthlsdemux.c b/gst/hls/gsthlsdemux.c index ca3d64e05d..c09f075649 100644 --- a/gst/hls/gsthlsdemux.c +++ b/gst/hls/gsthlsdemux.c @@ -46,7 +46,6 @@ #define GLIB_DISABLE_DEPRECATION_WARNINGS #include -#include #include #include "gsthlsdemux.h" @@ -90,10 +89,14 @@ static GstStateChangeReturn gst_hls_demux_change_state (GstElement * element, GstStateChange transition); /* GstHLSDemux */ -static GstFlowReturn gst_hls_demux_chain (GstPad * pad, GstBuffer * buf); -static gboolean gst_hls_demux_sink_event (GstPad * pad, GstEvent * event); -static gboolean gst_hls_demux_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_hls_demux_src_query (GstPad * pad, GstQuery * query); +static GstFlowReturn gst_hls_demux_chain (GstPad * pad, GstObject * parent, + GstBuffer * buf); +static gboolean gst_hls_demux_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); +static gboolean gst_hls_demux_src_event (GstPad * pad, GstObject * parent, + GstEvent * event); +static gboolean gst_hls_demux_src_query (GstPad * pad, GstObject * parent, + GstQuery * query); static void gst_hls_demux_stream_loop (GstHLSDemux * demux); static void gst_hls_demux_updates_loop (GstHLSDemux * demux); static void gst_hls_demux_stop (GstHLSDemux * demux); @@ -108,34 +111,8 @@ static gboolean gst_hls_demux_set_location (GstHLSDemux * demux, const gchar * uri); static gchar *gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf); -static void -_do_init (GType type) -{ - GST_DEBUG_CATEGORY_INIT (gst_hls_demux_debug, "hlsdemux", 0, - "hlsdemux element"); -} - -GST_BOILERPLATE_FULL (GstHLSDemux, gst_hls_demux, GstElement, - GST_TYPE_ELEMENT, _do_init); - -static void -gst_hls_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 (&srctemplate)); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sinktemplate)); - - gst_element_class_set_details_simple (element_class, - "HLS Demuxer", - "Demuxer/URIList", - "HTTP Live Streaming demuxer", - "Marc-Andre Lureau \n" - "Andoni Morales Alastruey "); -} +#define gst_hls_demux_parent_class parent_class +G_DEFINE_TYPE (GstHLSDemux, gst_hls_demux, GST_TYPE_ELEMENT); static void gst_hls_demux_dispose (GObject * obj) @@ -149,7 +126,7 @@ gst_hls_demux_dispose (GObject * obj) gst_task_join (demux->stream_task); } gst_object_unref (demux->stream_task); - g_static_rec_mutex_free (&demux->stream_lock); + g_rec_mutex_clear (&demux->stream_lock); demux->stream_task = NULL; } @@ -160,8 +137,8 @@ gst_hls_demux_dispose (GObject * obj) gst_task_join (demux->updates_task); } gst_object_unref (demux->updates_task); - g_mutex_free (demux->updates_timed_lock); - g_static_rec_mutex_free (&demux->updates_lock); + g_mutex_clear (&demux->updates_timed_lock); + g_rec_mutex_clear (&demux->updates_lock); demux->updates_task = NULL; } @@ -181,10 +158,10 @@ static void gst_hls_demux_class_init (GstHLSDemuxClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; + GstElementClass *element_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; + element_class = (GstElementClass *) klass; gobject_class->set_property = gst_hls_demux_set_property; gobject_class->get_property = gst_hls_demux_get_property; @@ -204,12 +181,27 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass) 0, 1, DEFAULT_BITRATE_SWITCH_TOLERANCE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_hls_demux_change_state); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_hls_demux_change_state); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&srctemplate)); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sinktemplate)); + + gst_element_class_set_details_simple (element_class, + "HLS Demuxer", + "Demuxer/URIList", + "HTTP Live Streaming demuxer", + "Marc-Andre Lureau \n" + "Andoni Morales Alastruey "); + + GST_DEBUG_CATEGORY_INIT (gst_hls_demux_debug, "hlsdemux", 0, + "hlsdemux element"); } static void -gst_hls_demux_init (GstHLSDemux * demux, GstHLSDemuxClass * klass) +gst_hls_demux_init (GstHLSDemux * demux) { /* sink pad */ demux->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink"); @@ -231,16 +223,16 @@ gst_hls_demux_init (GstHLSDemux * demux, GstHLSDemuxClass * klass) demux->queue = g_queue_new (); /* Updates task */ - g_static_rec_mutex_init (&demux->updates_lock); + g_rec_mutex_init (&demux->updates_lock); demux->updates_task = - gst_task_create ((GstTaskFunction) gst_hls_demux_updates_loop, demux); + gst_task_new ((GstTaskFunction) gst_hls_demux_updates_loop, demux); gst_task_set_lock (demux->updates_task, &demux->updates_lock); - demux->updates_timed_lock = g_mutex_new (); + g_mutex_init (&demux->updates_timed_lock); /* Streaming task */ - g_static_rec_mutex_init (&demux->stream_lock); + g_rec_mutex_init (&demux->stream_lock); demux->stream_task = - gst_task_create ((GstTaskFunction) gst_hls_demux_stream_loop, demux); + gst_task_new ((GstTaskFunction) gst_hls_demux_stream_loop, demux); gst_task_set_lock (demux->stream_task, &demux->stream_lock); } @@ -323,11 +315,11 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition) } static gboolean -gst_hls_demux_src_event (GstPad * pad, GstEvent * event) +gst_hls_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstHLSDemux *demux; - demux = GST_HLS_DEMUX (gst_pad_get_element_private (pad)); + demux = GST_HLS_DEMUX (parent); switch (event->type) { case GST_EVENT_SEEK: @@ -393,12 +385,12 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event) gst_task_pause (demux->stream_task); /* wait for streaming to finish */ - g_static_rec_mutex_lock (&demux->stream_lock); + g_rec_mutex_lock (&demux->stream_lock); demux->need_cache = TRUE; while (!g_queue_is_empty (demux->queue)) { - GstBufferList *buf_list = g_queue_pop_head (demux->queue); - gst_buffer_list_unref (buf_list); + GstFragment *fragment = g_queue_pop_head (demux->queue); + g_object_unref (fragment); } g_queue_clear (demux->queue); @@ -413,12 +405,12 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event) if (flags & GST_SEEK_FLAG_FLUSH) { GST_DEBUG_OBJECT (demux, "sending flush stop"); - gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ()); + gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop (TRUE)); } demux->cancelled = FALSE; gst_task_start (demux->stream_task); - g_static_rec_mutex_unlock (&demux->stream_lock); + g_rec_mutex_unlock (&demux->stream_lock); return TRUE; } @@ -426,21 +418,22 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event) break; } - return gst_pad_event_default (pad, event); + return gst_pad_event_default (pad, parent, event); } static gboolean -gst_hls_demux_sink_event (GstPad * pad, GstEvent * event) +gst_hls_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { - GstHLSDemux *demux = GST_HLS_DEMUX (gst_pad_get_parent (pad)); + GstHLSDemux *demux; GstQuery *query; gboolean ret; gchar *uri; + demux = GST_HLS_DEMUX (parent); switch (event->type) { case GST_EVENT_EOS:{ - gchar *playlist; + gchar *playlist = NULL; if (demux->playlist == NULL) { GST_WARNING_OBJECT (demux, "Received EOS without a playlist."); @@ -483,7 +476,7 @@ gst_hls_demux_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); return TRUE; } - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: /* Swallow newsegments, we'll push our own */ gst_event_unref (event); return TRUE; @@ -491,11 +484,11 @@ gst_hls_demux_sink_event (GstPad * pad, GstEvent * event) break; } - return gst_pad_event_default (pad, event); + return gst_pad_event_default (pad, parent, event); } static gboolean -gst_hls_demux_src_query (GstPad * pad, GstQuery * query) +gst_hls_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstHLSDemux *hlsdemux; gboolean ret = FALSE; @@ -503,7 +496,7 @@ gst_hls_demux_src_query (GstPad * pad, GstQuery * query) if (query == NULL) return FALSE; - hlsdemux = GST_HLS_DEMUX (gst_pad_get_element_private (pad)); + hlsdemux = GST_HLS_DEMUX (parent); switch (query->type) { case GST_QUERY_DURATION:{ @@ -563,17 +556,15 @@ gst_hls_demux_src_query (GstPad * pad, GstQuery * query) } static GstFlowReturn -gst_hls_demux_chain (GstPad * pad, GstBuffer * buf) +gst_hls_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { - GstHLSDemux *demux = GST_HLS_DEMUX (gst_pad_get_parent (pad)); + GstHLSDemux *demux = GST_HLS_DEMUX (parent); if (demux->playlist == NULL) demux->playlist = buf; else demux->playlist = gst_buffer_append (demux->playlist, buf); - gst_object_unref (demux); - return GST_FLOW_OK; } @@ -600,18 +591,6 @@ switch_pads (GstHLSDemux * demux, GstCaps * newcaps) GST_DEBUG ("Switching pads (oldpad:%p) with caps: %" GST_PTR_FORMAT, oldpad, newcaps); - /* FIXME: This is a workaround for a bug in playsink. - * If we're switching from an audio-only or video-only fragment - * to an audio-video segment, the new sink doesn't know about - * the current running time and audio/video will go out of sync. - * - * This should be fixed in playsink by distributing the - * current running time to newly created sinks and is - * fixed in 0.11 with the new segments. - */ - if (demux->srcpad) - gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ()); - /* First create and activate new pad */ demux->srcpad = gst_pad_new_from_static_template (&srctemplate, NULL); gst_pad_set_event_function (demux->srcpad, @@ -620,7 +599,9 @@ switch_pads (GstHLSDemux * demux, GstCaps * newcaps) GST_DEBUG_FUNCPTR (gst_hls_demux_src_query)); gst_pad_set_element_private (demux->srcpad, demux); gst_pad_set_active (demux->srcpad, TRUE); + gst_pad_push_event (demux->srcpad, gst_event_new_stream_start ()); gst_pad_set_caps (demux->srcpad, newcaps); + gst_pad_push_event (demux->srcpad, gst_event_new_caps (newcaps)); gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad); gst_element_no_more_pads (GST_ELEMENT (demux)); @@ -636,9 +617,10 @@ switch_pads (GstHLSDemux * demux, GstCaps * newcaps) static void gst_hls_demux_stream_loop (GstHLSDemux * demux) { - GstBufferList *buffer_list; + GstFragment *fragment; GstBuffer *buf; GstFlowReturn ret; + GstCaps *bufcaps, *srccaps = NULL; /* Loop for the source pad task. The task is started when we have * received the main playlist from the source element. It tries first to @@ -663,24 +645,33 @@ gst_hls_demux_stream_loop (GstHLSDemux * demux) goto pause_task; } - buffer_list = g_queue_pop_head (demux->queue); - /* Work with the first buffer of the list */ - buf = gst_buffer_list_get (buffer_list, 0, 0); + fragment = g_queue_pop_head (demux->queue); + buf = gst_fragment_get_buffer (fragment); + /* Figure out if we need to create/switch pads */ - if (G_UNLIKELY (!demux->srcpad - || GST_BUFFER_CAPS (buf) != GST_PAD_CAPS (demux->srcpad) + if (G_LIKELY (demux->srcpad)) + srccaps = gst_pad_get_current_caps (demux->srcpad); + bufcaps = gst_fragment_get_caps (fragment); + if (G_UNLIKELY (!srccaps || !gst_caps_is_equal_fixed (bufcaps, srccaps) || demux->need_segment)) { - switch_pads (demux, GST_BUFFER_CAPS (buf)); + switch_pads (demux, bufcaps); demux->need_segment = TRUE; } + gst_caps_unref (bufcaps); + if (G_LIKELY (srccaps)) + gst_caps_unref (srccaps); + g_object_unref (fragment); + if (demux->need_segment) { GstClockTime start = demux->position + demux->position_shift; + GstSegment segment; /* And send a newsegment */ GST_DEBUG_OBJECT (demux, "Sending new-segment. segment start:%" GST_TIME_FORMAT, GST_TIME_ARGS (start)); - gst_pad_push_event (demux->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, - start, GST_CLOCK_TIME_NONE, start)); + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = start; + segment.time = start; + gst_pad_push_event (demux->srcpad, gst_event_new_segment (&segment)); demux->need_segment = FALSE; demux->position_shift = 0; } @@ -688,7 +679,7 @@ gst_hls_demux_stream_loop (GstHLSDemux * demux) if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buf))) demux->position += GST_BUFFER_DURATION (buf); - ret = gst_pad_push_list (demux->srcpad, buffer_list); + ret = gst_pad_push (demux->srcpad, buf); if (ret != GST_FLOW_OK) goto error_pushing; @@ -758,8 +749,8 @@ gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose) } while (!g_queue_is_empty (demux->queue)) { - GstBufferList *buffer_list = g_queue_pop_head (demux->queue); - gst_buffer_list_unref (buffer_list); + GstFragment *fragment = g_queue_pop_head (demux->queue); + g_object_unref (fragment); } g_queue_clear (demux->queue); @@ -788,11 +779,11 @@ gst_hls_demux_updates_loop (GstHLSDemux * demux) * switch to a different bitrate */ /* block until the next scheduled update or the signal to quit this thread */ - g_mutex_lock (demux->updates_timed_lock); + g_mutex_lock (&demux->updates_timed_lock); GST_DEBUG_OBJECT (demux, "Started updates task"); while (TRUE) { if (g_cond_timed_wait (GST_TASK_GET_COND (demux->updates_task), - demux->updates_timed_lock, &demux->next_update)) { + &demux->updates_timed_lock, &demux->next_update)) { goto quit; } /* update the playlist for live sources */ @@ -852,7 +843,7 @@ quit: { GST_DEBUG_OBJECT (demux, "Stopped updates task"); gst_hls_demux_stop (demux); - g_mutex_unlock (demux->updates_timed_lock); + g_mutex_unlock (&demux->updates_timed_lock); } } @@ -933,29 +924,33 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux) static gchar * gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf) { - gint size; - gchar *data; + GstMapInfo info; gchar *playlist; - data = (gchar *) GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - if (!g_utf8_validate (data, size, NULL)) + if (!gst_buffer_map (buf, &info, GST_MAP_READ)) return NULL; - /* alloc size + 1 to end with a null character */ - playlist = g_malloc0 (size + 1); - memcpy (playlist, data, size + 1); + if (!g_utf8_validate ((gchar *) info.data, info.size, NULL)) + goto validate_error; + /* alloc size + 1 to end with a null character */ + playlist = g_malloc0 (info.size + 1); + memcpy (playlist, info.data, info.size + 1); + + gst_buffer_unmap (buf, &info); gst_buffer_unref (buf); return playlist; + +validate_error: + gst_buffer_unmap (buf, &info); + gst_buffer_unref (buf); + return NULL; } static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux) { GstFragment *download; - GstBufferListIterator *it; GstBuffer *buf; gchar *playlist; @@ -966,17 +961,8 @@ gst_hls_demux_update_playlist (GstHLSDemux * demux) if (download == NULL) return FALSE; - /* Merge all the buffers in the list to build a unique buffer with the - * playlist */ - it = gst_buffer_list_iterate (gst_fragment_get_buffer_list (download)); - - /* skip the first group, which contains the headers, which are not set in the - * demuxer*/ - gst_buffer_list_iterator_next_group (it); - buf = gst_buffer_list_iterator_merge_group (it); - + buf = gst_fragment_get_buffer (download); playlist = gst_hls_src_buf_to_utf8_playlist (buf); - gst_buffer_list_iterator_free (it); g_object_unref (download); if (playlist == NULL) { @@ -1112,7 +1098,6 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean caching) const gchar *next_fragment_uri; GstClockTime duration; GstClockTime timestamp; - GstBufferList *buffer_list; GstBuffer *buf; gboolean discont; @@ -1132,14 +1117,13 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean caching) if (download == NULL) goto error; - buffer_list = gst_fragment_get_buffer_list (download); - buf = gst_buffer_list_get (buffer_list, 0, 0); + buf = gst_fragment_get_buffer (download); GST_BUFFER_DURATION (buf) = duration; - GST_BUFFER_TIMESTAMP (buf) = timestamp; + GST_BUFFER_PTS (buf) = timestamp; /* We actually need to do this every time we switch bitrate */ if (G_UNLIKELY (demux->do_typefind)) { - GstCaps *caps = gst_type_find_helper_for_buffer (NULL, buf, NULL); + GstCaps *caps = gst_fragment_get_caps (download); if (!demux->input_caps || !gst_caps_is_equal (caps, demux->input_caps)) { gst_caps_replace (&demux->input_caps, caps); @@ -1147,22 +1131,21 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean caching) GST_INFO_OBJECT (demux, "Input source caps: %" GST_PTR_FORMAT, demux->input_caps); demux->do_typefind = FALSE; - } else - gst_caps_unref (caps); + } + gst_caps_unref (caps); + } else { + gst_fragment_set_caps (download, demux->input_caps); } - gst_buffer_set_caps (buf, demux->input_caps); if (discont) { GST_DEBUG_OBJECT (demux, "Marking fragment as discontinuous"); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); } - g_queue_push_tail (demux->queue, buffer_list); - g_object_unref (download); + g_queue_push_tail (demux->queue, download); if (!caching) { GST_TASK_SIGNAL (demux->updates_task); } - return TRUE; error: diff --git a/gst/hls/gsthlsdemux.h b/gst/hls/gsthlsdemux.h index 16c86775ea..28470f88a9 100644 --- a/gst/hls/gsthlsdemux.h +++ b/gst/hls/gsthlsdemux.h @@ -41,6 +41,8 @@ G_BEGIN_DECLS (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HLS_DEMUX)) #define GST_IS_HLS_DEMUX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HLS_DEMUX)) +#define GST_HLS_DEMUX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_HLS_DEMUX,GstHLSDemuxClass)) typedef struct _GstHLSDemux GstHLSDemux; typedef struct _GstHLSDemuxClass GstHLSDemuxClass; @@ -71,13 +73,13 @@ struct _GstHLSDemux /* Streaming task */ GstTask *stream_task; - GStaticRecMutex stream_lock; + GRecMutex stream_lock; gboolean stop_stream_task; /* Updates task */ GstTask *updates_task; - GStaticRecMutex updates_lock; - GMutex *updates_timed_lock; + GRecMutex updates_lock; + GMutex updates_timed_lock; GTimeVal next_update; /* Time of the next update */ gint64 accumulated_delay; /* Delay accumulated fetching fragments, used to decide a playlist switch */ gboolean cancelled; diff --git a/gst/hls/gsturidownloader.c b/gst/hls/gsturidownloader.c index e208efe155..6cf34cb0dd 100644 --- a/gst/hls/gsturidownloader.c +++ b/gst/hls/gsturidownloader.c @@ -39,15 +39,17 @@ struct _GstUriDownloaderPrivate GstPad *pad; GTimeVal *timeout; GstFragment *download; - GMutex *lock; - GCond *cond; + GMutex lock; + GCond cond; }; static void gst_uri_downloader_finalize (GObject * object); static void gst_uri_downloader_dispose (GObject * object); -static GstFlowReturn gst_uri_downloader_chain (GstPad * pad, GstBuffer * buf); -static gboolean gst_uri_downloader_sink_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_uri_downloader_chain (GstPad * pad, GstObject * parent, + GstBuffer * buf); +static gboolean gst_uri_downloader_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); static GstBusSyncReply gst_uri_downloader_bus_handler (GstBus * bus, GstMessage * message, gpointer data); @@ -91,13 +93,13 @@ gst_uri_downloader_init (GstUriDownloader * downloader) gst_pad_set_event_function (downloader->priv->pad, GST_DEBUG_FUNCPTR (gst_uri_downloader_sink_event)); gst_pad_set_element_private (downloader->priv->pad, downloader); - gst_pad_activate_push (downloader->priv->pad, TRUE); + gst_pad_set_active (downloader->priv->pad, TRUE); /* Create a bus to handle error and warning message from the source element */ downloader->priv->bus = gst_bus_new (); - downloader->priv->lock = g_mutex_new (); - downloader->priv->cond = g_cond_new (); + g_mutex_init (&downloader->priv->lock); + g_cond_init (&downloader->priv->cond); } static void @@ -133,8 +135,8 @@ gst_uri_downloader_finalize (GObject * object) { GstUriDownloader *downloader = GST_URI_DOWNLOADER (object); - g_mutex_free (downloader->priv->lock); - g_cond_free (downloader->priv->cond); + g_mutex_clear (&downloader->priv->lock); + g_cond_clear (&downloader->priv->cond); G_OBJECT_CLASS (gst_uri_downloader_parent_class)->finalize (object); } @@ -146,10 +148,13 @@ gst_uri_downloader_new (void) } static gboolean -gst_uri_downloader_sink_event (GstPad * pad, GstEvent * event) +gst_uri_downloader_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event) { - GstUriDownloader *downloader = - (GstUriDownloader *) (gst_pad_get_element_private (pad)); + gboolean ret = FALSE; + GstUriDownloader *downloader; + + downloader = GST_URI_DOWNLOADER (gst_pad_get_element_private (pad)); switch (event->type) { case GST_EVENT_EOS:{ @@ -161,19 +166,19 @@ gst_uri_downloader_sink_event (GstPad * pad, GstEvent * event) downloader->priv->download->download_stop_time = g_get_real_time (); GST_OBJECT_UNLOCK (downloader); GST_DEBUG_OBJECT (downloader, "Signaling chain funtion"); - g_cond_signal (downloader->priv->cond); - + g_cond_signal (&downloader->priv->cond); } else { GST_OBJECT_UNLOCK (downloader); } + gst_event_unref (event); break; } default: + ret = gst_pad_event_default (pad, parent, event); break; } - gst_event_unref (event); - return FALSE; + return ret; } static GstBusSyncReply @@ -205,10 +210,11 @@ gst_uri_downloader_bus_handler (GstBus * bus, } static GstFlowReturn -gst_uri_downloader_chain (GstPad * pad, GstBuffer * buf) +gst_uri_downloader_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { - GstUriDownloader *downloader = - (GstUriDownloader *) gst_pad_get_element_private (pad); + GstUriDownloader *downloader; + + downloader = GST_URI_DOWNLOADER (gst_pad_get_element_private (pad)); /* HTML errors (404, 500, etc...) are also pushed through this pad as * response but the source element will also post a warning or error message @@ -222,7 +228,7 @@ gst_uri_downloader_chain (GstPad * pad, GstBuffer * buf) } GST_LOG_OBJECT (downloader, "The uri fetcher received a new buffer " - "of size %u", GST_BUFFER_SIZE (buf)); + "of size %u", gst_buffer_get_size (buf)); if (!gst_fragment_add_buffer (downloader->priv->download, buf)) GST_WARNING_OBJECT (downloader, "Could not add buffer to fragment"); GST_OBJECT_UNLOCK (downloader); @@ -264,7 +270,7 @@ gst_uri_downloader_cancel (GstUriDownloader * downloader) downloader->priv->download = NULL; GST_OBJECT_UNLOCK (downloader); GST_DEBUG_OBJECT (downloader, "Signaling chain funtion"); - g_cond_signal (downloader->priv->cond); + g_cond_signal (&downloader->priv->cond); } else { GST_OBJECT_UNLOCK (downloader); GST_DEBUG_OBJECT (downloader, @@ -305,7 +311,7 @@ gst_uri_downloader_fetch_uri (GstUriDownloader * downloader, const gchar * uri) GstStateChangeReturn ret; GstFragment *download = NULL; - g_mutex_lock (downloader->priv->lock); + g_mutex_lock (&downloader->priv->lock); if (!gst_uri_downloader_set_uri (downloader, uri)) { goto quit; @@ -326,7 +332,7 @@ gst_uri_downloader_fetch_uri (GstUriDownloader * downloader, const gchar * uri) * - the download was canceled */ GST_DEBUG_OBJECT (downloader, "Waiting to fetch the URI"); - g_cond_wait (downloader->priv->cond, downloader->priv->lock); + g_cond_wait (&downloader->priv->cond, &downloader->priv->lock); GST_OBJECT_LOCK (downloader); download = downloader->priv->download; @@ -341,7 +347,7 @@ gst_uri_downloader_fetch_uri (GstUriDownloader * downloader, const gchar * uri) quit: { gst_uri_downloader_stop (downloader); - g_mutex_unlock (downloader->priv->lock); + g_mutex_unlock (&downloader->priv->lock); return download; } }