Beispiel #1
0
static void
gst_hls_demux_clear_pending_data (GstHLSDemux * hlsdemux)
{
  gst_hls_demux_decrypt_end (hlsdemux);
  gst_adapter_clear (hlsdemux->pending_encrypted_data);
  gst_buffer_replace (&hlsdemux->pending_decrypted_buffer, NULL);
  gst_buffer_replace (&hlsdemux->pending_typefind_buffer, NULL);
  hlsdemux->current_offset = -1;
}
Beispiel #2
0
static GstFlowReturn
gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
    GstAdaptiveDemuxStream * stream)
{
  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
  GstFlowReturn ret = GST_FLOW_OK;

  if (hlsdemux->current_key)
    gst_hls_demux_decrypt_end (hlsdemux);

  /* ideally this should be empty, but this eos might have been
   * caused by an error on the source element */
  GST_DEBUG_OBJECT (demux, "Data still on the adapter when EOS was received"
      ": %" G_GSIZE_FORMAT, gst_adapter_available (stream->adapter));
  gst_adapter_clear (stream->adapter);

  if (stream->last_ret == GST_FLOW_OK) {
    if (hlsdemux->pending_buffer) {
      if (hlsdemux->current_key) {
        GstMapInfo info;
        gssize unpadded_size;

        /* Handle pkcs7 unpadding here */
        gst_buffer_map (hlsdemux->pending_buffer, &info, GST_MAP_READ);
        unpadded_size = info.size - info.data[info.size - 1];
        gst_buffer_unmap (hlsdemux->pending_buffer, &info);

        gst_buffer_resize (hlsdemux->pending_buffer, 0, unpadded_size);
      }

      ret =
          gst_hls_demux_handle_buffer (demux, stream, hlsdemux->pending_buffer,
          TRUE);
      hlsdemux->pending_buffer = NULL;
    }
  } else {
    if (hlsdemux->pending_buffer)
      gst_buffer_unref (hlsdemux->pending_buffer);
    hlsdemux->pending_buffer = NULL;
  }

  if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED)
    return gst_adaptive_demux_stream_advance_fragment (demux, stream,
        stream->fragment.duration);
  return ret;
}
Beispiel #3
0
static GstFlowReturn
gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
    GstAdaptiveDemuxStream * stream)
{
  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
  GstFlowReturn ret = GST_FLOW_OK;

  if (hlsdemux->current_key)
    gst_hls_demux_decrypt_end (hlsdemux);

  if (stream->last_ret == GST_FLOW_OK) {
    if (hlsdemux->pending_decrypted_buffer) {
      if (hlsdemux->current_key) {
        GstMapInfo info;
        gssize unpadded_size;

        /* Handle pkcs7 unpadding here */
        gst_buffer_map (hlsdemux->pending_decrypted_buffer, &info,
            GST_MAP_READ);
        unpadded_size = info.size - info.data[info.size - 1];
        gst_buffer_unmap (hlsdemux->pending_decrypted_buffer, &info);

        gst_buffer_resize (hlsdemux->pending_decrypted_buffer, 0,
            unpadded_size);
      }

      ret =
          gst_hls_demux_handle_buffer (demux, stream,
          hlsdemux->pending_decrypted_buffer, TRUE);
      hlsdemux->pending_decrypted_buffer = NULL;
    }
  }
  gst_hls_demux_clear_pending_data (hlsdemux);

  if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED)
    return gst_adaptive_demux_stream_advance_fragment (demux, stream,
        stream->fragment.duration);
  return ret;
}
Beispiel #4
0
static void
gst_hls_demux_reset (GstAdaptiveDemux * ademux)
{
  GstHLSDemux *demux = GST_HLS_DEMUX_CAST (ademux);

  demux->do_typefind = TRUE;
  demux->reset_pts = TRUE;

  g_free (demux->key_url);
  demux->key_url = NULL;

  if (demux->key_fragment)
    g_object_unref (demux->key_fragment);
  demux->key_fragment = NULL;

  if (demux->client) {
    gst_m3u8_client_free (demux->client);
    demux->client = NULL;
  }
  /* TODO recreated on hls only if reset was not for disposing */
  demux->client = gst_m3u8_client_new ("", NULL);

  demux->srcpad_counter = 0;
  if (demux->pending_buffer)
    gst_buffer_unref (demux->pending_buffer);
  demux->pending_buffer = NULL;
  if (demux->current_key) {
    g_free (demux->current_key);
    demux->current_key = NULL;
  }
  if (demux->current_iv) {
    g_free (demux->current_iv);
    demux->current_iv = NULL;
  }

  gst_hls_demux_decrypt_end (demux);
}
Beispiel #5
0
static gboolean
gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
{
  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  gdouble rate;
  GList *walk, *current_file = NULL;
  GstClockTime current_pos, target_pos;
  gint64 current_sequence;
  GstM3U8MediaFile *file;
  guint64 bitrate;

  gst_event_parse_seek (seek, &rate, &format, &flags, &start_type, &start,
      &stop_type, &stop);

  bitrate = gst_hls_demux_get_bitrate (hlsdemux);

  /* properly cleanup pending decryption status */
  if (flags & GST_SEEK_FLAG_FLUSH) {
    gst_hls_demux_decrypt_end (hlsdemux);
  }

  /* Use I-frame variants for trick modes */
  if (hlsdemux->client->main->iframe_lists && rate < -1.0
      && demux->segment.rate >= -1.0 && demux->segment.rate <= 1.0) {
    GError *err = NULL;

    GST_M3U8_CLIENT_LOCK (hlsdemux->client);
    /* Switch to I-frame variant */
    hlsdemux->client->main->current_variant =
        hlsdemux->client->main->iframe_lists;
    GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
    gst_m3u8_client_set_current (hlsdemux->client,
        hlsdemux->client->main->iframe_lists->data);
    gst_uri_downloader_reset (demux->downloader);
    if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
      GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
      return FALSE;
    }
    //hlsdemux->discont = TRUE;
    hlsdemux->do_typefind = TRUE;

    gst_hls_demux_change_playlist (hlsdemux, bitrate / ABS (rate), NULL);
  } else if (rate > -1.0 && rate <= 1.0 && (demux->segment.rate < -1.0
          || demux->segment.rate > 1.0)) {
    GError *err = NULL;
    GST_M3U8_CLIENT_LOCK (hlsdemux->client);
    /* Switch to normal variant */
    hlsdemux->client->main->current_variant = hlsdemux->client->main->lists;
    GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
    gst_m3u8_client_set_current (hlsdemux->client,
        hlsdemux->client->main->lists->data);
    gst_uri_downloader_reset (demux->downloader);
    if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
      GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
      return FALSE;
    }
    //hlsdemux->discont = TRUE;
    hlsdemux->do_typefind = TRUE;
    /* TODO why not continue using the same? that was being used up to now? */
    gst_hls_demux_change_playlist (hlsdemux, bitrate, NULL);
  }

  GST_M3U8_CLIENT_LOCK (hlsdemux->client);
  file = GST_M3U8_MEDIA_FILE (hlsdemux->client->current->files->data);
  current_sequence = file->sequence;
  current_pos = 0;
  target_pos = rate > 0 ? start : stop;
  /* FIXME: Here we need proper discont handling */
  for (walk = hlsdemux->client->current->files; walk; walk = walk->next) {
    file = walk->data;

    current_sequence = file->sequence;
    current_file = walk;
    if (current_pos <= target_pos && target_pos < current_pos + file->duration) {
      break;
    }
    current_pos += file->duration;
  }

  if (walk == NULL) {
    GST_DEBUG_OBJECT (demux, "seeking further than track duration");
    current_sequence++;
  }

  GST_DEBUG_OBJECT (demux, "seeking to sequence %u", (guint) current_sequence);
  hlsdemux->reset_pts = TRUE;
  hlsdemux->client->sequence = current_sequence;
  hlsdemux->client->current_file =
      current_file ? current_file : hlsdemux->client->current->files;
  hlsdemux->client->sequence_position = current_pos;
  GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);

  return TRUE;
}