* #GstRTSPSession and #GstRTSPSessionMedia.
*
* 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
* gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
}
}
+/**
+ * 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
stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media)
{
}
/**
- * gst_rtsp_media_seek_full:
+ * gst_rtsp_media_seek_full_with_rate:
* @media: a #GstRTSPMedia
* @range: (transfer none): a #GstRTSPTimeRange
* @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
- * gst_rtsp_media_prepare(). In order to perform the seek operation,
- * the pipeline must contain all needed transport parts (transport sinks).
+ * Seek the pipeline of @media to @range with the given @flags and @rate.
+ * @media must be prepared with gst_rtsp_media_prepare().
+ * In order to perform the seek operation, the pipeline must contain all
+ * needed transport parts (transport sinks).
*
* Returns: %TRUE on success.
*
- * Since: 1.14
+ * Since: 1.18
*/
gboolean
-gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
- GstSeekFlags flags)
+gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media,
+ GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate)
{
GstRTSPMediaClass *klass;
GstRTSPMediaPrivate *priv;
GstClockTime start, stop;
GstSeekType start_type, stop_type;
gint64 current_position;
+ gboolean force_seek;
klass = GST_RTSP_MEDIA_GET_CLASS (media);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
- g_return_val_if_fail (range != NULL, FALSE);
- g_return_val_if_fail (klass->convert_range != NULL, FALSE);
+ /* if there's a range then klass->convert_range must be set */
+ g_return_val_if_fail (range == NULL || klass->convert_range != NULL, FALSE);
+
+ GST_DEBUG ("flags=%x rate=%f", flags, rate);
priv = media->priv;
}
start_type = stop_type = GST_SEEK_TYPE_NONE;
+ start = stop = GST_CLOCK_TIME_NONE;
- if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT))
- goto not_supported;
- gst_rtsp_range_get_times (range, &start, &stop);
+ /* 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))
+ goto not_supported;
+ gst_rtsp_range_get_times (range, &start, &stop);
- GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
- GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
- GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
- GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
+ GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+ GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop));
+ }
current_position = -1;
if (klass->query_position)
else if (stop != GST_CLOCK_TIME_NONE)
stop_type = GST_SEEK_TYPE_SET;
- if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
- gboolean had_flags = flags != 0;
+ /* we force a seek if any seek flag is set, or if the the rate
+ * 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_TIME_ARGS (start), GST_TIME_ARGS (stop));
/* depends on the current playing state of the pipeline. We might need to
* queue this until we get EOS. */
- if (had_flags)
- flags |= GST_SEEK_FLAG_FLUSH;
- else
- flags = GST_SEEK_FLAG_FLUSH;
-
+ flags |= GST_SEEK_FLAG_FLUSH;
/* 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
* 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) {
GST_WARNING ("current position unknown");
} else {
flags |= GST_SEEK_FLAG_KEY_UNIT;
}
- if (start == current_position && stop_type == GST_SEEK_TYPE_NONE) {
- GST_DEBUG ("not seeking because no position change");
+ if (start == current_position && stop_type == GST_SEEK_TYPE_NONE &&
+ !force_seek) {
+ GST_DEBUG ("no position change, no flags set by caller, so not seeking");
res = TRUE;
} else {
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, 1.0, GST_FORMAT_TIME,
+ res = gst_element_seek (priv->pipeline, rate, GST_FORMAT_TIME,
flags, start_type, start, stop_type, stop);
/* and block for the seek to complete */
}
}
+/**
+ * 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:
gboolean
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
stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked)
{
GstRTSPThreadPool *pool;
GstRTSPThread *thread;
GstRTSPTransport *transport;
+ gdouble rate = 0;
+ gdouble applied_rate = 0;
factory = gst_rtsp_media_factory_new ();
fail_if (gst_rtsp_media_factory_is_shared (factory));
str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT);
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);
- g_free (str);
fail_unless (gst_rtsp_media_unprepare (media));
g_object_unref (media);