GstFragment *
gst_uri_downloader_fetch_uri (GstUriDownloader * downloader, const gchar * uri)
{
  GstStateChangeReturn ret;
  GstFragment *download = NULL;

  g_mutex_lock (&downloader->priv->lock);

  if (downloader->priv->cancelled) {
    goto quit;
  }

  if (!gst_uri_downloader_set_uri (downloader, uri)) {
    goto quit;
  }

  downloader->priv->download = gst_fragment_new ();

  gst_bus_set_flushing (downloader->priv->bus, FALSE);
  ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    g_object_unref (downloader->priv->download);
    downloader->priv->download = NULL;
    goto quit;
  }

  /* wait until:
   *   - the download succeed (EOS in the src pad)
   *   - the download failed (Error message on the fetcher bus)
   *   - the download was canceled
   */
  GST_DEBUG_OBJECT (downloader, "Waiting to fetch the URI %s", uri);
  g_cond_wait (&downloader->priv->cond, &downloader->priv->lock);

  if (downloader->priv->cancelled) {
    if (downloader->priv->download) {
      g_object_unref (downloader->priv->download);
      downloader->priv->download = NULL;
    }
    goto quit;
  }

  GST_OBJECT_LOCK (downloader);
  download = downloader->priv->download;
  downloader->priv->download = NULL;
  GST_OBJECT_UNLOCK (downloader);

  if (download != NULL)
    GST_INFO_OBJECT (downloader, "URI fetched successfully");
  else
    GST_INFO_OBJECT (downloader, "Error fetching URI");

quit:
  {
    gst_uri_downloader_stop (downloader);
    g_mutex_unlock (&downloader->priv->lock);
    return download;
  }
}
/**
 * gst_uri_downloader_fetch_uri_with_range:
 * @downloader: the #GstUriDownloader
 * @uri: the uri
 * @range_start: the starting byte index
 * @range_end: the final byte index, use -1 for unspecified
 *
 * Returns the downloaded #GstFragment
 */
GstFragment *
gst_uri_downloader_fetch_uri_with_range (GstUriDownloader *
    downloader, const gchar * uri, const gchar * referer, gboolean compress,
    gboolean refresh, gboolean allow_cache,
    gint64 range_start, gint64 range_end, GError ** err)
{
  GstStateChangeReturn ret;
  GstFragment *download = NULL;

  GST_DEBUG_OBJECT (downloader, "Fetching URI %s", uri);

  g_mutex_lock (&downloader->priv->download_lock);
  downloader->priv->err = NULL;
  downloader->priv->got_buffer = FALSE;

  GST_OBJECT_LOCK (downloader);
  if (downloader->priv->cancelled) {
    GST_DEBUG_OBJECT (downloader, "Cancelled, aborting fetch");
    goto quit;
  }

  if (!gst_uri_downloader_set_uri (downloader, uri, referer, compress, refresh,
          allow_cache)) {
    GST_WARNING_OBJECT (downloader, "Failed to set URI");
    goto quit;
  }

  gst_bus_set_flushing (downloader->priv->bus, FALSE);
  if (downloader->priv->download)
    g_object_unref (downloader->priv->download);
  downloader->priv->download = gst_fragment_new ();
  downloader->priv->download->range_start = range_start;
  downloader->priv->download->range_end = range_end;
  GST_OBJECT_UNLOCK (downloader);
  ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_READY);
  GST_OBJECT_LOCK (downloader);
  if (ret == GST_STATE_CHANGE_FAILURE || downloader->priv->download == NULL) {
    GST_WARNING_OBJECT (downloader, "Failed to set src to READY");
    goto quit;
  }

  /* might have been cancelled because of failures in state change */
  if (downloader->priv->cancelled) {
    goto quit;
  }

  if (range_start < 0 && range_end < 0) {
    if (!gst_uri_downloader_set_method (downloader, "HEAD")) {
      GST_WARNING_OBJECT (downloader, "Failed to set HTTP method");
      goto quit;
    }
  } else {
    if (!gst_uri_downloader_set_range (downloader, range_start, range_end)) {
      GST_WARNING_OBJECT (downloader, "Failed to set range");
      goto quit;
    }
  }

  GST_OBJECT_UNLOCK (downloader);
  ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_PLAYING);
  GST_OBJECT_LOCK (downloader);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    if (downloader->priv->download) {
      g_object_unref (downloader->priv->download);
      downloader->priv->download = NULL;
    }
    goto quit;
  }

  /* might have been cancelled because of failures in state change */
  if (downloader->priv->cancelled) {
    goto quit;
  }

  /* wait until:
   *   - the download succeed (EOS in the src pad)
   *   - the download failed (Error message on the fetcher bus)
   *   - the download was canceled
   */
  GST_DEBUG_OBJECT (downloader, "Waiting to fetch the URI %s", uri);
  while (!downloader->priv->cancelled && !downloader->priv->download->completed)
    g_cond_wait (&downloader->priv->cond, GST_OBJECT_GET_LOCK (downloader));

  if (downloader->priv->cancelled) {
    if (downloader->priv->download) {
      g_object_unref (downloader->priv->download);
      downloader->priv->download = NULL;
    }
    goto quit;
  }

  download = downloader->priv->download;
  downloader->priv->download = NULL;
  if (!downloader->priv->got_buffer) {
    if (download->range_start < 0 && download->range_end < 0) {
      /* HEAD request, so we don't expect a response */
    } else {
      g_object_unref (download);
      download = NULL;
      GST_ERROR_OBJECT (downloader, "Didn't retrieve a buffer before EOS");
    }
  }

  if (download != NULL)
    GST_INFO_OBJECT (downloader, "URI fetched successfully");
  else
    GST_INFO_OBJECT (downloader, "Error fetching URI");

quit:
  {
    if (downloader->priv->urisrc) {
      GstPad *pad;
      GstElement *urisrc;

      urisrc = downloader->priv->urisrc;

      GST_DEBUG_OBJECT (downloader, "Stopping source element %s",
          GST_ELEMENT_NAME (urisrc));

      /* remove the bus' sync handler */
      gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL, NULL);
      gst_bus_set_flushing (downloader->priv->bus, TRUE);

      /* set the element state to NULL */
      GST_OBJECT_UNLOCK (downloader);
      if (download == NULL) {
        gst_element_set_state (urisrc, GST_STATE_NULL);
      } else {
        GstQuery *query;

        /* Download successfull, let's query the URI */
        query = gst_query_new_uri ();
        if (gst_element_query (urisrc, query)) {
          gst_query_parse_uri (query, &download->uri);
          gst_query_parse_uri_redirection (query, &download->redirect_uri);
          gst_query_parse_uri_redirection_permanent (query,
              &download->redirect_permanent);
        }
        gst_query_unref (query);
        gst_element_set_state (urisrc, GST_STATE_READY);
      }
      GST_OBJECT_LOCK (downloader);
      gst_element_set_bus (urisrc, NULL);

      /* unlink the source element from the internal pad */
      pad = gst_pad_get_peer (downloader->priv->pad);
      if (pad) {
        gst_pad_unlink (pad, downloader->priv->pad);
        gst_object_unref (pad);
      }
    }
    GST_OBJECT_UNLOCK (downloader);

    if (download == NULL) {
      if (!downloader->priv->err) {
        g_set_error (err, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_OPEN_READ,
            "Failed to download '%s'", uri);
      } else {
        g_propagate_error (err, downloader->priv->err);
        downloader->priv->err = NULL;
      }
    }

    downloader->priv->cancelled = FALSE;

    g_mutex_unlock (&downloader->priv->download_lock);
    return download;
  }
}
/**
 * gst_uri_downloader_fetch_uri_with_range:
 * @downloader: the #GstUriDownloader
 * @uri: the uri
 * @range_start: the starting byte index
 * @range_end: the final byte index, use -1 for unspecified
 *
 * Returns the downloaded #GstFragment
 */
GstFragment *
gst_uri_downloader_fetch_uri_with_range (GstUriDownloader * downloader,
    const gchar * uri, gint64 range_start, gint64 range_end)
{
  GstStateChangeReturn ret;
  GstFragment *download = NULL;

  GST_DEBUG_OBJECT (downloader, "Fetching URI %s", uri);

  g_mutex_lock (&downloader->priv->download_lock);

  GST_OBJECT_LOCK (downloader);
  if (downloader->priv->cancelled) {
    GST_DEBUG_OBJECT (downloader, "Cancelled, aborting fetch");
    goto quit;
  }

  if (!gst_uri_downloader_set_uri (downloader, uri)) {
    GST_WARNING_OBJECT (downloader, "Failed to set URI");
    goto quit;
  }

  gst_bus_set_flushing (downloader->priv->bus, FALSE);
  downloader->priv->download = gst_fragment_new ();
  GST_OBJECT_UNLOCK (downloader);
  ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_READY);
  GST_OBJECT_LOCK (downloader);
  if (ret == GST_STATE_CHANGE_FAILURE || downloader->priv->download == NULL) {
    GST_WARNING_OBJECT (downloader, "Failed to set src to READY");
    goto quit;
  }

  /* might have been cancelled because of failures in state change */
  if (downloader->priv->cancelled) {
    goto quit;
  }

  if (!gst_uri_downloader_set_range (downloader, range_start, range_end)) {
    GST_WARNING_OBJECT (downloader, "Failed to set range");
    goto quit;
  }

  GST_OBJECT_UNLOCK (downloader);
  ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_PLAYING);
  GST_OBJECT_LOCK (downloader);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    if (downloader->priv->download) {
      g_object_unref (downloader->priv->download);
      downloader->priv->download = NULL;
    }
    goto quit;
  }

  /* might have been cancelled because of failures in state change */
  if (downloader->priv->cancelled) {
    goto quit;
  }

  /* wait until:
   *   - the download succeed (EOS in the src pad)
   *   - the download failed (Error message on the fetcher bus)
   *   - the download was canceled
   */
  GST_DEBUG_OBJECT (downloader, "Waiting to fetch the URI %s", uri);
  while (!downloader->priv->cancelled && !downloader->priv->download->completed)
    g_cond_wait (&downloader->priv->cond, GST_OBJECT_GET_LOCK (downloader));

  if (downloader->priv->cancelled) {
    if (downloader->priv->download) {
      g_object_unref (downloader->priv->download);
      downloader->priv->download = NULL;
    }
    goto quit;
  }

  download = downloader->priv->download;
  downloader->priv->download = NULL;

  if (download != NULL)
    GST_INFO_OBJECT (downloader, "URI fetched successfully");
  else
    GST_INFO_OBJECT (downloader, "Error fetching URI");

quit:
  {
    if (downloader->priv->urisrc) {
      GstPad *pad;
      GstElement *urisrc;

      GST_DEBUG_OBJECT (downloader, "Stopping source element %s",
          GST_ELEMENT_NAME (downloader->priv->urisrc));

      /* remove the bus' sync handler */
      gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL, NULL);
      /* unlink the source element from the internal pad */
      pad = gst_pad_get_peer (downloader->priv->pad);
      if (pad) {
        gst_pad_unlink (pad, downloader->priv->pad);
        gst_object_unref (pad);
      }
      urisrc = downloader->priv->urisrc;
      downloader->priv->urisrc = NULL;
      GST_OBJECT_UNLOCK (downloader);

      GST_DEBUG_OBJECT (downloader, "Stopping source element %s",
          GST_ELEMENT_NAME (urisrc));

      /* set the element state to NULL */
      gst_bus_set_flushing (downloader->priv->bus, TRUE);
      gst_element_set_state (urisrc, GST_STATE_NULL);
      gst_element_get_state (urisrc, NULL, NULL, GST_CLOCK_TIME_NONE);
      gst_element_set_bus (urisrc, NULL);
      gst_object_unref (urisrc);
    } else {
      GST_OBJECT_UNLOCK (downloader);
    }

    g_mutex_unlock (&downloader->priv->download_lock);
    return download;
  }
}