Beispiel #1
0
void test_no_lock()
{
  GstTask *t;
  gboolean ret;
    //xmlfile = "test_no_lock";
 std_log(LOG_FILENAME_LINE, "Test Started test_no_lock");

  t = gst_task_create (task_func, NULL);
  fail_if (t == NULL);
  TEST_ASSERT_FAIL

  /* stop should be possible without lock */
  gst_task_stop (t);
  /* pause should give a warning */
  ASSERT_WARNING (ret = gst_task_pause (t));   //b failing
   fail_unless (ret == FALSE);
    TEST_ASSERT_FAIL
    /* start should give a warning */
  ASSERT_WARNING (ret = gst_task_start (t));
  fail_unless (ret == FALSE);
   TEST_ASSERT_FAIL
     /* stop should be possible without lock */
  gst_task_stop (t);
  gst_object_unref (t);
  std_log(LOG_FILENAME_LINE, "Test Successful");
    create_xml(0);
}
Beispiel #2
0
static void gst_amlvdec_polling_eos (GstAmlVdec *amlvdec)
{
    unsigned rp_move_count = 40,count=0;
    struct buf_status vbuf;
    unsigned last_rp = 0;
    int ret=1;	
    do {
	  if(count>2000)//avoid infinite loop
	      break;	
        ret = codec_get_vbuf_state(amlvdec->pcodec, &vbuf);
        if (ret != 0) {
            GST_ERROR("codec_get_vbuf_state error: %x\n", -ret);
            break;
        }
        if(last_rp != vbuf.read_pointer){
            last_rp = vbuf.read_pointer;
            rp_move_count = 200;
        }else
            rp_move_count--;        
        usleep(1000*30);
        count++;	

     /*   if(amlvdec->passthrough) {
          break;
        }*/
    } while (vbuf.data_len > 0x100 && rp_move_count > 0);
   // amlvdec->passthrough = FALSE;
    //gst_pad_push_event (amlvdec->srcpad, gst_event_new_eos ());
    gst_task_pause (amlvdec->eos_task);

}
Beispiel #3
0
void test_lock()
{
  GstTask *t;
  gboolean ret;
    //xmlfile = "test_lock";
 std_log(LOG_FILENAME_LINE, "Test Started test_lock");

  t = gst_task_create (task_func, NULL);
  fail_if (t == NULL);
  TEST_ASSERT_FAIL

  gst_task_set_lock (t, &task_mutex);

  GST_DEBUG ("pause");
  ret = gst_task_pause (t);
  fail_unless (ret == TRUE);
  TEST_ASSERT_FAIL

  g_usleep (1 * G_USEC_PER_SEC / 2);

  GST_DEBUG ("joining");
  ret = gst_task_join (t);
  fail_unless (ret == TRUE);
  TEST_ASSERT_FAIL

  g_usleep (1 * G_USEC_PER_SEC / 2);

  gst_object_unref (t);
  std_log(LOG_FILENAME_LINE, "Test Successful");
    create_xml(0);
}
static void
gst_ss_demux_stream_loop (GstSSDemux * demux)
{
  GThread *self = NULL;
  int stream_type = 0;
  GstSSDemuxStream *stream = NULL;

  self = g_thread_self ();

  for (stream_type = 0; stream_type < SS_STREAM_NUM; stream_type++) {
    if (demux->streams[stream_type]->stream_task->abidata.ABI.thread == self) {
      stream = demux->streams[stream_type];
      break;
    }
  }

  /* download next fragment of stream_type */
  if (!gst_ss_demux_get_next_fragment (demux, stream_type)) {
    GST_ERROR_OBJECT (demux, "failed to get next fragment...");
    goto error;
  }

  return;

error:
  {
    gst_task_pause (stream->stream_task);
    GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
          ("could not download fragments"), (NULL));
      gst_ss_demux_stop (demux, stream);
    return;
  }
}
/*
 * Decrement the reference count on the curl multi loop. If this is called by
 * the last instance to hold a reference, shut down the worker. (Otherwise
 * GStreamer can't close down with a thread still running). Also offers the
 * "force_all" boolean parameter, which if TRUE removes all references and shuts
 * down.
 */
void
gst_curl_multi_context_unref (GstCurlMultiContext * thiz)
{
  g_mutex_lock(&thiz->mutex);
  thiz->refcount--;
  GST_INFO ("Worker thread refcount is now %u", thiz->refcount);

  if (thiz->refcount <= 0) {
    /* Everything's done! Clean up. */
    gst_task_pause (thiz->task);
    g_cond_signal (&thiz->signal);
    g_mutex_unlock (&thiz->mutex);
    gst_task_join (thiz->task);
  } else {
    g_mutex_unlock(&thiz->mutex);
  }
}
Beispiel #6
0
static void
gst_hls_demux_loop (GstHLSDemux * demux)
{
  GstBuffer *buf;
  GstFlowReturn ret;

  /* Loop for the source pad task. The task is started when we have
   * received the main playlist from the source element. It tries first to
   * cache the first fragments and then it waits until it has more data in the
   * queue. This task is woken up when we push a new fragment to the queue or
   * when we reached the end of the playlist  */

  if (G_UNLIKELY (demux->need_cache)) {
    if (!gst_hls_demux_cache_fragments (demux))
      goto cache_error;

    /* we can start now the updates thread */
    gst_hls_demux_start_update (demux);
    GST_INFO_OBJECT (demux, "First fragments cached successfully");
  }

  if (g_queue_is_empty (demux->queue)) {
    if (demux->end_of_playlist)
      goto end_of_playlist;

    goto empty_queue;
  }

  buf = g_queue_pop_head (demux->queue);

  /* Figure out if we need to create/switch pads */
  if (G_UNLIKELY (!demux->srcpad
          || GST_BUFFER_CAPS (buf) != GST_PAD_CAPS (demux->srcpad)
          || demux->need_segment)) {
    switch_pads (demux, GST_BUFFER_CAPS (buf));
    demux->need_segment = TRUE;
  }
  if (demux->need_segment) {
    /* And send a newsegment */
    GST_DEBUG_OBJECT (demux, "Sending new-segment. Segment start:%"
        GST_TIME_FORMAT, GST_TIME_ARGS (demux->position));
    gst_pad_push_event (demux->srcpad,
        gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, demux->position,
            GST_CLOCK_TIME_NONE, demux->position));
    demux->need_segment = FALSE;
  }

  if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buf)))
    demux->position += GST_BUFFER_DURATION (buf);

  ret = gst_pad_push (demux->srcpad, buf);
  if (ret != GST_FLOW_OK)
    goto error;

  return;

end_of_playlist:
  {
    GST_DEBUG_OBJECT (demux, "Reached end of playlist, sending EOS");
    gst_pad_push_event (demux->srcpad, gst_event_new_eos ());
    gst_hls_demux_stop (demux);
    return;
  }

cache_error:
  {
    gst_task_pause (demux->task);
    if (!demux->cancelled) {
      GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
          ("Could not cache the first fragments"), (NULL));
      gst_hls_demux_stop (demux);
    }
    return;
  }

error:
  {
    /* FIXME: handle error */
    GST_DEBUG_OBJECT (demux, "error, stopping task");
    gst_hls_demux_stop (demux);
    return;
  }

empty_queue:
  {
    gst_task_pause (demux->task);
    return;
  }
}
Beispiel #7
0
static gboolean
gst_hls_demux_src_event (GstPad * pad, GstEvent * event)
{
  GstHLSDemux *demux;

  demux = GST_HLS_DEMUX (gst_pad_get_element_private (pad));

  switch (event->type) {
    case GST_EVENT_SEEK:
    {
      gdouble rate;
      GstFormat format;
      GstSeekFlags flags;
      GstSeekType start_type, stop_type;
      gint64 start, stop;
      GList *walk;
      gint current_pos;
      gint current_sequence;
      gint target_second;
      GstM3U8MediaFile *file;

      GST_INFO_OBJECT (demux, "Received GST_EVENT_SEEK");

      if (gst_m3u8_client_is_live (demux->client)) {
        GST_WARNING_OBJECT (demux, "Received seek event for live stream");
        return FALSE;
      }

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

      if (format != GST_FORMAT_TIME)
        return FALSE;

      GST_DEBUG_OBJECT (demux, "seek event, rate: %f start: %" GST_TIME_FORMAT
          " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
          GST_TIME_ARGS (stop));

      file = GST_M3U8_MEDIA_FILE (demux->client->current->files->data);
      current_sequence = file->sequence;
      current_pos = 0;
      target_second = start / GST_SECOND;
      GST_DEBUG_OBJECT (demux, "Target seek to %d", target_second);
      for (walk = demux->client->current->files; walk; walk = walk->next) {
        file = walk->data;

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

      if (walk == NULL) {
        GST_WARNING_OBJECT (demux, "Could not find seeked fragment");
        return FALSE;
      }

      if (flags & GST_SEEK_FLAG_FLUSH) {
        GST_DEBUG_OBJECT (demux, "sending flush start");
        gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ());
      }

      demux->cancelled = TRUE;
      gst_task_pause (demux->task);
      g_mutex_lock (demux->fetcher_lock);
      gst_hls_demux_stop_fetcher (demux, TRUE);
      g_mutex_unlock (demux->fetcher_lock);
      g_mutex_lock (demux->thread_lock);
      g_cond_signal (demux->thread_cond);
      g_mutex_unlock (demux->thread_lock);
      gst_task_pause (demux->task);

      /* wait for streaming to finish */
      g_static_rec_mutex_lock (&demux->task_lock);

      demux->need_cache = TRUE;
      while (!g_queue_is_empty (demux->queue)) {
        GstBuffer *buf = g_queue_pop_head (demux->queue);
        gst_buffer_unref (buf);
      }

      GST_DEBUG_OBJECT (demux, "seeking to sequence %d", current_sequence);
      demux->client->sequence = current_sequence;
      demux->position = start;
      demux->need_segment = TRUE;

      if (flags & GST_SEEK_FLAG_FLUSH) {
        GST_DEBUG_OBJECT (demux, "sending flush stop");
        gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ());
      }

      demux->cancelled = FALSE;
      gst_task_start (demux->task);
      g_static_rec_mutex_unlock (&demux->task_lock);

      return TRUE;
    }
    default:
      break;
  }

  return gst_pad_event_default (pad, event);
}
Beispiel #8
0
static void
task_monitor_alsa (gpointer data)
{
  struct pollfd *pfds;
  unsigned int nfds, rnfds;
  unsigned short revents;
  GstAlsaMixer *mixer = (GstAlsaMixer *) data;
  gint ret;

  g_static_rec_mutex_lock (mixer->rec_mutex);

  nfds = snd_mixer_poll_descriptors_count (mixer->handle);
  if (nfds <= 0) {
    GST_ERROR ("snd_mixer_poll_descriptors_count <= 0: %d", nfds);
    /* FIXME: sleep ? stop monitoring ? */
    g_static_rec_mutex_unlock (mixer->rec_mutex);
    return;
  }

  pfds = g_newa (struct pollfd, nfds + 1);
  rnfds = snd_mixer_poll_descriptors (mixer->handle, pfds, nfds);
  g_assert (rnfds <= nfds);

  if (rnfds < 0) {
    GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), ("alsa error: %s",
            snd_strerror (rnfds)));
    gst_task_pause (mixer->task);
    g_static_rec_mutex_unlock (mixer->rec_mutex);
    return;
  }

  pfds[rnfds].fd = mixer->pfd[0];
  pfds[rnfds].events = POLLIN | POLLPRI | POLLHUP | POLLERR;
  pfds[rnfds].revents = 0;

  g_static_rec_mutex_unlock (mixer->rec_mutex);

  GST_LOG ("task loop");
  ret = poll (pfds, rnfds + 1, -1);

  if (ret < 0) {
    GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
    gst_task_pause (mixer->task);
    return;
  }

  g_static_rec_mutex_lock (mixer->rec_mutex);

  ret =
      snd_mixer_poll_descriptors_revents (mixer->handle, pfds, nfds, &revents);
  if (ret < 0) {
    GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), ("alsa error: %s",
            snd_strerror (ret)));
    gst_task_pause (mixer->task);
  } else if (revents & (POLLIN | POLLPRI)) {
    GST_DEBUG ("Handling events");
    snd_mixer_handle_events (mixer->handle);
  } else if (revents & (POLLERR | POLLNVAL | POLLHUP)) {
    GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), (NULL));
    gst_task_pause (mixer->task);
  }

  g_static_rec_mutex_unlock (mixer->rec_mutex);
}
static void
gst_decklink_src_task (void *priv)
{
  GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (priv);
  GstBuffer *buffer;
  GstBuffer *audio_buffer;
  IDeckLinkVideoInputFrame *video_frame;
  IDeckLinkAudioInputPacket *audio_frame;
  void *data;
  gsize data_size;
  int n_samples;
  GstFlowReturn ret;
  const GstDecklinkMode *mode;
  gboolean discont = FALSE;

  GST_DEBUG_OBJECT (decklinksrc, "task");

  g_mutex_lock (&decklinksrc->mutex);
  while (decklinksrc->video_frame == NULL && !decklinksrc->stop) {
    g_cond_wait (&decklinksrc->cond, &decklinksrc->mutex);
  }
  video_frame = decklinksrc->video_frame;
  audio_frame = decklinksrc->audio_frame;
  decklinksrc->video_frame = NULL;
  decklinksrc->audio_frame = NULL;
  g_mutex_unlock (&decklinksrc->mutex);

  if (decklinksrc->stop) {
    if (video_frame)
      video_frame->Release ();
    if (audio_frame)
      audio_frame->Release ();
    GST_DEBUG ("stopping task");
    return;
  }

  /* warning on dropped frames */
  /* FIXME: post QoS message */
  if (decklinksrc->dropped_frames - decklinksrc->dropped_frames_old > 0) {
    GST_ELEMENT_WARNING (decklinksrc, RESOURCE, READ,
        ("Dropped %d frame(s), for a total of %d frame(s)",
            decklinksrc->dropped_frames - decklinksrc->dropped_frames_old,
            decklinksrc->dropped_frames), (NULL));
    decklinksrc->dropped_frames_old = decklinksrc->dropped_frames;
    /* FIXME: discont = TRUE; ? */
  }

  if (!decklinksrc->started) {
    gst_decklink_src_send_initial_events (decklinksrc);
    decklinksrc->started = TRUE;
  }

  mode = gst_decklink_get_mode (decklinksrc->mode);

  video_frame->GetBytes (&data);

  data_size = mode->width * mode->height * 2;

  if (decklinksrc->copy_data) {
    buffer = gst_buffer_new_and_alloc (data_size);

    gst_buffer_fill (buffer, 0, data, data_size);

    video_frame->Release ();
  } else {
    VideoFrame *vf;

    vf = (VideoFrame *) g_malloc0 (sizeof (VideoFrame));

    buffer = gst_buffer_new_wrapped_full ((GstMemoryFlags) 0, data, data_size,
        0, data_size, vf, (GDestroyNotify) video_frame_free);

    vf->frame = video_frame;
    vf->input = decklinksrc->input;
    vf->input->AddRef ();
  }

  GST_BUFFER_TIMESTAMP (buffer) =
      gst_util_uint64_scale_int (decklinksrc->frame_num * GST_SECOND,
      mode->fps_d, mode->fps_n);
  GST_BUFFER_DURATION (buffer) =
      gst_util_uint64_scale_int ((decklinksrc->frame_num + 1) * GST_SECOND,
      mode->fps_d, mode->fps_n) - GST_BUFFER_TIMESTAMP (buffer);
  GST_BUFFER_OFFSET (buffer) = decklinksrc->frame_num;
  GST_BUFFER_OFFSET_END (buffer) = decklinksrc->frame_num; /* FIXME: +1? */

  /* FIXME: set video meta */

  if (decklinksrc->frame_num == 0)
    discont = TRUE;

  if (discont)
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
  else
    GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);

  /* FIXME: proper flow aggregation with audio flow */
  ret = gst_pad_push (decklinksrc->videosrcpad, buffer);
  if (!(ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED ||
          ret == GST_FLOW_FLUSHING)) {
    GST_ELEMENT_ERROR (decklinksrc, STREAM, FAILED,
        ("Internal data stream error."),
        ("stream stopped, reason %s", gst_flow_get_name (ret)));
      goto pause;
  }

  if (gst_pad_is_linked (decklinksrc->audiosrcpad)) {
    n_samples = audio_frame->GetSampleFrameCount ();
    audio_frame->GetBytes (&data);
    audio_buffer = gst_buffer_new_and_alloc (n_samples * 2 * 2);
    gst_buffer_fill (audio_buffer, 0, data, n_samples * 2 * 2);

    GST_BUFFER_TIMESTAMP (audio_buffer) =
        gst_util_uint64_scale_int (decklinksrc->num_audio_samples * GST_SECOND,
        1, 48000);
    /* FIXME: should be next_timestamp - timestamp for perfect stream */
    GST_BUFFER_DURATION (audio_buffer) =
        gst_util_uint64_scale_int (n_samples * GST_SECOND, 1, 48000);
    GST_BUFFER_OFFSET (audio_buffer) = decklinksrc->num_audio_samples;
    GST_BUFFER_OFFSET_END (audio_buffer) =
        GST_BUFFER_OFFSET (audio_buffer) + n_samples;

    decklinksrc->num_audio_samples += n_samples;

  /* FIXME: proper flow aggregation with video flow */
    ret = gst_pad_push (decklinksrc->audiosrcpad, audio_buffer);
    if (!(ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED ||
            ret == GST_FLOW_FLUSHING)) {
      GST_ELEMENT_ERROR (decklinksrc, STREAM, FAILED,
          ("Internal data stream error."),
          ("stream stopped, reason %s", gst_flow_get_name (ret)));
      goto pause;
    }
  }

done:

  if (audio_frame)
    audio_frame->Release ();

  return;

pause:
  {
    const gchar *reason = gst_flow_get_name (ret);
    GstEvent *event = NULL;

    GST_DEBUG_OBJECT (decklinksrc, "pausing task, reason %s", reason);
    gst_task_pause (decklinksrc->task);
    if (ret == GST_FLOW_EOS) {
      /* perform EOS logic (very crude, we don't even keep a GstSegment) */
      event = gst_event_new_eos ();
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      event = gst_event_new_eos ();
      /* for fatal errors we post an error message, post the error
       * first so the app knows about the error first.
       * Also don't do this for FLUSHING because it happens
       * due to flushing and posting an error message because of
       * that is the wrong thing to do, e.g. when we're doing
       * a flushing seek. */
      GST_ELEMENT_ERROR (decklinksrc, STREAM, FAILED,
          ("Internal data flow error."),
          ("streaming task paused, reason %s (%d)", reason, ret));
    }
    if (event != NULL) {
      GST_INFO_OBJECT (decklinksrc->videosrcpad, "pushing EOS event");
      gst_pad_push_event (decklinksrc->videosrcpad, gst_event_ref (event));
      GST_INFO_OBJECT (decklinksrc->audiosrcpad, "pushing EOS event");
      gst_pad_push_event (decklinksrc->audiosrcpad, event);
    }
    goto done;
  }
}
Beispiel #10
0
static GstStateChangeReturn
gst_swfdec_change_state (GstElement * element, GstStateChange transition)
{
  GstSwfdec *swfdec = GST_SWFDEC (element);
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
    {
      gst_adapter_clear (swfdec->adapter);
      /*
         gst_swfdec_vo_open (swfdec);
         swfdec_decoder_new (swfdec->decoder, swfdec->accel, swfdec->vo);

         swfdec->decoder->is_sequence_needed = 1;
         swfdec->decoder->frame_rate_code = 0;
       */
      swfdec->timestamp = 0;
      swfdec->closed = FALSE;

      /* reset the initial video state */
      swfdec->have_format = FALSE;
      swfdec->format = -1;
      swfdec->width = -1;
      swfdec->height = -1;
      swfdec->first = TRUE;
      break;
    }
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
      gst_task_start (swfdec->task);
      break;
    default:
      break;
  }

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

  switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      gst_task_pause (swfdec->task);
      gst_task_join (swfdec->task);
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      /* if we are not closed by an EOS event do so now, this cen send a few frames but
       * we are prepared to not really send them (see above) */
      if (!swfdec->closed) {
        /*swf_close (swfdec->decoder); */
        swfdec->closed = TRUE;
      }
      /* gst_swfdec_vo_destroy (swfdec); */
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      gst_task_stop (swfdec->task);
      gst_task_join (swfdec->task);
      break;
    default:
      break;
  }

  return ret;

}
Beispiel #11
0
static void
gst_hls_demux_stream_loop (GstHLSDemux * demux)
{
  GstFragment *fragment;
  GstBuffer *buf;
  GstFlowReturn ret;
  GstCaps *bufcaps, *srccaps = NULL;

  /* Loop for the source pad task. The task is started when we have
   * received the main playlist from the source element. It tries first to
   * cache the first fragments and then it waits until it has more data in the
   * queue. This task is woken up when we push a new fragment to the queue or
   * when we reached the end of the playlist  */

  if (G_UNLIKELY (demux->need_cache)) {
    if (!gst_hls_demux_cache_fragments (demux))
      goto cache_error;

    /* we can start now the updates thread (only if on playing) */
    if (GST_STATE (demux) == GST_STATE_PLAYING)
      gst_task_start (demux->updates_task);
    GST_INFO_OBJECT (demux, "First fragments cached successfully");
  }

  if (g_queue_is_empty (demux->queue)) {
    if (demux->end_of_playlist)
      goto end_of_playlist;

    goto pause_task;
  }

  fragment = g_queue_pop_head (demux->queue);
  buf = gst_fragment_get_buffer (fragment);

  /* Figure out if we need to create/switch pads */
  if (G_LIKELY (demux->srcpad))
    srccaps = gst_pad_get_current_caps (demux->srcpad);
  bufcaps = gst_fragment_get_caps (fragment);
  if (G_UNLIKELY (!srccaps || !gst_caps_is_equal_fixed (bufcaps, srccaps)
          || demux->need_segment)) {
    switch_pads (demux, bufcaps);
    demux->need_segment = TRUE;
  }
  gst_caps_unref (bufcaps);
  if (G_LIKELY (srccaps))
    gst_caps_unref (srccaps);
  g_object_unref (fragment);

  if (demux->need_segment) {
    GstSegment segment;
    GstClockTime start = GST_BUFFER_PTS (buf);

    start += demux->position_shift;
    /* And send a newsegment */
    GST_DEBUG_OBJECT (demux, "Sending new-segment. segment start:%"
        GST_TIME_FORMAT, GST_TIME_ARGS (start));
    gst_segment_init (&segment, GST_FORMAT_TIME);
    segment.start = start;
    segment.time = start;
    gst_pad_push_event (demux->srcpad, gst_event_new_segment (&segment));
    demux->need_segment = FALSE;
    demux->position_shift = 0;
  }

  ret = gst_pad_push (demux->srcpad, buf);
  if (ret != GST_FLOW_OK)
    goto error_pushing;

  return;

end_of_playlist:
  {
    GST_DEBUG_OBJECT (demux, "Reached end of playlist, sending EOS");
    gst_pad_push_event (demux->srcpad, gst_event_new_eos ());
    gst_hls_demux_stop (demux);
    return;
  }

cache_error:
  {
    gst_task_pause (demux->stream_task);
    if (!demux->cancelled) {
      GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
          ("Could not cache the first fragments"), (NULL));
      gst_hls_demux_stop (demux);
    }
    return;
  }

error_pushing:
  {
    /* FIXME: handle error */
    GST_DEBUG_OBJECT (demux, "Error pushing buffer: %s... stopping task",
        gst_flow_get_name (ret));
    gst_hls_demux_stop (demux);
    return;
  }

pause_task:
  {
    gst_task_pause (demux->stream_task);
    return;
  }
}
Beispiel #12
0
static gboolean
gst_hls_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstHLSDemux *demux;

  demux = GST_HLS_DEMUX (parent);

  switch (event->type) {
    case GST_EVENT_SEEK:
    {
      gdouble rate;
      GstFormat format;
      GstSeekFlags flags;
      GstSeekType start_type, stop_type;
      gint64 start, stop;
      GList *walk;
      GstClockTime position, current_pos, target_pos;
      gint current_sequence;
      GstM3U8MediaFile *file;

      GST_INFO_OBJECT (demux, "Received GST_EVENT_SEEK");

      if (gst_m3u8_client_is_live (demux->client)) {
        GST_WARNING_OBJECT (demux, "Received seek event for live stream");
        return FALSE;
      }

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

      if (format != GST_FORMAT_TIME)
        return FALSE;

      GST_DEBUG_OBJECT (demux, "seek event, rate: %f start: %" GST_TIME_FORMAT
          " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
          GST_TIME_ARGS (stop));

      GST_M3U8_CLIENT_LOCK (demux->client);
      file = GST_M3U8_MEDIA_FILE (demux->client->current->files->data);
      current_sequence = file->sequence;
      current_pos = 0;
      target_pos = (GstClockTime) start;
      for (walk = demux->client->current->files; walk; walk = walk->next) {
        file = walk->data;

        current_sequence = file->sequence;
        if (current_pos <= target_pos
            && target_pos < current_pos + file->duration) {
          break;
        }
        current_pos += file->duration;
      }
      GST_M3U8_CLIENT_UNLOCK (demux->client);

      if (walk == NULL) {
        GST_WARNING_OBJECT (demux, "Could not find seeked fragment");
        return FALSE;
      }

      if (flags & GST_SEEK_FLAG_FLUSH) {
        GST_DEBUG_OBJECT (demux, "sending flush start");
        gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ());
      }

      demux->cancelled = TRUE;
      gst_task_pause (demux->stream_task);
      gst_uri_downloader_cancel (demux->downloader);
      gst_task_stop (demux->updates_task);
      gst_task_pause (demux->stream_task);

      /* wait for streaming to finish */
      g_rec_mutex_lock (&demux->stream_lock);

      demux->need_cache = TRUE;
      while (!g_queue_is_empty (demux->queue)) {
        GstFragment *fragment = g_queue_pop_head (demux->queue);
        g_object_unref (fragment);
      }
      g_queue_clear (demux->queue);

      GST_M3U8_CLIENT_LOCK (demux->client);
      GST_DEBUG_OBJECT (demux, "seeking to sequence %d", current_sequence);
      demux->client->sequence = current_sequence;
      gst_m3u8_client_get_current_position (demux->client, &position);
      demux->position_shift = start - position;
      demux->need_segment = TRUE;
      GST_M3U8_CLIENT_UNLOCK (demux->client);


      if (flags & GST_SEEK_FLAG_FLUSH) {
        GST_DEBUG_OBJECT (demux, "sending flush stop");
        gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop (TRUE));
      }

      demux->cancelled = FALSE;
      gst_task_start (demux->stream_task);
      g_rec_mutex_unlock (&demux->stream_lock);

      return TRUE;
    }
    default:
      break;
  }

  return gst_pad_event_default (pad, parent, event);
}