mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-14 03:15:47 +00:00
rtsp-media: allow specifying rate when seeking
Add new function gst_rtsp_media_seek_full_with_rate() which allows the caller to specify the rate for the seek. Also added functions in rtsp-stream and rtsp-media for retreiving current rate and applied rate. https://bugzilla.gnome.org/show_bug.cgi?id=754575
This commit is contained in:
parent
e788fc4e88
commit
421ac85150
5 changed files with 209 additions and 32 deletions
|
@ -50,7 +50,8 @@
|
||||||
* #GstRTSPSession and #GstRTSPSessionMedia.
|
* #GstRTSPSession and #GstRTSPSessionMedia.
|
||||||
*
|
*
|
||||||
* The state of the media can be controlled with gst_rtsp_media_set_state ().
|
* The state of the media can be controlled with gst_rtsp_media_set_state ().
|
||||||
* Seeking can be done with gst_rtsp_media_seek().
|
* Seeking can be done with gst_rtsp_media_seek(), or gst_rtsp_media_seek_full()
|
||||||
|
* or gst_rtsp_media_seek_full_with_rate() for finer control of the seek.
|
||||||
*
|
*
|
||||||
* With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
|
* With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
|
||||||
* gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
|
* gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
|
||||||
|
@ -2554,6 +2555,51 @@ conversion_failed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_get_rates:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
* @rate (allow-none): the rate of the current segment
|
||||||
|
* @applied_rate (allow-none): the applied_rate of the current segment
|
||||||
|
*
|
||||||
|
* Get the rate and applied_rate of the current segment.
|
||||||
|
*
|
||||||
|
* Returns: %FALSE if looking up the rate and applied rate failed. Otherwise
|
||||||
|
* %TRUE is returned and @rate and @applied_rate are set to the rate and
|
||||||
|
* applied_rate of the current segment.
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_rtsp_media_get_rates (GstRTSPMedia * media, gdouble * rate,
|
||||||
|
gdouble * applied_rate)
|
||||||
|
{
|
||||||
|
GstRTSPMediaPrivate *priv;
|
||||||
|
GstRTSPStream *stream;
|
||||||
|
gboolean result = TRUE;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
|
||||||
|
|
||||||
|
if (!rate && !applied_rate) {
|
||||||
|
GST_WARNING_OBJECT (media, "rate and applied_rate are both NULL");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = media->priv;
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
GST_WARNING_OBJECT (media,
|
||||||
|
"failed to obtain rate and applied_rate from first stream");
|
||||||
|
result = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media)
|
stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media)
|
||||||
{
|
{
|
||||||
|
@ -2635,22 +2681,24 @@ gst_rtsp_media_get_status (GstRTSPMedia * media)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_seek_full:
|
* gst_rtsp_media_seek_full_with_rate:
|
||||||
* @media: a #GstRTSPMedia
|
* @media: a #GstRTSPMedia
|
||||||
* @range: (transfer none): a #GstRTSPTimeRange
|
* @range: (transfer none): a #GstRTSPTimeRange
|
||||||
* @flags: The minimal set of #GstSeekFlags to use
|
* @flags: The minimal set of #GstSeekFlags to use
|
||||||
|
* @rate: the rate to use in the seek
|
||||||
*
|
*
|
||||||
* Seek the pipeline of @media to @range. @media must be prepared with
|
* Seek the pipeline of @media to @range with the given @flags and @rate.
|
||||||
* gst_rtsp_media_prepare(). In order to perform the seek operation,
|
* @media must be prepared with gst_rtsp_media_prepare().
|
||||||
* the pipeline must contain all needed transport parts (transport sinks).
|
* In order to perform the seek operation, the pipeline must contain all
|
||||||
|
* needed transport parts (transport sinks).
|
||||||
*
|
*
|
||||||
* Returns: %TRUE on success.
|
* Returns: %TRUE on success.
|
||||||
*
|
*
|
||||||
* Since: 1.14
|
* Since: 1.18
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media,
|
||||||
GstSeekFlags flags)
|
GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate)
|
||||||
{
|
{
|
||||||
GstRTSPMediaClass *klass;
|
GstRTSPMediaClass *klass;
|
||||||
GstRTSPMediaPrivate *priv;
|
GstRTSPMediaPrivate *priv;
|
||||||
|
@ -2658,12 +2706,15 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
GstClockTime start, stop;
|
GstClockTime start, stop;
|
||||||
GstSeekType start_type, stop_type;
|
GstSeekType start_type, stop_type;
|
||||||
gint64 current_position;
|
gint64 current_position;
|
||||||
|
gboolean force_seek;
|
||||||
|
|
||||||
klass = GST_RTSP_MEDIA_GET_CLASS (media);
|
klass = GST_RTSP_MEDIA_GET_CLASS (media);
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
|
||||||
g_return_val_if_fail (range != NULL, FALSE);
|
/* if there's a range then klass->convert_range must be set */
|
||||||
g_return_val_if_fail (klass->convert_range != NULL, FALSE);
|
g_return_val_if_fail (range == NULL || klass->convert_range != NULL, FALSE);
|
||||||
|
|
||||||
|
GST_DEBUG ("flags=%x rate=%f", flags, rate);
|
||||||
|
|
||||||
priv = media->priv;
|
priv = media->priv;
|
||||||
|
|
||||||
|
@ -2689,7 +2740,12 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
}
|
}
|
||||||
|
|
||||||
start_type = stop_type = GST_SEEK_TYPE_NONE;
|
start_type = stop_type = GST_SEEK_TYPE_NONE;
|
||||||
|
start = stop = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
/* if caller provided a range convert it to NPT format
|
||||||
|
* if no range provided the seek is assumed to be the same position but with
|
||||||
|
* e.g. the rate changed */
|
||||||
|
if (range != NULL) {
|
||||||
if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT))
|
if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT))
|
||||||
goto not_supported;
|
goto not_supported;
|
||||||
gst_rtsp_range_get_times (range, &start, &stop);
|
gst_rtsp_range_get_times (range, &start, &stop);
|
||||||
|
@ -2698,6 +2754,7 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
|
GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
|
||||||
GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
|
GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
|
GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
|
||||||
|
}
|
||||||
|
|
||||||
current_position = -1;
|
current_position = -1;
|
||||||
if (klass->query_position)
|
if (klass->query_position)
|
||||||
|
@ -2713,24 +2770,24 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
else if (stop != GST_CLOCK_TIME_NONE)
|
else if (stop != GST_CLOCK_TIME_NONE)
|
||||||
stop_type = GST_SEEK_TYPE_SET;
|
stop_type = GST_SEEK_TYPE_SET;
|
||||||
|
|
||||||
if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
|
/* we force a seek if any seek flag is set, or if the the rate
|
||||||
gboolean had_flags = flags != 0;
|
* is non-standard, i.e. not 1.0 */
|
||||||
|
force_seek = flags != GST_SEEK_FLAG_NONE || 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_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
|
GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
|
||||||
|
|
||||||
/* depends on the current playing state of the pipeline. We might need to
|
/* depends on the current playing state of the pipeline. We might need to
|
||||||
* queue this until we get EOS. */
|
* queue this until we get EOS. */
|
||||||
if (had_flags)
|
|
||||||
flags |= GST_SEEK_FLAG_FLUSH;
|
flags |= GST_SEEK_FLAG_FLUSH;
|
||||||
else
|
|
||||||
flags = GST_SEEK_FLAG_FLUSH;
|
|
||||||
|
|
||||||
|
|
||||||
/* if range start was not supplied we must continue from current position.
|
/* if range start was not supplied we must continue from current position.
|
||||||
* but since we're doing a flushing seek, let us query the current position
|
* but since we're doing a flushing seek, let us query the current position
|
||||||
* so we end up at exactly the same position after the seek. */
|
* so we end up at exactly the same position after the seek. */
|
||||||
if (range->min.type == GST_RTSP_TIME_END) { /* Yepp, that's right! */
|
if (range == NULL || range->min.type == GST_RTSP_TIME_END) {
|
||||||
if (current_position == -1) {
|
if (current_position == -1) {
|
||||||
GST_WARNING ("current position unknown");
|
GST_WARNING ("current position unknown");
|
||||||
} else {
|
} else {
|
||||||
|
@ -2748,14 +2805,14 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
flags |= GST_SEEK_FLAG_KEY_UNIT;
|
flags |= GST_SEEK_FLAG_KEY_UNIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start == current_position && stop_type == GST_SEEK_TYPE_NONE) {
|
if (start == current_position && stop_type == GST_SEEK_TYPE_NONE &&
|
||||||
GST_DEBUG ("not seeking because no position change");
|
!force_seek) {
|
||||||
|
GST_DEBUG ("no position change, no flags set by caller, so not seeking");
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
} else {
|
} else {
|
||||||
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
||||||
|
|
||||||
/* FIXME, we only do forwards playback, no trick modes yet */
|
res = gst_element_seek (priv->pipeline, rate, GST_FORMAT_TIME,
|
||||||
res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME,
|
|
||||||
flags, start_type, start, stop_type, stop);
|
flags, start_type, start, stop_type, stop);
|
||||||
|
|
||||||
/* and block for the seek to complete */
|
/* and block for the seek to complete */
|
||||||
|
@ -2819,6 +2876,23 @@ preroll_failed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_seek_full:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
* @range: (transfer none): a #GstRTSPTimeRange
|
||||||
|
* @flags: The minimal set of #GstSeekFlags to use
|
||||||
|
*
|
||||||
|
* Seek the pipeline of @media to @range with the given @flags.
|
||||||
|
* @media must be prepared with gst_rtsp_media_prepare().
|
||||||
|
*
|
||||||
|
* Returns: %TRUE on success.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
|
GstSeekFlags flags)
|
||||||
|
{
|
||||||
|
return gst_rtsp_media_seek_full_with_rate (media, range, flags, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_seek:
|
* gst_rtsp_media_seek:
|
||||||
|
@ -2833,10 +2907,10 @@ preroll_failed:
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
||||||
{
|
{
|
||||||
return gst_rtsp_media_seek_full (media, range, 0);
|
return gst_rtsp_media_seek_full_with_rate (media, range, GST_SEEK_FLAG_NONE,
|
||||||
|
1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked)
|
stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked)
|
||||||
{
|
{
|
||||||
|
|
|
@ -387,6 +387,12 @@ gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media,
|
||||||
GstRTSPTimeRange *range,
|
GstRTSPTimeRange *range,
|
||||||
GstSeekFlags flags);
|
GstSeekFlags flags);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
gboolean gst_rtsp_media_seek_full_with_rate (GstRTSPMedia *media,
|
||||||
|
GstRTSPTimeRange *range,
|
||||||
|
GstSeekFlags flags,
|
||||||
|
gdouble rate);
|
||||||
|
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media);
|
GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media);
|
||||||
|
|
||||||
|
@ -395,6 +401,11 @@ gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media,
|
||||||
gboolean play,
|
gboolean play,
|
||||||
GstRTSPRangeUnit unit);
|
GstRTSPRangeUnit unit);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
gboolean gst_rtsp_media_get_rates (GstRTSPMedia * media,
|
||||||
|
gdouble * rate,
|
||||||
|
gdouble * applied_rate);
|
||||||
|
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state,
|
gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state,
|
||||||
GPtrArray *transports);
|
GPtrArray *transports);
|
||||||
|
|
|
@ -4127,6 +4127,70 @@ no_stats:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_get_rates:
|
||||||
|
* @stream: a #GstRTSPStream
|
||||||
|
* @rate: (allow-none): the configured rate
|
||||||
|
* @applied_rate: (allow-none): the configured applied_rate
|
||||||
|
*
|
||||||
|
* Retrieve the current rate and/or applied_rate.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if rate and/or applied_rate could be determined.
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_rtsp_stream_get_rates (GstRTSPStream * stream, gdouble * rate,
|
||||||
|
gdouble * applied_rate)
|
||||||
|
{
|
||||||
|
GstRTSPStreamPrivate *priv;
|
||||||
|
GstEvent *event;
|
||||||
|
const GstSegment *segment;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
|
||||||
|
|
||||||
|
if (!rate && !applied_rate) {
|
||||||
|
GST_WARNING_OBJECT (stream, "rate and applied_rate are both NULL");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = stream->priv;
|
||||||
|
|
||||||
|
g_mutex_lock (&priv->lock);
|
||||||
|
|
||||||
|
if (!priv->send_rtp_sink)
|
||||||
|
goto no_rtp_sink_pad;
|
||||||
|
|
||||||
|
event = gst_pad_get_sticky_event (priv->send_rtp_sink, GST_EVENT_SEGMENT, 0);
|
||||||
|
if (!event)
|
||||||
|
goto no_sticky_event;
|
||||||
|
|
||||||
|
gst_event_parse_segment (event, &segment);
|
||||||
|
if (rate)
|
||||||
|
*rate = segment->rate;
|
||||||
|
if (applied_rate)
|
||||||
|
*applied_rate = segment->applied_rate;
|
||||||
|
|
||||||
|
gst_event_unref (event);
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
no_rtp_sink_pad:
|
||||||
|
{
|
||||||
|
GST_WARNING_OBJECT (stream, "no send_rtp_sink pad yet");
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
no_sticky_event:
|
||||||
|
{
|
||||||
|
GST_WARNING_OBJECT (stream, "no segment event on send_rtp_sink pad");
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_stream_get_caps:
|
* gst_rtsp_stream_get_caps:
|
||||||
* @stream: a #GstRTSPStream
|
* @stream: a #GstRTSPStream
|
||||||
|
|
|
@ -198,6 +198,11 @@ gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream,
|
||||||
guint *clock_rate,
|
guint *clock_rate,
|
||||||
GstClockTime *running_time);
|
GstClockTime *running_time);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
gboolean gst_rtsp_stream_get_rates (GstRTSPStream * stream,
|
||||||
|
gdouble * rate,
|
||||||
|
gdouble * applied_rate);
|
||||||
|
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream);
|
GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream);
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,8 @@ GST_START_TEST (test_media_seek)
|
||||||
GstRTSPThreadPool *pool;
|
GstRTSPThreadPool *pool;
|
||||||
GstRTSPThread *thread;
|
GstRTSPThread *thread;
|
||||||
GstRTSPTransport *transport;
|
GstRTSPTransport *transport;
|
||||||
|
gdouble rate = 0;
|
||||||
|
gdouble applied_rate = 0;
|
||||||
|
|
||||||
factory = gst_rtsp_media_factory_new ();
|
factory = gst_rtsp_media_factory_new ();
|
||||||
fail_if (gst_rtsp_media_factory_is_shared (factory));
|
fail_if (gst_rtsp_media_factory_is_shared (factory));
|
||||||
|
@ -98,9 +100,30 @@ GST_START_TEST (test_media_seek)
|
||||||
|
|
||||||
str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT);
|
str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT);
|
||||||
fail_unless (g_str_equal (str, "npt=5-"));
|
fail_unless (g_str_equal (str, "npt=5-"));
|
||||||
|
g_free (str);
|
||||||
|
|
||||||
|
/* seeking without rate should result in rate == 1.0 */
|
||||||
|
fail_unless (gst_rtsp_media_seek (media, range));
|
||||||
|
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
||||||
|
fail_unless (rate == 1.0);
|
||||||
|
fail_unless (applied_rate == 1.0);
|
||||||
|
|
||||||
|
/* seeking with rate set to 1.5 should result in rate == 1.5 */
|
||||||
|
fail_unless (gst_rtsp_media_seek_full_with_rate (media, range,
|
||||||
|
GST_SEEK_FLAG_NONE, 1.5));
|
||||||
|
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
||||||
|
fail_unless (rate == 1.5);
|
||||||
|
fail_unless (applied_rate == 1.0);
|
||||||
|
|
||||||
|
/* seeking with rate set to -2.0 should result in rate == -2.0 */
|
||||||
|
fail_unless (gst_rtsp_range_parse ("npt=5-10", &range) == GST_RTSP_OK);
|
||||||
|
fail_unless (gst_rtsp_media_seek_full_with_rate (media, range,
|
||||||
|
GST_SEEK_FLAG_NONE, -2.0));
|
||||||
|
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
||||||
|
fail_unless (rate == -2.0);
|
||||||
|
fail_unless (applied_rate == 1.0);
|
||||||
|
|
||||||
gst_rtsp_range_free (range);
|
gst_rtsp_range_free (range);
|
||||||
g_free (str);
|
|
||||||
|
|
||||||
fail_unless (gst_rtsp_media_unprepare (media));
|
fail_unless (gst_rtsp_media_unprepare (media));
|
||||||
g_object_unref (media);
|
g_object_unref (media);
|
||||||
|
|
Loading…
Reference in a new issue