mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
Start support for RTSP 2.0
This adds basic support for new 2.0 features, though the protocol is subposdely backward incompatible, most semantics are the sames. This commit adds: - features: * version negotiation * pipelined requests support * Media-Properties support * Accept-Ranges support - APIs: * gst_rtsp_media_seekable The RTSP methods that have been removed when using 2.0 now return BAD_REQUEST. https://bugzilla.gnome.org/show_bug.cgi?id=781446
This commit is contained in:
parent
8b38aa9c46
commit
9706199efb
3 changed files with 261 additions and 47 deletions
|
@ -93,6 +93,11 @@ struct _GstRTSPClientPrivate
|
|||
|
||||
guint rtsp_ctrl_timeout_id;
|
||||
guint rtsp_ctrl_timeout_cnt;
|
||||
|
||||
/* The version currently being used */
|
||||
GstRTSPVersion version;
|
||||
|
||||
GHashTable *pipelined_requests; /* pipelined_request_id -> session_id */
|
||||
};
|
||||
|
||||
static GMutex tunnels_lock;
|
||||
|
@ -528,6 +533,8 @@ gst_rtsp_client_init (GstRTSPClient * client)
|
|||
priv->transports =
|
||||
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
|
||||
g_object_unref);
|
||||
priv->pipelined_requests = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal, g_free, g_free);
|
||||
}
|
||||
|
||||
static GstRTSPFilterResult
|
||||
|
@ -800,6 +807,10 @@ send_message (GstRTSPClient * client, GstRTSPContext * ctx,
|
|||
if (close)
|
||||
gst_rtsp_message_add_header (message, GST_RTSP_HDR_CONNECTION, "close");
|
||||
|
||||
if (ctx->request)
|
||||
message->type_data.response.version =
|
||||
ctx->request->type_data.request.version;
|
||||
|
||||
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE],
|
||||
0, ctx, message);
|
||||
|
||||
|
@ -1251,6 +1262,12 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
goto bad_request;
|
||||
|
||||
if (size == 0 || !data || strlen ((char *) data) == 0) {
|
||||
if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) {
|
||||
GST_ERROR_OBJECT (client, "Using PLAY request for keep-alive is forbidden"
|
||||
" in RTSP 2.0");
|
||||
goto bad_request;
|
||||
}
|
||||
|
||||
/* no body (or only '\0'), keep-alive request */
|
||||
send_generic_response (client, GST_RTSP_STS_OK, ctx);
|
||||
} else {
|
||||
|
@ -1498,6 +1515,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
|
||||
gchar *path, *rtpinfo;
|
||||
gint matched;
|
||||
gchar *seek_style = NULL;
|
||||
GstRTSPStatusCode sig_result;
|
||||
|
||||
if (!(session = ctx->session))
|
||||
|
@ -1546,10 +1564,26 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
if (res == GST_RTSP_OK) {
|
||||
if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
|
||||
GstRTSPMediaStatus media_status;
|
||||
GstSeekFlags flags = 0;
|
||||
|
||||
if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_SEEK_STYLE,
|
||||
&seek_style, 0)) {
|
||||
if (g_strcmp0 (seek_style, "RAP") == 0)
|
||||
flags = GST_SEEK_FLAG_ACCURATE;
|
||||
else if (g_strcmp0 (seek_style, "CoRAP") == 0)
|
||||
flags = GST_SEEK_FLAG_KEY_UNIT;
|
||||
else if (g_strcmp0 (seek_style, "First-Prior") == 0)
|
||||
flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_BEFORE;
|
||||
else if (g_strcmp0 (seek_style, "Next") == 0)
|
||||
flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_AFTER;
|
||||
else
|
||||
GST_FIXME_OBJECT (client, "Add support for seek style %s",
|
||||
seek_style);
|
||||
}
|
||||
|
||||
/* we have a range, seek to the position */
|
||||
unit = range->unit;
|
||||
gst_rtsp_media_seek (media, range);
|
||||
gst_rtsp_media_seek_full (media, range, flags);
|
||||
gst_rtsp_range_free (range);
|
||||
|
||||
media_status = gst_rtsp_media_get_status (media);
|
||||
|
@ -1570,6 +1604,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
if (rtpinfo)
|
||||
gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO,
|
||||
rtpinfo);
|
||||
if (seek_style)
|
||||
gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE,
|
||||
seek_style);
|
||||
|
||||
/* add the range */
|
||||
str = gst_rtsp_media_get_range_string (media, TRUE, unit);
|
||||
|
@ -2208,6 +2245,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
gint matched;
|
||||
gboolean new_session = FALSE;
|
||||
GstRTSPStatusCode sig_result;
|
||||
gchar *pipelined_request_id = NULL, *accept_range = NULL;
|
||||
|
||||
if (!ctx->uri)
|
||||
goto no_uri;
|
||||
|
@ -2223,6 +2261,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
if (res != GST_RTSP_OK)
|
||||
goto no_transport;
|
||||
|
||||
/* Handle Pipelined-requests if using >= 2.0 */
|
||||
if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0)
|
||||
gst_rtsp_message_get_header (ctx->request,
|
||||
GST_RTSP_HDR_PIPELINED_REQUESTS, &pipelined_request_id, 0);
|
||||
|
||||
/* we create the session after parsing stuff so that we don't make
|
||||
* a session for malformed requests */
|
||||
if (priv->session_pool == NULL)
|
||||
|
@ -2292,6 +2335,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
|
||||
goto service_unavailable;
|
||||
|
||||
/* Pipelined requests should be cleared between sessions */
|
||||
g_hash_table_remove_all (priv->pipelined_requests);
|
||||
|
||||
/* make sure this client is closed when the session is closed */
|
||||
client_watch_session (client, session);
|
||||
|
||||
|
@ -2303,6 +2349,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
ctx->session = session;
|
||||
}
|
||||
|
||||
if (pipelined_request_id) {
|
||||
g_hash_table_insert (client->priv->pipelined_requests,
|
||||
g_strdup (pipelined_request_id),
|
||||
g_strdup (gst_rtsp_session_get_sessionid (session)));
|
||||
}
|
||||
rtsp_ctrl_timeout_remove (priv);
|
||||
|
||||
if (!klass->configure_client_media (client, media, stream, ctx))
|
||||
|
@ -2328,6 +2379,33 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
goto keymgmt_error;
|
||||
}
|
||||
|
||||
if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
|
||||
&accept_range, 0) == GST_RTSP_OK) {
|
||||
GEnumValue *runit = NULL;
|
||||
gint i;
|
||||
gchar **valid_ranges;
|
||||
GEnumClass *runit_class = g_type_class_ref (GST_TYPE_RTSP_RANGE_UNIT);
|
||||
|
||||
gst_rtsp_message_dump (ctx->request);
|
||||
valid_ranges = g_strsplit (accept_range, ",", -1);
|
||||
|
||||
for (i = 0; valid_ranges[i]; i++) {
|
||||
gchar *range = valid_ranges[i];
|
||||
|
||||
while (*range == ' ')
|
||||
range++;
|
||||
|
||||
runit = g_enum_get_value_by_nick (runit_class, range);
|
||||
if (runit)
|
||||
break;
|
||||
}
|
||||
g_strfreev (valid_ranges);
|
||||
g_type_class_unref (runit_class);
|
||||
|
||||
if (!runit)
|
||||
goto unsupported_range_unit;
|
||||
}
|
||||
|
||||
if (sessmedia == NULL) {
|
||||
/* manage the media in our session now, if not done already */
|
||||
sessmedia =
|
||||
|
@ -2386,6 +2464,33 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
trans_str);
|
||||
g_free (trans_str);
|
||||
|
||||
if (pipelined_request_id)
|
||||
gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PIPELINED_REQUESTS,
|
||||
pipelined_request_id);
|
||||
|
||||
if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) {
|
||||
GstClockTimeDiff seekable = gst_rtsp_media_seekable (media);
|
||||
GString *media_properties = g_string_new (NULL);
|
||||
|
||||
if (seekable == -1)
|
||||
g_string_append (media_properties,
|
||||
"No-Seeking,Time-Progressing,Time-Duration=0.0");
|
||||
else if (seekable == 0)
|
||||
g_string_append (media_properties, "Beginning-Only");
|
||||
else if (seekable == G_MAXINT64)
|
||||
g_string_append (media_properties, "Random-Access");
|
||||
else
|
||||
g_string_append_printf (media_properties,
|
||||
"Random-Access=%f, Unlimited, Immutable",
|
||||
(gdouble) seekable / GST_SECOND);
|
||||
|
||||
gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_MEDIA_PROPERTIES,
|
||||
g_string_free (media_properties, FALSE));
|
||||
/* TODO Check how Accept-Ranges should be filled */
|
||||
gst_rtsp_message_add_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
|
||||
"npt, clock, smpte, clock");
|
||||
}
|
||||
|
||||
send_message (client, ctx, ctx->response, FALSE);
|
||||
|
||||
/* update the state */
|
||||
|
@ -2505,6 +2610,13 @@ unsupported_mode:
|
|||
send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
|
||||
goto cleanup_transport;
|
||||
}
|
||||
unsupported_range_unit:
|
||||
{
|
||||
GST_ERROR ("Client %p: does not support any range format we support",
|
||||
client);
|
||||
send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
|
||||
goto cleanup_transport;
|
||||
}
|
||||
keymgmt_error:
|
||||
{
|
||||
GST_ERROR ("client %p: keymgmt error", client);
|
||||
|
@ -3036,7 +3148,8 @@ unsuspend_failed:
|
|||
}
|
||||
|
||||
static gboolean
|
||||
handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||
handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx,
|
||||
GstRTSPVersion version)
|
||||
{
|
||||
GstRTSPMethod options;
|
||||
gchar *str;
|
||||
|
@ -3046,10 +3159,14 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
GST_RTSP_OPTIONS |
|
||||
GST_RTSP_PAUSE |
|
||||
GST_RTSP_PLAY |
|
||||
GST_RTSP_RECORD | GST_RTSP_ANNOUNCE |
|
||||
GST_RTSP_SETUP |
|
||||
GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
|
||||
|
||||
if (version < GST_RTSP_VERSION_2_0) {
|
||||
options |= GST_RTSP_RECORD;
|
||||
options |= GST_RTSP_ANNOUNCE;
|
||||
}
|
||||
|
||||
str = gst_rtsp_options_as_text (options);
|
||||
|
||||
gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
|
||||
|
@ -3209,7 +3326,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
|
|||
GstRTSPContext sctx = { NULL }, *ctx;
|
||||
GstRTSPMessage response = { 0 };
|
||||
gchar *unsupported_reqs = NULL;
|
||||
gchar *sessid;
|
||||
gchar *sessid = NULL, *pipelined_request_id = NULL;
|
||||
|
||||
if (!(ctx = gst_rtsp_context_get_current ())) {
|
||||
ctx = &sctx;
|
||||
|
@ -3233,7 +3350,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
|
|||
gst_rtsp_version_as_text (version));
|
||||
|
||||
/* we can only handle 1.0 requests */
|
||||
if (version != GST_RTSP_VERSION_1_0)
|
||||
if (version != GST_RTSP_VERSION_1_0 && version != GST_RTSP_VERSION_2_0)
|
||||
goto not_supported;
|
||||
|
||||
ctx->method = method;
|
||||
|
@ -3272,7 +3389,20 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
|
|||
}
|
||||
|
||||
/* get the session if there is any */
|
||||
res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
|
||||
res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_PIPELINED_REQUESTS,
|
||||
&pipelined_request_id, 0);
|
||||
if (res == GST_RTSP_OK) {
|
||||
sessid = g_hash_table_lookup (client->priv->pipelined_requests,
|
||||
pipelined_request_id);
|
||||
|
||||
if (!sessid)
|
||||
res = GST_RTSP_ERROR;
|
||||
}
|
||||
|
||||
if (res != GST_RTSP_OK)
|
||||
res =
|
||||
gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
|
||||
|
||||
if (res == GST_RTSP_OK) {
|
||||
if (priv->session_pool == NULL)
|
||||
goto no_pool;
|
||||
|
@ -3334,7 +3464,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
|
|||
/* now see what is asked and dispatch to a dedicated handler */
|
||||
switch (method) {
|
||||
case GST_RTSP_OPTIONS:
|
||||
handle_options_request (client, ctx);
|
||||
priv->version = version;
|
||||
handle_options_request (client, ctx, version);
|
||||
break;
|
||||
case GST_RTSP_DESCRIBE:
|
||||
handle_describe_request (client, ctx);
|
||||
|
@ -3358,9 +3489,13 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
|
|||
handle_get_param_request (client, ctx);
|
||||
break;
|
||||
case GST_RTSP_ANNOUNCE:
|
||||
if (version >= GST_RTSP_VERSION_2_0)
|
||||
goto invalid_command_for_version;
|
||||
handle_announce_request (client, ctx);
|
||||
break;
|
||||
case GST_RTSP_RECORD:
|
||||
if (version >= GST_RTSP_VERSION_2_0)
|
||||
goto invalid_command_for_version;
|
||||
handle_record_request (client, ctx);
|
||||
break;
|
||||
case GST_RTSP_REDIRECT:
|
||||
|
@ -3394,6 +3529,15 @@ not_supported:
|
|||
ctx);
|
||||
goto done;
|
||||
}
|
||||
invalid_command_for_version:
|
||||
{
|
||||
if (priv->watch != NULL)
|
||||
gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
|
||||
|
||||
GST_ERROR ("client %p: invalid command for version", client);
|
||||
send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
|
||||
goto done;
|
||||
}
|
||||
bad_request:
|
||||
{
|
||||
GST_ERROR ("client %p: bad request", client);
|
||||
|
|
|
@ -125,7 +125,7 @@ struct _GstRTSPMediaPrivate
|
|||
GstNetTimeProvider *nettime;
|
||||
|
||||
gboolean is_live;
|
||||
gboolean seekable;
|
||||
GstClockTimeDiff seekable;
|
||||
gboolean buffering;
|
||||
GstState target_state;
|
||||
|
||||
|
@ -661,6 +661,45 @@ default_create_rtpbin (GstRTSPMedia * media)
|
|||
return rtpbin;
|
||||
}
|
||||
|
||||
/* must be called with state lock */
|
||||
static void
|
||||
check_seekable (GstRTSPMedia * media)
|
||||
{
|
||||
GstQuery *query;
|
||||
GstRTSPMediaPrivate *priv = media->priv;
|
||||
|
||||
/* Update the seekable state of the pipeline in case it changed */
|
||||
if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) {
|
||||
/* TODO: Seeking for RECORD? */
|
||||
priv->seekable = -1;
|
||||
} else {
|
||||
guint i, n = priv->streams->len;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
|
||||
|
||||
if (gst_rtsp_stream_get_publish_clock_mode (stream) ==
|
||||
GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) {
|
||||
priv->seekable = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query = gst_query_new_seeking (GST_FORMAT_TIME);
|
||||
if (gst_element_query (priv->pipeline, query)) {
|
||||
GstFormat format;
|
||||
gboolean seekable;
|
||||
gint64 start, end;
|
||||
|
||||
gst_query_parse_seeking (query, &format, &seekable, &start, &end);
|
||||
priv->seekable = seekable ? G_MAXINT64 : 0.0;
|
||||
}
|
||||
|
||||
gst_query_unref (query);
|
||||
}
|
||||
|
||||
|
||||
/* must be called with state lock */
|
||||
static void
|
||||
collect_media_stats (GstRTSPMedia * media)
|
||||
|
@ -730,6 +769,8 @@ collect_media_stats (GstRTSPMedia * media)
|
|||
priv->range.max.seconds = ((gdouble) stop) / GST_SECOND;
|
||||
priv->range_stop = stop;
|
||||
}
|
||||
|
||||
check_seekable (media);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2114,9 +2155,10 @@ gst_rtsp_media_get_status (GstRTSPMedia * media)
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_rtsp_media_seek:
|
||||
* 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. @media must be prepared with
|
||||
* gst_rtsp_media_prepare().
|
||||
|
@ -2124,14 +2166,14 @@ gst_rtsp_media_get_status (GstRTSPMedia * media)
|
|||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
||||
gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||
GstSeekFlags flags)
|
||||
{
|
||||
GstRTSPMediaClass *klass;
|
||||
GstRTSPMediaPrivate *priv;
|
||||
gboolean res;
|
||||
GstClockTime start, stop;
|
||||
GstSeekType start_type, stop_type;
|
||||
GstQuery *query;
|
||||
gint64 current_position;
|
||||
|
||||
klass = GST_RTSP_MEDIA_GET_CLASS (media);
|
||||
|
@ -2147,37 +2189,16 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
|||
goto not_prepared;
|
||||
|
||||
/* Update the seekable state of the pipeline in case it changed */
|
||||
if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) {
|
||||
/* TODO: Seeking for RECORD? */
|
||||
priv->seekable = FALSE;
|
||||
} else {
|
||||
guint i, n = priv->streams->len;
|
||||
check_seekable (media);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
|
||||
if (priv->seekable == 0) {
|
||||
GST_FIXME_OBJECT (media, "Handle going back to 0 for none live"
|
||||
" not seekable streams.");
|
||||
|
||||
if (gst_rtsp_stream_get_publish_clock_mode (stream) ==
|
||||
GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) {
|
||||
priv->seekable = FALSE;
|
||||
goto not_seekable;
|
||||
}
|
||||
}
|
||||
|
||||
query = gst_query_new_seeking (GST_FORMAT_TIME);
|
||||
if (gst_element_query (priv->pipeline, query)) {
|
||||
GstFormat format;
|
||||
gboolean seekable;
|
||||
gint64 start, end;
|
||||
|
||||
gst_query_parse_seeking (query, &format, &seekable, &start, &end);
|
||||
priv->seekable = seekable;
|
||||
}
|
||||
|
||||
gst_query_unref (query);
|
||||
}
|
||||
|
||||
if (!priv->seekable)
|
||||
goto not_seekable;
|
||||
} else if (priv->seekable < 0) {
|
||||
goto not_seekable;
|
||||
}
|
||||
|
||||
start_type = stop_type = GST_SEEK_TYPE_NONE;
|
||||
|
||||
|
@ -2205,14 +2226,18 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
|||
stop_type = GST_SEEK_TYPE_SET;
|
||||
|
||||
if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) {
|
||||
GstSeekFlags flags;
|
||||
gboolean had_flags = flags != 0;
|
||||
|
||||
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. */
|
||||
flags = GST_SEEK_FLAG_FLUSH;
|
||||
if (had_flags)
|
||||
flags |= GST_SEEK_FLAG_FLUSH;
|
||||
else
|
||||
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
|
||||
|
@ -2225,12 +2250,14 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
|||
GST_TIME_ARGS (current_position));
|
||||
start = current_position;
|
||||
start_type = GST_SEEK_TYPE_SET;
|
||||
flags |= GST_SEEK_FLAG_ACCURATE;
|
||||
if (!had_flags)
|
||||
flags |= GST_SEEK_FLAG_ACCURATE;
|
||||
}
|
||||
} else {
|
||||
/* only set keyframe flag when modifying start */
|
||||
if (start_type != GST_SEEK_TYPE_NONE)
|
||||
flags |= GST_SEEK_FLAG_KEY_UNIT;
|
||||
if (!had_flags)
|
||||
flags |= GST_SEEK_FLAG_KEY_UNIT;
|
||||
}
|
||||
|
||||
if (start == current_position && stop_type == GST_SEEK_TYPE_NONE) {
|
||||
|
@ -2300,6 +2327,24 @@ preroll_failed:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_rtsp_media_seek:
|
||||
* @media: a #GstRTSPMedia
|
||||
* @range: (transfer none): a #GstRTSPTimeRange
|
||||
*
|
||||
* Seek the pipeline of @media to @range. @media must be prepared with
|
||||
* gst_rtsp_media_prepare().
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
||||
{
|
||||
return gst_rtsp_media_seek_full (media, range, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked)
|
||||
{
|
||||
|
@ -2675,18 +2720,16 @@ start_preroll (GstRTSPMedia * media)
|
|||
switch (ret) {
|
||||
case GST_STATE_CHANGE_SUCCESS:
|
||||
GST_INFO ("SUCCESS state change for media %p", media);
|
||||
priv->seekable = TRUE;
|
||||
break;
|
||||
case GST_STATE_CHANGE_ASYNC:
|
||||
GST_INFO ("ASYNC state change for media %p", media);
|
||||
priv->seekable = TRUE;
|
||||
break;
|
||||
case GST_STATE_CHANGE_NO_PREROLL:
|
||||
/* we need to go to PLAYING */
|
||||
GST_INFO ("NO_PREROLL state change: live media %p", media);
|
||||
/* FIXME we disable seeking for live streams for now. We should perform a
|
||||
* seeking query in preroll instead */
|
||||
priv->seekable = FALSE;
|
||||
priv->seekable = -1;
|
||||
priv->is_live = TRUE;
|
||||
if (!(priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) {
|
||||
/* start blocked to make sure nothing goes to the sink */
|
||||
|
@ -2953,7 +2996,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
|
|||
|
||||
/* reset some variables */
|
||||
priv->is_live = FALSE;
|
||||
priv->seekable = FALSE;
|
||||
priv->seekable = -1;
|
||||
priv->buffering = FALSE;
|
||||
|
||||
/* we're preparing now */
|
||||
|
@ -3937,3 +3980,24 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media)
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_rtsp_media_get_seekbale:
|
||||
* @media: a #GstRTSPMedia
|
||||
*
|
||||
* Check if the pipeline for @media seek and up to what point in time,
|
||||
* it can seek.
|
||||
*
|
||||
* Returns: -1 if the stream is not seekable, 0 if seekable only to the beginning
|
||||
* and > 0 to indicate the longest duration between any two random access points.
|
||||
* G_MAXINT64 means any value is possible.
|
||||
*/
|
||||
GstClockTimeDiff
|
||||
gst_rtsp_media_seekable (GstRTSPMedia * media)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
|
||||
|
||||
/* Currently we are not able to seek on live streams,
|
||||
* and no stream is seekable only to the beginning */
|
||||
return media->priv->seekable;
|
||||
}
|
||||
|
|
|
@ -362,6 +362,12 @@ GstRTSPStream * gst_rtsp_media_find_stream (GstRTSPMedia *media, cons
|
|||
|
||||
GST_EXPORT
|
||||
gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range);
|
||||
gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media,
|
||||
GstRTSPTimeRange *range,
|
||||
GstSeekFlags flags);
|
||||
|
||||
GST_EXPORT
|
||||
GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media);
|
||||
|
||||
GST_EXPORT
|
||||
gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media,
|
||||
|
|
Loading…
Reference in a new issue