mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
souphttpsrc: allow seeks in ready
On is_seekable, check if the server's headers have already been received. If not, do a HEAD request to get them before responding to basesrc. https://bugzilla.gnome.org/show_bug.cgi?id=702206
This commit is contained in:
parent
1db7e62060
commit
5bc5f4a0f6
2 changed files with 119 additions and 50 deletions
|
@ -136,13 +136,15 @@ static gboolean gst_soup_http_src_set_location (GstSoupHTTPSrc * src,
|
|||
static gboolean gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src,
|
||||
const gchar * uri);
|
||||
static char *gst_soup_http_src_unicodify (const char *str);
|
||||
static gboolean gst_soup_http_src_build_message (GstSoupHTTPSrc * src);
|
||||
static gboolean gst_soup_http_src_build_message (GstSoupHTTPSrc * src,
|
||||
const gchar * method);
|
||||
static void gst_soup_http_src_cancel_message (GstSoupHTTPSrc * src);
|
||||
static void gst_soup_http_src_queue_message (GstSoupHTTPSrc * src);
|
||||
static gboolean gst_soup_http_src_add_range_header (GstSoupHTTPSrc * src,
|
||||
guint64 offset);
|
||||
static void gst_soup_http_src_session_unpause_message (GstSoupHTTPSrc * src);
|
||||
static void gst_soup_http_src_session_pause_message (GstSoupHTTPSrc * src);
|
||||
static gboolean gst_soup_http_src_session_open (GstSoupHTTPSrc * src);
|
||||
static void gst_soup_http_src_session_close (GstSoupHTTPSrc * src);
|
||||
static void gst_soup_http_src_parse_status (SoupMessage * msg,
|
||||
GstSoupHTTPSrc * src);
|
||||
|
@ -273,6 +275,7 @@ gst_soup_http_src_reset (GstSoupHTTPSrc * src)
|
|||
src->interrupted = FALSE;
|
||||
src->retry = FALSE;
|
||||
src->have_size = FALSE;
|
||||
src->got_headers = FALSE;
|
||||
src->seekable = FALSE;
|
||||
src->read_position = 0;
|
||||
src->request_position = 0;
|
||||
|
@ -292,6 +295,8 @@ gst_soup_http_src_init (GstSoupHTTPSrc * src)
|
|||
{
|
||||
const gchar *proxy;
|
||||
|
||||
g_mutex_init (&src->mutex);
|
||||
g_cond_init (&src->request_finished_cond);
|
||||
src->location = NULL;
|
||||
src->automatic_redirect = TRUE;
|
||||
src->user_agent = g_strdup (DEFAULT_USER_AGENT);
|
||||
|
@ -322,6 +327,8 @@ gst_soup_http_src_finalize (GObject * gobject)
|
|||
|
||||
GST_DEBUG_OBJECT (src, "finalize");
|
||||
|
||||
g_mutex_clear (&src->mutex);
|
||||
g_cond_clear (&src->request_finished_cond);
|
||||
g_free (src->location);
|
||||
g_free (src->user_agent);
|
||||
if (src->proxy != NULL) {
|
||||
|
@ -627,6 +634,57 @@ gst_soup_http_src_session_pause_message (GstSoupHTTPSrc * src)
|
|||
soup_session_pause_message (src->session, src->msg);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
|
||||
{
|
||||
if (src->session) {
|
||||
GST_DEBUG_OBJECT (src, "Session is already open");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!src->location) {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (_("No URL set.")),
|
||||
("Missing location property"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
src->context = g_main_context_new ();
|
||||
|
||||
src->loop = g_main_loop_new (src->context, TRUE);
|
||||
if (!src->loop) {
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
(NULL), ("Failed to start GMainLoop"));
|
||||
g_main_context_unref (src->context);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (src, "Creating session");
|
||||
if (src->proxy == NULL) {
|
||||
src->session =
|
||||
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
|
||||
src->context, SOUP_SESSION_USER_AGENT, src->user_agent,
|
||||
SOUP_SESSION_TIMEOUT, src->timeout,
|
||||
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
|
||||
NULL);
|
||||
} else {
|
||||
src->session =
|
||||
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
|
||||
src->context, SOUP_SESSION_PROXY_URI, src->proxy,
|
||||
SOUP_SESSION_TIMEOUT, src->timeout,
|
||||
SOUP_SESSION_USER_AGENT, src->user_agent, NULL);
|
||||
}
|
||||
|
||||
if (!src->session) {
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
(NULL), ("Failed to create async session"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_connect (src->session, "authenticate",
|
||||
G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_soup_http_src_session_close (GstSoupHTTPSrc * src)
|
||||
{
|
||||
|
@ -687,6 +745,7 @@ gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
|
|||
return;
|
||||
|
||||
src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING;
|
||||
src->got_headers = TRUE;
|
||||
|
||||
/* Parse Content-Length. */
|
||||
if (soup_message_headers_get_encoding (msg->response_headers) ==
|
||||
|
@ -825,6 +884,7 @@ gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
|
|||
if (src->loop)
|
||||
g_main_loop_quit (src->loop);
|
||||
}
|
||||
g_cond_signal (&src->request_finished_cond);
|
||||
}
|
||||
|
||||
/* Have body. Signal EOS. */
|
||||
|
@ -876,6 +936,7 @@ gst_soup_http_src_finished_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
|
|||
}
|
||||
if (src->loop)
|
||||
g_main_loop_quit (src->loop);
|
||||
g_cond_signal (&src->request_finished_cond);
|
||||
}
|
||||
|
||||
/* Buffer lifecycle management.
|
||||
|
@ -1092,9 +1153,9 @@ gst_soup_http_src_parse_status (SoupMessage * msg, GstSoupHTTPSrc * src)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
gst_soup_http_src_build_message (GstSoupHTTPSrc * src)
|
||||
gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
|
||||
{
|
||||
src->msg = soup_message_new (SOUP_METHOD_GET, src->location);
|
||||
src->msg = soup_message_new (method, src->location);
|
||||
if (!src->msg) {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
|
||||
("Error parsing URL."), ("URL: %s", src->location));
|
||||
|
@ -1141,12 +1202,10 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src)
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
|
||||
gst_soup_http_src_do_request (GstSoupHTTPSrc * src, const gchar * method,
|
||||
GstBuffer ** outbuf)
|
||||
{
|
||||
GstSoupHTTPSrc *src;
|
||||
|
||||
src = GST_SOUP_HTTP_SRC (psrc);
|
||||
|
||||
GST_LOG_OBJECT (src, "Running request for method: %s", method);
|
||||
if (src->msg && (src->request_position != src->read_position)) {
|
||||
if (src->session_io_status == GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE) {
|
||||
gst_soup_http_src_add_range_header (src, src->request_position);
|
||||
|
@ -1158,8 +1217,9 @@ gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
|
|||
}
|
||||
}
|
||||
if (!src->msg)
|
||||
if (!gst_soup_http_src_build_message (src))
|
||||
if (!gst_soup_http_src_build_message (src, method)) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
src->ret = GST_FLOW_CUSTOM_ERROR;
|
||||
src->outbuf = outbuf;
|
||||
|
@ -1170,8 +1230,9 @@ gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
|
|||
}
|
||||
if (src->retry) {
|
||||
GST_DEBUG_OBJECT (src, "Reconnecting");
|
||||
if (!gst_soup_http_src_build_message (src))
|
||||
if (!gst_soup_http_src_build_message (src, method)) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
src->retry = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
@ -1201,9 +1262,24 @@ gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
|
|||
|
||||
if (src->ret == GST_FLOW_CUSTOM_ERROR)
|
||||
src->ret = GST_FLOW_EOS;
|
||||
g_cond_signal (&src->request_finished_cond);
|
||||
return src->ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
|
||||
{
|
||||
GstSoupHTTPSrc *src;
|
||||
GstFlowReturn ret;
|
||||
|
||||
src = GST_SOUP_HTTP_SRC (psrc);
|
||||
|
||||
g_mutex_lock (&src->mutex);
|
||||
ret = gst_soup_http_src_do_request (src, SOUP_METHOD_GET, outbuf);
|
||||
g_mutex_unlock (&src->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_soup_http_src_start (GstBaseSrc * bsrc)
|
||||
{
|
||||
|
@ -1211,46 +1287,7 @@ gst_soup_http_src_start (GstBaseSrc * bsrc)
|
|||
|
||||
GST_DEBUG_OBJECT (src, "start(\"%s\")", src->location);
|
||||
|
||||
if (!src->location) {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (_("No URL set.")),
|
||||
("Missing location property"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
src->context = g_main_context_new ();
|
||||
|
||||
src->loop = g_main_loop_new (src->context, TRUE);
|
||||
if (!src->loop) {
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
(NULL), ("Failed to start GMainLoop"));
|
||||
g_main_context_unref (src->context);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->proxy == NULL) {
|
||||
src->session =
|
||||
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
|
||||
src->context, SOUP_SESSION_USER_AGENT, src->user_agent,
|
||||
SOUP_SESSION_TIMEOUT, src->timeout,
|
||||
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
|
||||
NULL);
|
||||
} else {
|
||||
src->session =
|
||||
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
|
||||
src->context, SOUP_SESSION_PROXY_URI, src->proxy,
|
||||
SOUP_SESSION_TIMEOUT, src->timeout,
|
||||
SOUP_SESSION_USER_AGENT, src->user_agent, NULL);
|
||||
}
|
||||
|
||||
if (!src->session) {
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
(NULL), ("Failed to create async session"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_connect (src->session, "authenticate",
|
||||
G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
|
||||
return TRUE;
|
||||
return gst_soup_http_src_session_open (src);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -1288,6 +1325,7 @@ gst_soup_http_src_unlock (GstBaseSrc * bsrc)
|
|||
src->interrupted = TRUE;
|
||||
if (src->loop)
|
||||
g_main_loop_quit (src->loop);
|
||||
g_cond_signal (&src->request_finished_cond);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1325,6 +1363,33 @@ static gboolean
|
|||
gst_soup_http_src_is_seekable (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
/* Special case to check if the server allows range requests
|
||||
* before really starting to get data in the buffer creation
|
||||
* loops.
|
||||
*/
|
||||
if (!src->got_headers && GST_STATE (src) != GST_STATE_NULL) {
|
||||
g_mutex_lock (&src->mutex);
|
||||
while (!src->got_headers && !src->interrupted && ret == GST_FLOW_OK) {
|
||||
if ((src->msg && src->msg->method != SOUP_METHOD_HEAD) &&
|
||||
src->session_io_status != GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE) {
|
||||
/* wait for the current request to finish */
|
||||
g_cond_wait (&src->request_finished_cond, &src->mutex);
|
||||
} else {
|
||||
if (gst_soup_http_src_session_open (src)) {
|
||||
ret = gst_soup_http_src_do_request (src, SOUP_METHOD_HEAD, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src->ret == GST_FLOW_EOS) {
|
||||
/* A HEAD request shouldn't lead to EOS */
|
||||
src->ret = GST_FLOW_OK;
|
||||
}
|
||||
/* resets status to idle */
|
||||
gst_soup_http_src_cancel_message (src);
|
||||
g_mutex_unlock (&src->mutex);
|
||||
}
|
||||
|
||||
return src->seekable;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ struct _GstSoupHTTPSrc {
|
|||
gboolean interrupted; /* Signal unlock(). */
|
||||
gboolean retry; /* Should attempt to reconnect. */
|
||||
|
||||
gboolean got_headers; /* Already received headers from the server */
|
||||
gboolean have_size; /* Received and parsed Content-Length
|
||||
header. */
|
||||
guint64 content_size; /* Value of Content-Length header. */
|
||||
|
@ -86,6 +87,9 @@ struct _GstSoupHTTPSrc {
|
|||
GstStructure *extra_headers;
|
||||
|
||||
guint timeout;
|
||||
|
||||
GMutex mutex;
|
||||
GCond request_finished_cond;
|
||||
};
|
||||
|
||||
struct _GstSoupHTTPSrcClass {
|
||||
|
|
Loading…
Reference in a new issue