X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Frtsp-server%2Frtsp-media.c;h=345559d7c3c9993225a111ef714c47d8e6956632;hb=e16867b1618460452d0a637b2ba64e6d88e0c7c9;hp=bd3fcaab91cb8ccb4053ad6d25ec13373f43bced;hpb=ab37286300baac65e6ccfca2101007a00a49a292;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index bd3fcaa..345559d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -152,6 +152,7 @@ struct _GstRTSPMediaPrivate /* Dynamic element handling */ guint nb_dynamic_elements; guint no_more_pads_pending; + gboolean expected_async_done; }; #define DEFAULT_SHARED FALSE @@ -235,7 +236,7 @@ static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); static gboolean wait_preroll (GstRTSPMedia * media); -static GstElement *find_payload_element (GstElement * payloader); +static GstElement *find_payload_element (GstElement * payloader, GstPad * pad); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -243,6 +244,8 @@ static gboolean check_complete (GstRTSPMedia * media); #define C_ENUM(v) ((gint) v) +#define TRICKMODE_FLAGS (GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_TRICKMODE_KEY_UNITS | GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED) + GType gst_rtsp_suspend_mode_get_type (void) { @@ -474,6 +477,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; + priv->expected_async_done = FALSE; } static void @@ -2046,7 +2050,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) pad = gst_element_get_static_pad (elem, "src"); /* find the real payload element in case elem is a GstBin */ - pay = find_payload_element (elem); + pay = find_payload_element (elem, pad); /* create the stream */ if (pay == NULL) { @@ -2213,7 +2217,8 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_mutex_lock (&priv->lock); idx = priv->streams->len; - GST_DEBUG ("media %p: creating stream with index %d", media, idx); + GST_DEBUG ("media %p: creating stream with index %d and payloader %" + GST_PTR_FORMAT, media, idx, payloader); if (GST_PAD_IS_SRC (pad)) name = g_strdup_printf ("src_%u", idx); @@ -2559,7 +2564,10 @@ gst_rtsp_media_get_rates (GstRTSPMedia * media, gdouble * rate, { GstRTSPMediaPrivate *priv; GstRTSPStream *stream; + gdouble save_rate, save_applied_rate; gboolean result = TRUE; + gboolean first_stream = TRUE; + gint i; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); @@ -2573,11 +2581,34 @@ gst_rtsp_media_get_rates (GstRTSPMedia * media, gdouble * rate, g_mutex_lock (&priv->lock); g_assert (priv->streams->len > 0); - stream = g_ptr_array_index (priv->streams, 0); - if (!gst_rtsp_stream_get_rates (stream, rate, applied_rate)) { + for (i = 0; i < priv->streams->len; i++) { + stream = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_is_complete (stream)) { + if (gst_rtsp_stream_get_rates (stream, rate, applied_rate)) { + if (first_stream) { + save_rate = *rate; + save_applied_rate = *applied_rate; + first_stream = FALSE; + } else { + if (save_rate != *rate || save_applied_rate != *applied_rate) { + /* diffrent rate or applied_rate, weird */ + g_assert (FALSE); + result = FALSE; + break; + } + } + } else { + /* complete stream withot rate and applied_rate, weird */ + g_assert (FALSE); + result = FALSE; + break; + } + } + } + + if (!result) { GST_WARNING_OBJECT (media, - "failed to obtain rate and applied_rate from first stream"); - result = FALSE; + "failed to obtain consistent rate and applied_rate"); } g_mutex_unlock (&priv->lock); @@ -2604,15 +2635,15 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) static void stream_unblock (GstRTSPStream * stream, GstRTSPMedia * media) { - gst_rtsp_stream_unblock_linked (stream); + gst_rtsp_stream_set_blocked (stream, FALSE); } static void -media_unblock_linked (GstRTSPMedia * media) +media_unblock (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - GST_DEBUG ("media %p unblocking linked streams", media); + GST_DEBUG ("media %p unblocking streams", media); /* media is not blocked any longer, as it contains active streams, * streams that are complete */ priv->blocked = FALSE; @@ -2756,13 +2787,11 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, if (stop != GST_CLOCK_TIME_NONE) stop_type = GST_SEEK_TYPE_SET; - /* we force a seek if any seek flag is set, or if the the rate + /* we force a seek if any trickmode flag is set, or if the rate * is non-standard, i.e. not 1.0 */ - force_seek = flags != GST_SEEK_FLAG_NONE || rate != 1.0; + force_seek = (flags & TRICKMODE_FLAGS) || rate != 1.0; if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE || force_seek) { - gboolean had_flags = flags != GST_SEEK_FLAG_NONE; - GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); @@ -2781,14 +2810,7 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, GST_TIME_ARGS (current_position)); start = current_position; start_type = GST_SEEK_TYPE_SET; - if (!had_flags) - flags |= GST_SEEK_FLAG_ACCURATE; } - } else { - /* only set keyframe flag when modifying start */ - if (start_type != GST_SEEK_TYPE_NONE) - if (!had_flags) - flags |= GST_SEEK_FLAG_KEY_UNIT; } if (start == current_position && stop_type == GST_SEEK_TYPE_NONE && @@ -2799,6 +2821,30 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, GstEvent *seek_event; gboolean unblock = FALSE; + /* Handle expected async-done before waiting on next async-done. + * + * Since the seek further down in code will cause a preroll and + * a async-done will be generated it's important to wait on async-done + * if that is expected. Otherwise there is the risk that the waiting + * for async-done after the seek is detecting the expected async-done + * instead of the one that corresponds to the seek. Then execution + * continue and act as if the pipeline is prerolled, but it's not. + * + * During wait_preroll message GST_MESSAGE_ASYNC_DONE will come + * and then the state will change from preparing to prepared */ + if (priv->expected_async_done) { + GST_DEBUG (" expected to get async-done, waiting "); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + g_rec_mutex_unlock (&priv->state_lock); + + /* wait until pipeline is prerolled */ + if (!wait_preroll (media)) + goto preroll_failed_expected_async_done; + + g_rec_mutex_lock (&priv->state_lock); + GST_DEBUG (" got expected async-done"); + } + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); if (rate < 0.0) { @@ -2890,6 +2936,11 @@ preroll_failed: GST_WARNING ("failed to preroll after seek"); return FALSE; } +preroll_failed_expected_async_done: + { + GST_WARNING ("failed to preroll"); + return FALSE; + } } /** @@ -2902,6 +2953,7 @@ preroll_failed: * @media must be prepared with gst_rtsp_media_prepare(). * * Returns: %TRUE on success. + * Since: 1.18 */ gboolean gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, @@ -3097,6 +3149,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: + if (priv->expected_async_done) + priv->expected_async_done = FALSE; if (priv->complete) { /* receive the final ASYNC_DONE, that is posted by the media pipeline * after all the transport parts have been successfully added to @@ -3148,27 +3202,57 @@ watch_destroyed (GstRTSPMedia * media) g_object_unref (media); } +static gboolean +is_payloader (GstElement * element) +{ + GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element); + const gchar *klass; + + klass = gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS); + if (klass == NULL) + return FALSE; + + if (strstr (klass, "Payloader") && strstr (klass, "RTP")) { + return TRUE; + } + + return FALSE; +} + static GstElement * -find_payload_element (GstElement * payloader) +find_payload_element (GstElement * payloader, GstPad * pad) { GstElement *pay = NULL; if (GST_IS_BIN (payloader)) { GstIterator *iter; GValue item = { 0 }; + gchar *pad_name, *payloader_name; + GstElement *element; + + if ((element = gst_bin_get_by_name (GST_BIN (payloader), "pay"))) { + if (is_payloader (element)) + return element; + gst_object_unref (element); + } + + pad_name = gst_object_get_name (GST_OBJECT (pad)); + payloader_name = g_strdup_printf ("pay_%s", pad_name); + g_free (pad_name); + if ((element = gst_bin_get_by_name (GST_BIN (payloader), payloader_name))) { + g_free (payloader_name); + if (is_payloader (element)) + return element; + gst_object_unref (element); + } else { + g_free (payloader_name); + } iter = gst_bin_iterate_recurse (GST_BIN (payloader)); while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) { - GstElement *element = (GstElement *) g_value_get_object (&item); - GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element); - const gchar *klass; + element = (GstElement *) g_value_get_object (&item); - klass = - gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS); - if (klass == NULL) - continue; - - if (strstr (klass, "Payloader") && strstr (klass, "RTP")) { + if (is_payloader (element)) { pay = gst_object_ref (element); g_value_unset (&item); break; @@ -3192,7 +3276,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) GstElement *pay; /* find the real payload element */ - pay = find_payload_element (element); + pay = find_payload_element (element, pad); stream = gst_rtsp_media_create_stream (media, pay, pad); gst_object_unref (pay); @@ -4309,8 +4393,8 @@ default_unsuspend (GstRTSPMedia * media) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); /* at this point the media pipeline has been updated and contain all * specific transport parts: all active streams contain at least one sink - * element and it's safe to unblock any blocked streams that are active */ - media_unblock_linked (media); + * element and it's safe to unblock all blocked streams */ + media_unblock (media); } else { /* streams are not blocked and media is suspended from PAUSED */ gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -4330,8 +4414,8 @@ default_unsuspend (GstRTSPMedia * media) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); /* at this point the media pipeline has been updated and contain all * specific transport parts: all active streams contain at least one sink - * element and it's safe to unblock any blocked streams that are active */ - media_unblock_linked (media); + * element and it's safe to unblock all blocked streams */ + media_unblock (media); if (!start_preroll (media)) goto start_failed; @@ -4408,6 +4492,8 @@ static void media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) { GstRTSPMediaPrivate *priv = media->priv; + GstStateChangeReturn set_state_ret; + priv->expected_async_done = FALSE; if (state == GST_STATE_NULL) { gst_rtsp_media_unprepare (media); @@ -4421,13 +4507,17 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) } else { if (state == GST_STATE_PLAYING) /* make sure pads are not blocking anymore when going to PLAYING */ - media_unblock_linked (media); - - set_state (media, state); + media_unblock (media); - /* and suspend after pause */ - if (state == GST_STATE_PAUSED) + if (state == GST_STATE_PAUSED) { + set_state_ret = set_state (media, state); + if (set_state_ret == GST_STATE_CHANGE_ASYNC) + priv->expected_async_done = TRUE; + /* and suspend after pause */ gst_rtsp_media_suspend (media); + } else { + set_state (media, state); + } } } } @@ -4757,6 +4847,36 @@ gst_rtsp_media_is_receive_only (GstRTSPMedia * media) } /** + * gst_rtsp_media_has_completed_sender: + * + * See gst_rtsp_stream_is_complete(), gst_rtsp_stream_is_sender(). + * + * Returns: whether @media has at least one complete sender stream. + * Since: 1.18 + */ +gboolean +gst_rtsp_media_has_completed_sender (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + gboolean sender = FALSE; + guint i; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_is_complete (stream)) + if (gst_rtsp_stream_is_sender (stream) || + !gst_rtsp_stream_is_receiver (stream)) { + sender = TRUE; + break; + } + } + g_mutex_unlock (&priv->lock); + + return sender; +} + +/** * gst_rtsp_media_set_rate_control: * * Define whether @media will follow the Rate-Control=no behaviour as specified