Exemplo n.º 1
0
static gboolean
gst_hls_demux_select_bitrate (GstAdaptiveDemuxStream * stream, guint64 bitrate)
{
  GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (stream->demux);
  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
  gboolean changed = FALSE;

  GST_M3U8_CLIENT_LOCK (hlsdemux->client);
  if (!hlsdemux->client->main->lists) {
    GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
    return FALSE;
  }
  GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);

  /* FIXME: Currently several issues have be found when letting bitrate adaptation
   * happen using trick modes (such as 'All streams finished without buffers') and
   * the adaptive algorithm does not properly behave. */
  if (demux->segment.rate != 1.0)
    return FALSE;

  gst_hls_demux_change_playlist (hlsdemux, bitrate, &changed);
  if (changed)
    gst_hls_demux_setup_streams (GST_ADAPTIVE_DEMUX_CAST (hlsdemux));
  return changed;
}
Exemplo n.º 2
0
static GstStateChangeReturn
gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
{
  GstStateChangeReturn ret;
  GstHLSDemux *demux = GST_HLS_DEMUX (element);

  switch (transition) {
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
      break;
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
      break;
    default:
      break;
  }
  return ret;
}
Exemplo n.º 3
0
static void
gst_mss_demux_dispose (GObject * object)
{
  gst_mss_demux_reset (GST_ADAPTIVE_DEMUX_CAST (object));

  G_OBJECT_CLASS (parent_class)->dispose (object);
}
Exemplo n.º 4
0
static void
gst_mss_demux_init (GstMssDemux * mssdemux)
{
  mssdemux->data_queue_max_size = DEFAULT_MAX_QUEUE_SIZE_BUFFERS;

  gst_adaptive_demux_set_stream_struct_size (GST_ADAPTIVE_DEMUX_CAST (mssdemux),
      sizeof (GstMssDemuxStream));
}
Exemplo n.º 5
0
static void
gst_hls_demux_dispose (GObject * obj)
{
  GstHLSDemux *demux = GST_HLS_DEMUX (obj);

  gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
  gst_m3u8_client_free (demux->client);

  G_OBJECT_CLASS (parent_class)->dispose (obj);
}
Exemplo n.º 6
0
static void
gst_hls_demux_finalize (GObject * obj)
{
  GstHLSDemux *demux = GST_HLS_DEMUX (obj);

  gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
  g_object_unref (demux->pending_encrypted_data);
  gst_m3u8_client_free (demux->client);

  G_OBJECT_CLASS (parent_class)->finalize (obj);
}
Exemplo n.º 7
0
static guint64
gst_hls_demux_get_bitrate (GstHLSDemux * hlsdemux)
{
  GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (hlsdemux);

  /* Valid because hlsdemux only has a single output */
  if (demux->streams) {
    GstAdaptiveDemuxStream *stream = demux->streams->data;
    return stream->current_download_rate;
  }

  return 0;
}
Exemplo n.º 8
0
static void
gst_mss_demux_update_base_url (GstMssDemux * mssdemux)
{
  GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (mssdemux);
  gchar *baseurl_end;

  g_free (mssdemux->base_url);

  mssdemux->base_url =
      g_strdup (demux->manifest_base_uri ? demux->manifest_base_uri : demux->
      manifest_uri);
  baseurl_end = g_strrstr (mssdemux->base_url, "/Manifest");
  if (baseurl_end == NULL) {
    /* second try */
    baseurl_end = g_strrstr (mssdemux->base_url, "/manifest");
  }
  if (baseurl_end) {
    /* set the new end of the string */
    baseurl_end[0] = '\0';
  } else {
    GST_WARNING_OBJECT (mssdemux, "Stream's URI didn't end with /manifest");
  }

}
Exemplo n.º 9
0
static gboolean
gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
    GError ** err)
{
  GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
  GstFragment *download;
  GstBuffer *buf;
  gchar *playlist;
  gboolean main_checked = FALSE, updated = FALSE;
  gchar *uri, *main_uri;

retry:
  uri = gst_m3u8_client_get_current_uri (demux->client);
  main_uri = gst_m3u8_client_get_uri (demux->client);
  download =
      gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
      TRUE, TRUE, TRUE, err);
  g_free (main_uri);
  if (download == NULL) {
    gchar *base_uri;

    if (!update || main_checked
        || !gst_m3u8_client_has_variant_playlist (demux->client)) {
      g_free (uri);
      return FALSE;
    }

    g_clear_error (err);
    main_uri = gst_m3u8_client_get_uri (demux->client);
    GST_INFO_OBJECT (demux,
        "Updating playlist %s failed, attempt to refresh variant playlist %s",
        uri, main_uri);
    download =
        gst_uri_downloader_fetch_uri (adaptive_demux->downloader,
        main_uri, NULL, TRUE, TRUE, TRUE, err);
    g_free (main_uri);
    if (download == NULL) {
      g_free (uri);
      return FALSE;
    }

    buf = gst_fragment_get_buffer (download);
    playlist = gst_hls_src_buf_to_utf8_playlist (buf);
    gst_buffer_unref (buf);

    if (playlist == NULL) {
      GST_WARNING_OBJECT (demux,
          "Failed to validate variant playlist encoding");
      g_free (uri);
      g_object_unref (download);
      g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
          "Couldn't validate playlist encoding");
      return FALSE;
    }

    g_free (uri);
    if (download->redirect_permanent && download->redirect_uri) {
      uri = download->redirect_uri;
      base_uri = NULL;
    } else {
      uri = download->uri;
      base_uri = download->redirect_uri;
    }

    if (!gst_m3u8_client_update_variant_playlist (demux->client, playlist,
            uri, base_uri)) {
      GST_WARNING_OBJECT (demux, "Failed to update the variant playlist");
      g_object_unref (download);
      g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
          "Couldn't update playlist");
      return FALSE;
    }

    g_object_unref (download);

    main_checked = TRUE;
    goto retry;
  }
  g_free (uri);

  /* Set the base URI of the playlist to the redirect target if any */
  GST_M3U8_CLIENT_LOCK (demux->client);
  g_free (demux->client->current->uri);
  g_free (demux->client->current->base_uri);
  if (download->redirect_permanent && download->redirect_uri) {
    demux->client->current->uri = g_strdup (download->redirect_uri);
    demux->client->current->base_uri = NULL;
  } else {
    demux->client->current->uri = g_strdup (download->uri);
    demux->client->current->base_uri = g_strdup (download->redirect_uri);
  }
  GST_M3U8_CLIENT_UNLOCK (demux->client);

  buf = gst_fragment_get_buffer (download);
  playlist = gst_hls_src_buf_to_utf8_playlist (buf);
  gst_buffer_unref (buf);
  g_object_unref (download);

  if (playlist == NULL) {
    GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding");
    g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
        "Couldn't validate playlist encoding");
    return FALSE;
  }

  updated = gst_m3u8_client_update (demux->client, playlist);
  if (!updated) {
    GST_WARNING_OBJECT (demux, "Couldn't update playlist");
    g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
        "Couldn't update playlist");
    return FALSE;
  }

  /* If it's a live source, do not let the sequence number go beyond
   * three fragments before the end of the list */
  if (update == FALSE && demux->client->current &&
      gst_m3u8_client_is_live (demux->client)) {
    gint64 last_sequence, first_sequence;

    GST_M3U8_CLIENT_LOCK (demux->client);
    last_sequence =
        GST_M3U8_MEDIA_FILE (g_list_last (demux->client->current->
            files)->data)->sequence;
    first_sequence =
        GST_M3U8_MEDIA_FILE (demux->client->current->files->data)->sequence;

    GST_DEBUG_OBJECT (demux,
        "sequence:%" G_GINT64_FORMAT " , first_sequence:%" G_GINT64_FORMAT
        " , last_sequence:%" G_GINT64_FORMAT, demux->client->sequence,
        first_sequence, last_sequence);
    if (demux->client->sequence >= last_sequence - 3) {
      //demux->need_segment = TRUE;
      /* Make sure we never go below the minimum sequence number */
      demux->client->sequence = MAX (first_sequence, last_sequence - 3);
      GST_DEBUG_OBJECT (demux,
          "Sequence is beyond playlist. Moving back to %" G_GINT64_FORMAT,
          demux->client->sequence);
    }
    GST_M3U8_CLIENT_UNLOCK (demux->client);
  } else if (demux->client->current && !gst_m3u8_client_is_live (demux->client)) {
    GstClockTime current_pos, target_pos;
    guint sequence = 0;
    GList *walk;

    /* Sequence numbers are not guaranteed to be the same in different
     * playlists, so get the correct fragment here based on the current
     * position
     */
    GST_M3U8_CLIENT_LOCK (demux->client);

    /* Valid because hlsdemux only has a single output */
    if (GST_ADAPTIVE_DEMUX_CAST (demux)->streams) {
      GstAdaptiveDemuxStream *stream =
          GST_ADAPTIVE_DEMUX_CAST (demux)->streams->data;
      target_pos = stream->segment.position;
    } else {
      target_pos = 0;
    }
    if (GST_CLOCK_TIME_IS_VALID (demux->client->sequence_position)) {
      target_pos = MAX (target_pos, demux->client->sequence_position);
    }

    GST_LOG_OBJECT (demux, "Looking for sequence position %"
        GST_TIME_FORMAT " in updated playlist", GST_TIME_ARGS (target_pos));

    current_pos = 0;
    for (walk = demux->client->current->files; walk; walk = walk->next) {
      GstM3U8MediaFile *file = walk->data;

      sequence = file->sequence;
      if (current_pos <= target_pos
          && target_pos < current_pos + file->duration) {
        break;
      }
      current_pos += file->duration;
    }
    /* End of playlist */
    if (!walk)
      sequence++;
    demux->client->sequence = sequence;
    demux->client->sequence_position = current_pos;
    GST_M3U8_CLIENT_UNLOCK (demux->client);
  }

  return updated;
}
Exemplo n.º 10
0
static gboolean
gst_hls_demux_change_playlist (GstHLSDemux * demux, guint max_bitrate,
    gboolean * changed)
{
  GList *previous_variant, *current_variant;
  gint old_bandwidth, new_bandwidth;
  GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX_CAST (demux);
  GstAdaptiveDemuxStream *stream;

  g_return_val_if_fail (adaptive_demux->streams != NULL, FALSE);

  stream = adaptive_demux->streams->data;

  previous_variant = demux->client->main->current_variant;
  current_variant = gst_m3u8_client_get_playlist_for_bitrate (demux->client,
      max_bitrate);

  GST_M3U8_CLIENT_LOCK (demux->client);

retry_failover_protection:
  old_bandwidth = GST_M3U8 (previous_variant->data)->bandwidth;
  new_bandwidth = GST_M3U8 (current_variant->data)->bandwidth;

  /* Don't do anything else if the playlist is the same */
  if (new_bandwidth == old_bandwidth) {
    GST_M3U8_CLIENT_UNLOCK (demux->client);
    return TRUE;
  }

  demux->client->main->current_variant = current_variant;
  GST_M3U8_CLIENT_UNLOCK (demux->client);

  gst_m3u8_client_set_current (demux->client, current_variant->data);

  GST_INFO_OBJECT (demux, "Client was on %dbps, max allowed is %dbps, switching"
      " to bitrate %dbps", old_bandwidth, max_bitrate, new_bandwidth);

  if (gst_hls_demux_update_playlist (demux, TRUE, NULL)) {
    gchar *uri;
    gchar *main_uri;
    uri = gst_m3u8_client_get_current_uri (demux->client);
    main_uri = gst_m3u8_client_get_uri (demux->client);
    gst_element_post_message (GST_ELEMENT_CAST (demux),
        gst_message_new_element (GST_OBJECT_CAST (demux),
            gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
                "manifest-uri", G_TYPE_STRING,
                main_uri, "uri", G_TYPE_STRING,
                uri, "bitrate", G_TYPE_INT, new_bandwidth, NULL)));
    g_free (uri);
    g_free (main_uri);
    if (changed)
      *changed = TRUE;
    stream->discont = TRUE;
  } else {
    GList *failover = NULL;

    GST_INFO_OBJECT (demux, "Unable to update playlist. Switching back");
    GST_M3U8_CLIENT_LOCK (demux->client);

    failover = g_list_previous (current_variant);
    if (failover && new_bandwidth == GST_M3U8 (failover->data)->bandwidth) {
      current_variant = failover;
      goto retry_failover_protection;
    }

    demux->client->main->current_variant = previous_variant;
    GST_M3U8_CLIENT_UNLOCK (demux->client);
    gst_m3u8_client_set_current (demux->client, previous_variant->data);
    /*  Try a lower bitrate (or stop if we just tried the lowest) */
    if (GST_M3U8 (previous_variant->data)->iframe && new_bandwidth ==
        GST_M3U8 (g_list_first (demux->client->main->iframe_lists)->data)->
        bandwidth)
      return FALSE;
    else if (!GST_M3U8 (previous_variant->data)->iframe && new_bandwidth ==
        GST_M3U8 (g_list_first (demux->client->main->lists)->data)->bandwidth)
      return FALSE;
    else
      return gst_hls_demux_change_playlist (demux, new_bandwidth - 1, changed);
  }

  /* Force typefinding since we might have changed media type */
  demux->do_typefind = TRUE;

  return TRUE;
}
Exemplo n.º 11
0
static gboolean
gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
{
  GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
  GSList *streams = gst_mss_manifest_get_streams (mssdemux->manifest);
  GSList *iter;
  GSList *active_streams = NULL;

  if (streams == NULL) {
    GST_INFO_OBJECT (mssdemux, "No streams found in the manifest");
    GST_ELEMENT_ERROR (mssdemux, STREAM, DEMUX,
        (_("This file contains no playable streams.")),
        ("no streams found at the Manifest"));
    return FALSE;
  }

  GST_INFO_OBJECT (mssdemux, "Activating streams");
  for (iter = streams; iter; iter = g_slist_next (iter)) {
    GstPad *srcpad = NULL;
    GstMssDemuxStream *stream = NULL;
    GstMssStream *manifeststream = iter->data;

    srcpad = _create_pad (mssdemux, manifeststream);

    if (!srcpad) {
      continue;
    }

    stream = (GstMssDemuxStream *)
        gst_adaptive_demux_stream_new (GST_ADAPTIVE_DEMUX_CAST (mssdemux),
        srcpad);
    stream->manifest_stream = manifeststream;
    gst_mss_stream_set_active (manifeststream, TRUE);
    active_streams = g_slist_prepend (active_streams, stream);
  }

  GST_INFO_OBJECT (mssdemux, "Changing max bitrate to %u",
      demux->connection_speed);
  gst_mss_manifest_change_bitrate (mssdemux->manifest, demux->connection_speed);

  for (iter = active_streams; iter; iter = g_slist_next (iter)) {
    GstMssDemuxStream *stream = iter->data;
    GstCaps *caps;
    const gchar *lang;

    caps = gst_mss_stream_get_caps (stream->manifest_stream);
    gst_adaptive_demux_stream_set_caps (GST_ADAPTIVE_DEMUX_STREAM_CAST (stream),
        create_mss_caps (stream, caps));
    gst_caps_unref (caps);

    lang = gst_mss_stream_get_lang (stream->manifest_stream);
    if (lang != NULL) {
      GstTagList *tags;

      tags = gst_tag_list_new (GST_TAG_LANGUAGE_CODE, lang, NULL);
      gst_adaptive_demux_stream_set_tags (GST_ADAPTIVE_DEMUX_STREAM_CAST
          (stream), tags);
    }
  }

  g_slist_free (active_streams);
  return TRUE;
}