Esempio n. 1
0
static gboolean
gst_sub_parse_src_event (GstPad * pad, GstEvent * event)
{
  GstSubParse *self = GST_SUBPARSE (gst_pad_get_parent (pad));
  gboolean ret = FALSE;

  GST_DEBUG ("Handling %s event", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      GstFormat format;
      GstSeekType start_type, stop_type;
      gint64 start, stop;
      gdouble rate;
      gboolean update;

      gst_event_parse_seek (event, &rate, &format, &self->segment_flags,
          &start_type, &start, &stop_type, &stop);

      if (format != GST_FORMAT_TIME) {
        GST_WARNING_OBJECT (self, "we only support seeking in TIME format");
        gst_event_unref (event);
        goto beach;
      }

      /* Convert that seek to a seeking in bytes at position 0,
         FIXME: could use an index */
      ret = gst_pad_push_event (self->sinkpad,
          gst_event_new_seek (rate, GST_FORMAT_BYTES, self->segment_flags,
              GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0));

      if (ret) {
        /* Apply the seek to our segment */
        gst_segment_set_seek (&self->segment, rate, format, self->segment_flags,
            start_type, start, stop_type, stop, &update);

        GST_DEBUG_OBJECT (self, "segment after seek: %" GST_SEGMENT_FORMAT,
            &self->segment);

        self->next_offset = 0;

        self->need_segment = TRUE;
      } else {
        GST_WARNING_OBJECT (self, "seek to 0 bytes failed");
      }

      gst_event_unref (event);
      break;
    }
    default:
      ret = gst_pad_event_default (pad, event);
      break;
  }

beach:
  gst_object_unref (self);

  return ret;
}
Esempio n. 2
0
static gboolean
gst_mms_prepare_seek_segment (GstBaseSrc * src, GstEvent * event,
    GstSegment * segment)
{
  GstSeekType cur_type, stop_type;
  gint64 cur, stop;
  GstSeekFlags flags;
  GstFormat seek_format;
  gdouble rate;

  gst_event_parse_seek (event, &rate, &seek_format, &flags,
      &cur_type, &cur, &stop_type, &stop);

  if (seek_format != GST_FORMAT_BYTES && seek_format != GST_FORMAT_TIME) {
    GST_LOG_OBJECT (src, "Only byte or time seeking is supported");
    return FALSE;
  }

  if (stop_type != GST_SEEK_TYPE_NONE) {
    GST_LOG_OBJECT (src, "Stop seeking not supported");
    return FALSE;
  }

  if (cur_type != GST_SEEK_TYPE_NONE && cur_type != GST_SEEK_TYPE_SET) {
    GST_LOG_OBJECT (src, "Only absolute seeking is supported");
    return FALSE;
  }

  /* We would like to convert from GST_FORMAT_TIME to GST_FORMAT_BYTES here
     when needed, but we cannot as to do that we need to actually do the seek,
     so we handle this in do_seek instead. */

  /* FIXME implement relative seeking, we could do any needed relevant
     seeking calculations here (in seek_format metrics), before the re-init
     of the segment. */

  gst_segment_init (segment, seek_format);
  gst_segment_set_seek (segment, rate, seek_format, flags, cur_type, cur,
      stop_type, stop, NULL);

  return TRUE;
}
Esempio n. 3
0
static gboolean
gst_rtmp_src_prepare_seek_segment (GstBaseSrc * basesrc, GstEvent * event,
    GstSegment * segment)
{
  GstRTMPSrc *src;
  GstSeekType cur_type, stop_type;
  gint64 cur, stop;
  GstSeekFlags flags;
  GstFormat format;
  gdouble rate;

  src = GST_RTMP_SRC (basesrc);

  gst_event_parse_seek (event, &rate, &format, &flags,
      &cur_type, &cur, &stop_type, &stop);

  if (!src->seekable) {
    GST_LOG_OBJECT (src, "Not a seekable stream");
    return FALSE;
  }

  if (!src->rtmp) {
    GST_LOG_OBJECT (src, "Not connected yet");
    return FALSE;
  }

  if (format != GST_FORMAT_TIME) {
    GST_LOG_OBJECT (src, "Seeking only supported in TIME format");
    return FALSE;
  }

  if (stop_type != GST_SEEK_TYPE_NONE) {
    GST_LOG_OBJECT (src, "Setting a stop position is not supported");
    return FALSE;
  }

  gst_segment_init (segment, GST_FORMAT_TIME);
  gst_segment_set_seek (segment, rate, format, flags, cur_type, cur, stop_type,
      stop, NULL);

  return TRUE;
}
Esempio n. 4
0
static gboolean
gst_mms_do_seek (GstBaseSrc * src, GstSegment * segment)
{
  mms_off_t start;
  GstMMS *mmssrc = GST_MMS (src);

  if (segment->format == GST_FORMAT_TIME) {
    if (!mmsx_time_seek (NULL, mmssrc->connection,
            (double) segment->start / GST_SECOND)) {
      GST_LOG_OBJECT (mmssrc, "mmsx_time_seek() failed");
      return FALSE;
    }
    start = mmsx_get_current_pos (mmssrc->connection);
    GST_INFO_OBJECT (mmssrc, "sought to %" GST_TIME_FORMAT ", offset after "
        "seek: %" G_GINT64_FORMAT, GST_TIME_ARGS (segment->start), start);
  } else if (segment->format == GST_FORMAT_BYTES) {
    start = mmsx_seek (NULL, mmssrc->connection, segment->start, SEEK_SET);
    /* mmsx_seek will close and reopen the connection when seeking with the
       mmsh protocol, if the reopening fails this is indicated with -1 */
    if (start == -1) {
      GST_DEBUG_OBJECT (mmssrc, "connection broken during seek");
      return FALSE;
    }
    GST_INFO_OBJECT (mmssrc, "sought to: %" G_GINT64_FORMAT " bytes, "
        "result: %" G_GINT64_FORMAT, segment->start, start);
  } else {
    GST_DEBUG_OBJECT (mmssrc, "unsupported seek segment format: %s",
        GST_STR_NULL (gst_format_get_name (segment->format)));
    return FALSE;
  }
  gst_segment_init (segment, GST_FORMAT_BYTES);
  gst_segment_set_seek (segment, segment->rate, GST_FORMAT_BYTES,
      segment->flags, GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_NONE,
      segment->stop, NULL);
  return TRUE;
}
Esempio n. 5
0
/* This function is used to perform seeks on the element in
 * pull mode.
 *
 * It also works when event is NULL, in which case it will just
 * start from the last configured segment. This technique is
 * used when activating the element and to perform the seek in
 * READY.
 */
static gboolean
gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
{
  gboolean res;
  gdouble rate;
  GstFormat format, bformat;
  GstSeekFlags flags;
  GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
  gint64 cur, stop, upstream_size;
  gboolean flush;
  gboolean update;
  GstSegment seeksegment = { 0, };
  gint64 last_stop;

  if (event) {
    GST_DEBUG_OBJECT (aiff, "doing seek with event");

    gst_event_parse_seek (event, &rate, &format, &flags,
        &cur_type, &cur, &stop_type, &stop);

    /* no negative rates yet */
    if (rate < 0.0)
      goto negative_rate;

    if (format != aiff->segment.format) {
      GST_INFO_OBJECT (aiff, "converting seek-event from %s to %s",
          gst_format_get_name (format),
          gst_format_get_name (aiff->segment.format));
      res = TRUE;
      if (cur_type != GST_SEEK_TYPE_NONE)
        res =
            gst_pad_query_convert (aiff->srcpad, format, cur,
            &aiff->segment.format, &cur);
      if (res && stop_type != GST_SEEK_TYPE_NONE)
        res =
            gst_pad_query_convert (aiff->srcpad, format, stop,
            &aiff->segment.format, &stop);
      if (!res)
        goto no_format;

      format = aiff->segment.format;
    }
  } else {
    GST_DEBUG_OBJECT (aiff, "doing seek without event");
    flags = 0;
    rate = 1.0;
    cur_type = GST_SEEK_TYPE_SET;
    stop_type = GST_SEEK_TYPE_SET;
  }

  /* get flush flag */
  flush = flags & GST_SEEK_FLAG_FLUSH;

  /* now we need to make sure the streaming thread is stopped. We do this by
   * either sending a FLUSH_START event downstream which will cause the
   * streaming thread to stop with a WRONG_STATE.
   * For a non-flushing seek we simply pause the task, which will happen as soon
   * as it completes one iteration (and thus might block when the sink is
   * blocking in preroll). */
  if (flush) {
    GST_DEBUG_OBJECT (aiff, "sending flush start");
    gst_pad_push_event (aiff->srcpad, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (aiff->sinkpad);
  }

  /* we should now be able to grab the streaming thread because we stopped it
   * with the above flush/pause code */
  GST_PAD_STREAM_LOCK (aiff->sinkpad);

  /* save current position */
  last_stop = aiff->segment.last_stop;

  GST_DEBUG_OBJECT (aiff, "stopped streaming at %" G_GINT64_FORMAT, last_stop);

  /* copy segment, we need this because we still need the old
   * segment when we close the current segment. */
  memcpy (&seeksegment, &aiff->segment, sizeof (GstSegment));

  /* configure the seek parameters in the seeksegment. We will then have the
   * right values in the segment to perform the seek */
  if (event) {
    GST_DEBUG_OBJECT (aiff, "configuring seek");
    gst_segment_set_seek (&seeksegment, rate, format, flags,
        cur_type, cur, stop_type, stop, &update);
  }

  /* figure out the last position we need to play. If it's configured (stop !=
   * -1), use that, else we play until the total duration of the file */
  if ((stop = seeksegment.stop) == -1)
    stop = seeksegment.duration;

  GST_DEBUG_OBJECT (aiff, "cur_type =%d", cur_type);
  if ((cur_type != GST_SEEK_TYPE_NONE)) {
    /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
     * we can just copy the last_stop. If not, we use the bps to convert TIME to
     * bytes. */
    if (aiff->bps > 0)
      aiff->offset =
          uint64_ceiling_scale (seeksegment.last_stop, (guint64) aiff->bps,
          GST_SECOND);
    else
      aiff->offset = seeksegment.last_stop;
    GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
    aiff->offset -= (aiff->offset % aiff->bytes_per_sample);
    GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
    aiff->offset += aiff->datastart;
    GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
  } else {
    GST_LOG_OBJECT (aiff, "continue from offset=%" G_GUINT64_FORMAT,
        aiff->offset);
  }

  if (stop_type != GST_SEEK_TYPE_NONE) {
    if (aiff->bps > 0)
      aiff->end_offset =
          uint64_ceiling_scale (stop, (guint64) aiff->bps, GST_SECOND);
    else
      aiff->end_offset = stop;
    GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
    aiff->end_offset -= (aiff->end_offset % aiff->bytes_per_sample);
    GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
    aiff->end_offset += aiff->datastart;
    GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
  } else {
    GST_LOG_OBJECT (aiff, "continue to end_offset=%" G_GUINT64_FORMAT,
        aiff->end_offset);
  }

  /* make sure filesize is not exceeded due to rounding errors or so,
   * same precaution as in _stream_headers */
  bformat = GST_FORMAT_BYTES;
  if (gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size))
    aiff->end_offset = MIN (aiff->end_offset, upstream_size);

  /* this is the range of bytes we will use for playback */
  aiff->offset = MIN (aiff->offset, aiff->end_offset);
  aiff->dataleft = aiff->end_offset - aiff->offset;

  GST_DEBUG_OBJECT (aiff,
      "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
      ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, aiff->offset,
      aiff->end_offset, GST_TIME_ARGS (seeksegment.start),
      GST_TIME_ARGS (stop));

  /* prepare for streaming again */
  if (flush) {
    /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
    GST_DEBUG_OBJECT (aiff, "sending flush stop");
    gst_pad_push_event (aiff->srcpad, gst_event_new_flush_stop ());
  } else if (aiff->segment_running) {
    /* we are running the current segment and doing a non-flushing seek,
     * close the segment first based on the previous last_stop. */
    GST_DEBUG_OBJECT (aiff, "closing running segment %" G_GINT64_FORMAT
        " to %" G_GINT64_FORMAT, aiff->segment.accum, aiff->segment.last_stop);

    /* queue the segment for sending in the stream thread */
    if (aiff->close_segment)
      gst_event_unref (aiff->close_segment);
    aiff->close_segment = gst_event_new_new_segment (TRUE,
        aiff->segment.rate, aiff->segment.format,
        aiff->segment.accum, aiff->segment.last_stop, aiff->segment.accum);

    /* keep track of our last_stop */
    seeksegment.accum = aiff->segment.last_stop;
  }

  /* now we did the seek and can activate the new segment values */
  memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment));

  /* if we're doing a segment seek, post a SEGMENT_START message */
  if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) {
    gst_element_post_message (GST_ELEMENT_CAST (aiff),
        gst_message_new_segment_start (GST_OBJECT_CAST (aiff),
            aiff->segment.format, aiff->segment.last_stop));
  }

  /* now create the newsegment */
  GST_DEBUG_OBJECT (aiff, "Creating newsegment from %" G_GINT64_FORMAT
      " to %" G_GINT64_FORMAT, aiff->segment.last_stop, stop);

  /* store the newsegment event so it can be sent from the streaming thread. */
  if (aiff->start_segment)
    gst_event_unref (aiff->start_segment);
  aiff->start_segment =
      gst_event_new_new_segment (FALSE, aiff->segment.rate,
      aiff->segment.format, aiff->segment.last_stop, stop,
      aiff->segment.last_stop);

  /* mark discont if we are going to stream from another position. */
  if (last_stop != aiff->segment.last_stop) {
    GST_DEBUG_OBJECT (aiff, "mark DISCONT, we did a seek to another position");
    aiff->discont = TRUE;
  }

  /* and start the streaming task again */
  aiff->segment_running = TRUE;
  if (!aiff->streaming) {
    gst_pad_start_task (aiff->sinkpad, (GstTaskFunction) gst_aiff_parse_loop,
        aiff->sinkpad);
  }

  GST_PAD_STREAM_UNLOCK (aiff->sinkpad);

  return TRUE;

  /* ERRORS */
negative_rate:
  {
    GST_DEBUG_OBJECT (aiff, "negative playback rates are not supported yet.");
    return FALSE;
  }
no_format:
  {
    GST_DEBUG_OBJECT (aiff, "unsupported format given, seek aborted.");
    return FALSE;
  }
}
Esempio n. 6
0
/* TODO: if we have another payload already queued for this stream and that
 * payload doesn't have a duration, maybe we can calculate a duration for it
 * (if the previous timestamp is smaller etc. etc.) */
static void
gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload,
    AsfStream * stream)
{
  GST_DEBUG_OBJECT (demux, "Got payload for stream %d ts:%" GST_TIME_FORMAT,
      stream->id, GST_TIME_ARGS (payload->ts));
  /* remember the first timestamp in the stream */
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts) &&
          GST_CLOCK_TIME_IS_VALID (payload->ts))) {
    GST_DEBUG_OBJECT (demux, "first ts: %" GST_TIME_FORMAT,
        GST_TIME_ARGS (payload->ts));
    demux->first_ts = payload->ts;
  }

  /* make timestamps start from 0 */
  if (G_LIKELY (demux->first_ts < payload->ts))
    payload->ts -= demux->first_ts;
  else
    payload->ts = 0;

  /* remove any incomplete payloads that will never be completed */
  while (stream->payloads->len > 0) {
    AsfPayload *prev;
    guint idx_last;

    idx_last = stream->payloads->len - 1;
    prev = &g_array_index (stream->payloads, AsfPayload, idx_last);

    if (G_UNLIKELY (gst_asf_payload_is_complete (prev)))
      break;

    GST_DEBUG_OBJECT (demux, "Dropping incomplete fragmented media object "
        "queued for stream %u", stream->id);

    gst_buffer_replace (&prev->buf, NULL);
    g_array_remove_index (stream->payloads, idx_last);

    /* there's data missing, so there's a discontinuity now */
    GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
  }

  /* If we're about to queue a key frame that is before the segment start, we
   * can ditch any previously queued payloads (which would also be before the
   * segment start). This makes sure the decoder doesn't decode more than
   * absolutely necessary after a seek (we don't push out payloads that are
   * before the segment start until we have at least one that falls within the
   * segment) */
  if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
          payload->ts < demux->segment.start && payload->keyframe)) {
    GST_DEBUG_OBJECT (demux, "Queueing keyframe before segment start, removing"
        " %u previously-queued payloads, which would be out of segment too and"
        " hence don't have to be decoded", stream->payloads->len);
    while (stream->payloads->len > 0) {
      AsfPayload *last;
      guint idx_last;

      idx_last = stream->payloads->len - 1;
      last = &g_array_index (stream->payloads, AsfPayload, idx_last);
      gst_buffer_replace (&last->buf, NULL);
      g_array_remove_index (stream->payloads, idx_last);
    }

    /* Mark discontinuity (should be done via stream->discont anyway though) */
    GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
  }

  /* remember the first queued timestamp for the segment */
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
          GST_CLOCK_TIME_IS_VALID (payload->ts))) {
    GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
        GST_TIME_ARGS (payload->ts));
    demux->segment_ts = payload->ts;
    /* always note, but only determines segment when streaming */
    if (demux->streaming)
      gst_segment_set_seek (&demux->segment, demux->in_segment.rate,
          GST_FORMAT_TIME, demux->segment.flags, GST_SEEK_TYPE_SET,
          demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
  }

  g_array_append_vals (stream->payloads, payload, 1);
}
Esempio n. 7
0
static gboolean
gst_timidity_src_event (GstPad * pad, GstEvent * event)
{
  gboolean res = FALSE;
  GstTimidity *timidity = GST_TIMIDITY (gst_pad_get_parent (pad));

  GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      gdouble rate;
      GstFormat src_format, dst_format;
      GstSeekFlags flags;
      GstSeekType start_type, stop_type;
      gint64 orig_start, start, stop;
      gboolean flush, update;

      if (!timidity->song)
        break;

      gst_event_parse_seek (event, &rate, &src_format, &flags,
          &start_type, &orig_start, &stop_type, &stop);

      dst_format = GST_FORMAT_DEFAULT;

      gst_timidity_src_convert (timidity, src_format, orig_start,
          &dst_format, &start);
      gst_timidity_src_convert (timidity, src_format, stop, &dst_format, &stop);

      flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);

      if (flush) {
        GST_DEBUG ("performing flush");
        gst_pad_push_event (timidity->srcpad, gst_event_new_flush_start ());
      } else {
        gst_pad_stop_task (timidity->sinkpad);
      }

      GST_PAD_STREAM_LOCK (timidity->sinkpad);

      if (flush) {
        gst_pad_push_event (timidity->srcpad, gst_event_new_flush_stop ());
      }

      gst_segment_set_seek (timidity->o_segment, rate, dst_format, flags,
          start_type, start, stop_type, stop, &update);

      if ((flags && GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) {
        GST_DEBUG_OBJECT (timidity, "received segment seek %d, %d",
            (gint) start_type, (gint) stop_type);
      } else {
        GST_DEBUG_OBJECT (timidity, "received normal seek %d",
            (gint) start_type);
        update = FALSE;
      }

      gst_pad_push_event (timidity->srcpad,
          gst_timidity_get_new_segment_event (timidity, GST_FORMAT_TIME,
              update));

      timidity->o_seek = TRUE;

      gst_pad_start_task (timidity->sinkpad,
          (GstTaskFunction) gst_timidity_loop, timidity->sinkpad);

      GST_PAD_STREAM_UNLOCK (timidity->sinkpad);
      GST_DEBUG ("seek done");
    }
      res = TRUE;
      break;
    default:
      break;
  }

  g_object_unref (timidity);
  return res;
}
Esempio n. 8
0
static gboolean
gst_musepackdec_handle_seek_event (GstMusepackDec * dec, GstEvent * event)
{
    GstSeekType start_type, stop_type;
    GstSeekFlags flags;
    GstSegment segment;
    GstFormat format;
    gboolean flush;
    gdouble rate;
    gint64 start, stop;
    gint samplerate;

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

    if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
        GST_DEBUG_OBJECT (dec, "seek failed: only TIME or DEFAULT format allowed");
        return FALSE;
    }

    samplerate = g_atomic_int_get (&dec->rate);

    if (format == GST_FORMAT_TIME) {
        if (start_type != GST_SEEK_TYPE_NONE)
            start = gst_util_uint64_scale_int (start, samplerate, GST_SECOND);
        if (stop_type != GST_SEEK_TYPE_NONE)
            stop = gst_util_uint64_scale_int (stop, samplerate, GST_SECOND);
    }

    flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);

    if (flush)
        gst_pad_push_event (dec->srcpad, gst_event_new_flush_start ());
    else
        gst_pad_pause_task (dec->sinkpad);  /* not _stop_task()? */

    GST_PAD_STREAM_LOCK (dec->sinkpad);

    /* operate on segment copy until we know the seek worked */
    segment = dec->segment;

    gst_segment_set_seek (&segment, rate, GST_FORMAT_DEFAULT,
                          flags, start_type, start, stop_type, stop, NULL);

    gst_pad_push_event (dec->sinkpad, gst_event_new_flush_stop ());

    GST_DEBUG_OBJECT (dec, "segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
                      "] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]",
                      segment.start, segment.stop,
                      GST_TIME_ARGS (segment.start * GST_SECOND / dec->rate),
                      GST_TIME_ARGS (segment.stop * GST_SECOND / dec->rate));

    GST_DEBUG_OBJECT (dec, "performing seek to sample %" G_GINT64_FORMAT,
                      segment.start);

    if (segment.start < 0 || segment.start >= segment.duration) {
        GST_WARNING_OBJECT (dec, "seek out of bounds");
        goto failed;
    }
#ifdef MPC_IS_OLD_API
    if (!mpc_decoder_seek_sample (dec->d, segment.start))
        goto failed;
#else
    if (mpc_demux_seek_sample (dec->d, segment.start) != MPC_STATUS_OK)
        goto failed;
#endif

    if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) {
        GST_DEBUG_OBJECT (dec, "posting SEGMENT_START message");

        gst_element_post_message (GST_ELEMENT (dec),
                                  gst_message_new_segment_start (GST_OBJECT (dec), GST_FORMAT_TIME,
                                          gst_util_uint64_scale_int (segment.start, GST_SECOND, dec->rate)));
    }

    if (flush) {
        gst_pad_push_event (dec->srcpad, gst_event_new_flush_stop ());
    }

    gst_segment_set_last_stop (&segment, GST_FORMAT_DEFAULT, segment.start);
    dec->segment = segment;
    gst_musepackdec_send_newsegment (dec);

    GST_DEBUG_OBJECT (dec, "seek successful");

    gst_pad_start_task (dec->sinkpad,
                        (GstTaskFunction) gst_musepackdec_loop, dec->sinkpad);

    GST_PAD_STREAM_UNLOCK (dec->sinkpad);

    return TRUE;

failed:
    {
        GST_WARNING_OBJECT (dec, "seek failed");
        GST_PAD_STREAM_UNLOCK (dec->sinkpad);
        return FALSE;
    }
}
Esempio n. 9
0
static gboolean
gst_real_audio_demux_handle_seek (GstRealAudioDemux * demux, GstEvent * event)
{
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType cur_type, stop_type;
  gboolean flush, update;
  gdouble rate;
  guint64 seek_pos;
  gint64 cur, stop;

  if (!demux->seekable)
    goto not_seekable;

  if (demux->byterate_num == 0 || demux->byterate_denom == 0)
    goto no_bitrate;

  gst_event_parse_seek (event, &rate, &format, &flags,
      &cur_type, &cur, &stop_type, &stop);

  if (format != GST_FORMAT_TIME)
    goto only_time_format_supported;

  if (rate <= 0.0)
    goto cannot_do_backwards_playback;

  flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);

  GST_DEBUG_OBJECT (demux, "flush=%d, rate=%g", flush, rate);

  /* unlock streaming thread and make streaming stop */
  if (flush) {
    gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
    gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (demux->sinkpad);
  }

  GST_PAD_STREAM_LOCK (demux->sinkpad);

  if (demux->segment_running && !flush) {
    GstEvent *newseg;

    newseg = gst_event_new_new_segment_full (TRUE, demux->segment.rate,
        demux->segment.applied_rate, GST_FORMAT_TIME, demux->segment.start,
        demux->segment.last_stop, demux->segment.time);

    GST_DEBUG_OBJECT (demux, "sending NEWSEGMENT event to close the current "
        "segment: %" GST_PTR_FORMAT, newseg);

    gst_pad_push_event (demux->srcpad, newseg);
  }

  gst_segment_set_seek (&demux->segment, rate, format, flags,
      cur_type, cur, stop_type, stop, &update);

  GST_DEBUG_OBJECT (demux, "segment: %" GST_SEGMENT_FORMAT, &demux->segment);

  seek_pos = gst_util_uint64_scale (demux->segment.start,
      demux->byterate_num, demux->byterate_denom * GST_SECOND);
  if (demux->packet_size > 0) {
    seek_pos -= seek_pos % demux->packet_size;
  }
  seek_pos += demux->data_offset;

  GST_DEBUG_OBJECT (demux, "seek_pos = %" G_GUINT64_FORMAT, seek_pos);

  /* stop flushing */
  gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
  gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ());

  demux->offset = seek_pos;
  demux->need_newsegment = TRUE;

  /* notify start of new segment */
  if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
    gst_element_post_message (GST_ELEMENT (demux),
        gst_message_new_segment_start (GST_OBJECT (demux),
            GST_FORMAT_TIME, demux->segment.last_stop));
  }

  demux->segment_running = TRUE;
  /* restart our task since it might have been stopped when we did the flush */
  gst_pad_start_task (demux->sinkpad,
      (GstTaskFunction) gst_real_audio_demux_loop, demux);

  /* streaming can continue now */
  GST_PAD_STREAM_UNLOCK (demux->sinkpad);

  return TRUE;

/* ERRORS */
not_seekable:
  {
    GST_DEBUG_OBJECT (demux, "seek failed: cannot seek in streaming mode");
    return FALSE;
  }
no_bitrate:
  {
    GST_DEBUG_OBJECT (demux, "seek failed: bitrate unknown");
    return FALSE;
  }
only_time_format_supported:
  {
    GST_DEBUG_OBJECT (demux, "can only seek in TIME format");
    return FALSE;
  }
cannot_do_backwards_playback:
  {
    GST_DEBUG_OBJECT (demux, "can only seek with positive rate, not %lf", rate);
    return FALSE;
  }
}
Esempio n. 10
0
static gboolean
gst_raw_parse_handle_seek_pull (GstRawParse * rp, GstEvent * event)
{
  gdouble rate;
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  gint64 last_stop;
  gboolean ret = FALSE;
  gboolean flush;
  GstSegment seeksegment;

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

    /* convert input offsets to time */
    ret = gst_raw_parse_convert (rp, format, start, GST_FORMAT_TIME, &start);
    ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_TIME, &stop);
    if (!ret)
      goto convert_failed;

    GST_DEBUG_OBJECT (rp, "converted start - stop to time");

    format = GST_FORMAT_TIME;

    gst_event_unref (event);
  } else {
    format = GST_FORMAT_TIME;
    flags = 0;
  }

  flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);

  /* start flushing up and downstream so that the loop function pauses and we
   * can acquire the STREAM_LOCK. */
  if (flush) {
    GST_LOG_OBJECT (rp, "flushing");
    gst_pad_push_event (rp->sinkpad, gst_event_new_flush_start ());
    gst_pad_push_event (rp->srcpad, gst_event_new_flush_start ());
  } else {
    GST_LOG_OBJECT (rp, "pause task");
    gst_pad_pause_task (rp->sinkpad);
  }

  GST_PAD_STREAM_LOCK (rp->sinkpad);

  memcpy (&seeksegment, &rp->segment, sizeof (GstSegment));

  if (event) {
    /* configure the seek values */
    gst_segment_set_seek (&seeksegment, rate, format, flags,
        start_type, start, stop_type, stop, NULL);
  }

  /* get the desired position */
  last_stop = seeksegment.last_stop;

  GST_LOG_OBJECT (rp, "seeking to %" GST_TIME_FORMAT,
      GST_TIME_ARGS (last_stop));

  /* convert the desired position to bytes */
  ret =
      gst_raw_parse_convert (rp, format, last_stop, GST_FORMAT_BYTES,
      &last_stop);

  /* prepare for streaming */
  if (flush) {
    GST_LOG_OBJECT (rp, "stop flush");
    gst_pad_push_event (rp->sinkpad, gst_event_new_flush_stop ());
    gst_pad_push_event (rp->srcpad, gst_event_new_flush_stop ());
  } else if (ret && rp->running) {
    /* we are running the current segment and doing a non-flushing seek, 
     * close the segment first based on the last_stop. */
    GST_DEBUG_OBJECT (rp, "prepare close segment %" G_GINT64_FORMAT
        " to %" G_GINT64_FORMAT, rp->segment.start, rp->segment.last_stop);

    /* queue the segment for sending in the stream thread */
    if (rp->close_segment)
      gst_event_unref (rp->close_segment);
    rp->close_segment =
        gst_event_new_new_segment_full (TRUE,
        rp->segment.rate, rp->segment.applied_rate, rp->segment.format,
        rp->segment.start, rp->segment.last_stop, rp->segment.time);
  }

  if (ret) {
    /* seek done */

    /* Seek on a frame boundary */
    last_stop -= last_stop % rp->framesize;

    rp->offset = last_stop;
    rp->n_frames = last_stop / rp->framesize;

    GST_LOG_OBJECT (rp, "seeking to bytes %" G_GINT64_FORMAT, last_stop);

    memcpy (&rp->segment, &seeksegment, sizeof (GstSegment));

    if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) {
      gst_element_post_message (GST_ELEMENT_CAST (rp),
          gst_message_new_segment_start (GST_OBJECT_CAST (rp),
              rp->segment.format, rp->segment.last_stop));
    }

    /* for deriving a stop position for the playback segment from the seek
     * segment, we must take the duration when the stop is not set */
    if ((stop = rp->segment.stop) == -1)
      stop = rp->segment.duration;

    GST_DEBUG_OBJECT (rp, "preparing newsegment from %" G_GINT64_FORMAT
        " to %" G_GINT64_FORMAT, rp->segment.start, stop);

    /* now replace the old segment so that we send it in the stream thread the
     * next time it is scheduled. */
    if (rp->start_segment)
      gst_event_unref (rp->start_segment);

    if (rp->segment.rate >= 0.0) {
      /* forward, we send data from last_stop to stop */
      rp->start_segment =
          gst_event_new_new_segment_full (FALSE,
          rp->segment.rate, rp->segment.applied_rate, rp->segment.format,
          rp->segment.last_stop, stop, rp->segment.time);
    } else {
      /* reverse, we send data from last_stop to start */
      rp->start_segment =
          gst_event_new_new_segment_full (FALSE,
          rp->segment.rate, rp->segment.applied_rate, rp->segment.format,
          rp->segment.start, rp->segment.last_stop, rp->segment.time);
    }
  }
  rp->discont = TRUE;

  GST_LOG_OBJECT (rp, "start streaming");
  rp->running = TRUE;
  gst_pad_start_task (rp->sinkpad, (GstTaskFunction) gst_raw_parse_loop, rp);

  GST_PAD_STREAM_UNLOCK (rp->sinkpad);

  return ret;

  /* ERRORS */
convert_failed:
  {
    GST_DEBUG_OBJECT (rp, "Seek failed: couldn't convert to byte positions");
    return FALSE;
  }
}
Esempio n. 11
0
static gboolean
gst_wavpack_parse_handle_seek_event (GstWavpackParse * wvparse,
    GstEvent * event)
{
  GstSeekFlags seek_flags;

  GstSeekType start_type;

  GstSeekType stop_type;

  GstSegment segment;

  GstFormat format;

  gboolean only_update;

  gboolean flush, ret;

  gdouble speed;

  gint64 stop;

  gint64 start;                 /* sample we want to seek to                  */

  gint64 byte_offset;           /* byte offset the chunk we seek to starts at */

  gint64 chunk_start;           /* first sample in chunk we seek to           */

  guint rate;

  gint64 last_stop;

  if (wvparse->adapter) {
    GST_DEBUG_OBJECT (wvparse, "seeking in streaming mode not implemented yet");
    return FALSE;
  }

  gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type,
      &start, &stop_type, &stop);

  if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME) {
    GST_DEBUG ("seeking is only supported in TIME or DEFAULT format");
    return FALSE;
  }

  if (speed < 0.0) {
    GST_DEBUG ("only forward playback supported, rate %f not allowed", speed);
    return FALSE;
  }

  GST_OBJECT_LOCK (wvparse);

  rate = wvparse->samplerate;
  if (rate == 0) {
    GST_OBJECT_UNLOCK (wvparse);
    GST_DEBUG ("haven't read header yet");
    return FALSE;
  }

  /* figure out the last position we need to play. If it's configured (stop !=
   * -1), use that, else we play until the total duration of the file */
  if (stop == -1)
    stop = wvparse->segment.duration;

  /* convert from time to samples if necessary */
  if (format == GST_FORMAT_TIME) {
    if (start_type != GST_SEEK_TYPE_NONE)
      start = gst_util_uint64_scale_int (start, rate, GST_SECOND);
    if (stop_type != GST_SEEK_TYPE_NONE)
      stop = gst_util_uint64_scale_int (stop, rate, GST_SECOND);
  }

  if (start < 0) {
    GST_OBJECT_UNLOCK (wvparse);
    GST_DEBUG_OBJECT (wvparse, "Invalid start sample %" G_GINT64_FORMAT, start);
    return FALSE;
  }

  flush = ((seek_flags & GST_SEEK_FLAG_FLUSH) != 0);

  /* operate on segment copy until we know the seek worked */
  segment = wvparse->segment;

  gst_segment_set_seek (&segment, speed, GST_FORMAT_DEFAULT,
      seek_flags, start_type, start, stop_type, stop, &only_update);

#if 0
  if (only_update) {
    wvparse->segment = segment;
    gst_wavpack_parse_send_newsegment (wvparse, TRUE);
    goto done;
  }
#endif

  gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_start ());

  if (flush) {
    gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (wvparse->sinkpad);
  }

  GST_PAD_STREAM_LOCK (wvparse->sinkpad);

  /* Save current position */
  last_stop = wvparse->segment.last_stop;

  gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_stop ());

  if (flush) {
    gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_stop ());
  }

  GST_DEBUG_OBJECT (wvparse, "Performing seek to %" GST_TIME_FORMAT " sample %"
      G_GINT64_FORMAT, GST_TIME_ARGS (segment.start * GST_SECOND / rate),
      start);

  ret = gst_wavpack_parse_scan_to_find_sample (wvparse, segment.start,
      &byte_offset, &chunk_start);

  if (ret) {
    GST_DEBUG_OBJECT (wvparse, "new offset: %" G_GINT64_FORMAT, byte_offset);
    wvparse->current_offset = byte_offset;
    /* we want to send a newsegment event with the actual seek position
     * as start, even though our first buffer might start before the
     * configured segment. We leave it up to the decoder or sink to crop
     * the output buffers accordingly */
    wvparse->segment = segment;
    wvparse->segment.last_stop = chunk_start;
    wvparse->need_newsegment = TRUE;
    wvparse->discont = (last_stop != chunk_start) ? TRUE : FALSE;

    /* if we're doing a segment seek, post a SEGMENT_START message */
    if (wvparse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
      gst_element_post_message (GST_ELEMENT_CAST (wvparse),
          gst_message_new_segment_start (GST_OBJECT_CAST (wvparse),
              wvparse->segment.format, wvparse->segment.last_stop));
    }
  } else {
    GST_DEBUG_OBJECT (wvparse, "seek failed: don't know where to seek to");
  }

  GST_PAD_STREAM_UNLOCK (wvparse->sinkpad);
  GST_OBJECT_UNLOCK (wvparse);

  gst_pad_start_task (wvparse->sinkpad,
      (GstTaskFunction) gst_wavpack_parse_loop, wvparse);

  return ret;
}
Esempio n. 12
0
static gboolean
normal_seek (GstVdpMpegDec * mpeg_dec, GstEvent * event)
{
    gdouble rate;
    GstFormat format;
    GstSeekFlags flags;
    GstSeekType cur_type, stop_type;
    gint64 time_cur, bytes_cur;
    gint64 time_stop, bytes_stop;
    gboolean res;
    gboolean update;
    GstEvent *peer_event;

    GST_DEBUG ("normal seek");

    gst_event_parse_seek (event, &rate, &format, &flags,
                          &cur_type, &time_cur, &stop_type, &time_stop);

    if (format != GST_FORMAT_TIME)
        return FALSE;

    gst_segment_set_seek (&mpeg_dec->segment, rate, GST_FORMAT_TIME, flags,
                          cur_type, time_cur, stop_type, time_stop, &update);

    if (update) {
        /* seek on bytes */
        if (!gst_vdp_mpeg_dec_convert (mpeg_dec, GST_FORMAT_TIME, time_cur,
                                       GST_FORMAT_BYTES, &bytes_cur))
            goto convert_failed;
        if (!gst_vdp_mpeg_dec_convert (mpeg_dec, GST_FORMAT_TIME, time_stop,
                                       GST_FORMAT_BYTES, &bytes_stop))
            goto convert_failed;

        /* conversion succeeded, create the seek */
        peer_event =
            gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
                                cur_type, bytes_cur, stop_type, bytes_stop);

        g_mutex_lock (mpeg_dec->mutex);

        /* do the seek */
        res = gst_pad_push_event (mpeg_dec->sink, peer_event);

        if (res) {
            mpeg_dec->state = GST_VDP_MPEG_DEC_NEED_GOP;
            mpeg_dec->seeking = TRUE;
        }

        g_mutex_unlock (mpeg_dec->mutex);

    } else {
        GstEvent *event;

        /* send segment with new rate */
        event = gst_event_new_new_segment (TRUE,
                                           mpeg_dec->segment.rate, GST_FORMAT_TIME, mpeg_dec->segment.start,
                                           mpeg_dec->segment.stop, mpeg_dec->segment.time);

        gst_pad_push_event (mpeg_dec->src, event);
        res = TRUE;
    }

    return res;

    /* ERRORS */
convert_failed:
    {
        /* probably unsupported seek format */
        GST_DEBUG_OBJECT (mpeg_dec,
                          "failed to convert format %u into GST_FORMAT_TIME", format);
        return FALSE;
    }
}
Esempio n. 13
0
static gboolean
gst_wildmidi_do_seek (GstWildmidi * wildmidi, GstEvent * event)
{
  gdouble rate;
  GstFormat src_format, dst_format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  gboolean flush, update, accurate;
  gboolean res;
  unsigned long int sample;
  GstSegment *segment;

  if (!wildmidi->song)
    return FALSE;

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

  /* convert the input format to samples */
  dst_format = GST_FORMAT_DEFAULT;
  res = TRUE;
  if (start_type != GST_SEEK_TYPE_NONE) {
    res =
        gst_wildmidi_src_convert (wildmidi, src_format, start, &dst_format,
        &start);
  }
  if (res && stop_type != GST_SEEK_TYPE_NONE) {
    res =
        gst_wildmidi_src_convert (wildmidi, src_format, stop, &dst_format,
        &stop);
  }
  /* unsupported format */
  if (!res)
    return res;

  flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
  accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);

  if (flush) {
    GST_DEBUG ("performing flush");
    gst_pad_push_event (wildmidi->srcpad, gst_event_new_flush_start ());
  } else {
    gst_pad_stop_task (wildmidi->sinkpad);
  }

  segment = wildmidi->o_segment;

  GST_PAD_STREAM_LOCK (wildmidi->sinkpad);

  if (flush) {
    gst_pad_push_event (wildmidi->srcpad, gst_event_new_flush_stop ());
  }

  /* update the segment now */
  gst_segment_set_seek (segment, rate, dst_format, flags,
      start_type, start, stop_type, stop, &update);

  /* we need to seek to last_stop in the segment now, sample will be updated */
  sample = segment->last_stop;

  GST_OBJECT_LOCK (wildmidi);
  if (accurate) {
    WildMidi_SampledSeek (wildmidi->song, &sample);
  } else {
    WildMidi_FastSeek (wildmidi->song, &sample);
  }
  GST_OBJECT_UNLOCK (wildmidi);

  segment->start = segment->time = segment->last_stop = sample;

  gst_pad_push_event (wildmidi->srcpad,
      gst_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME));

  gst_pad_start_task (wildmidi->sinkpad,
      (GstTaskFunction) gst_wildmidi_loop, wildmidi->sinkpad);

  wildmidi->discont = TRUE;
  GST_PAD_STREAM_UNLOCK (wildmidi->sinkpad);
  GST_DEBUG ("seek done");

  return TRUE;
}