gst_rmdemux_perform_seek (GstRMDemux * rmdemux, GstEvent * event)
{
  gboolean validated;
  gboolean ret = TRUE;
  gboolean flush;
  GstFormat format;
  gdouble rate;
  GstSeekFlags flags;
  GstSeekType cur_type, stop_type;
  gint64 cur, stop;
  gboolean update;

  if (event) {
    GST_DEBUG_OBJECT (rmdemux, "seek with event");

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

    /* we can only seek on time */
    if (format != GST_FORMAT_TIME) {
      GST_DEBUG_OBJECT (rmdemux, "can only seek on TIME");
      goto error;
    }
    /* cannot yet do backwards playback */
    if (rate <= 0.0) {
      GST_DEBUG_OBJECT (rmdemux, "can only seek with positive rate, not %lf",
          rate);
      goto error;
    }
  } else {
    GST_DEBUG_OBJECT (rmdemux, "seek without event");

    flags = 0;
    rate = 1.0;
  }

  GST_DEBUG_OBJECT (rmdemux, "seek, rate %g", rate);

  flush = flags & GST_SEEK_FLAG_FLUSH;

  /* first step is to unlock the streaming thread if it is
   * blocked in a chain call, we do this by starting the flush. */
  if (flush) {
    gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_start ());
    gst_rmdemux_send_event (rmdemux, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (rmdemux->sinkpad);
  }

  GST_LOG_OBJECT (rmdemux, "Done starting flushes");

  /* now grab the stream lock so that streaming cannot continue, for
   * non flushing seeks when the element is in PAUSED this could block
   * forever. */
  GST_PAD_STREAM_LOCK (rmdemux->sinkpad);

  GST_LOG_OBJECT (rmdemux, "Took streamlock");

  if (event) {
    if (!gst_segment_do_seek (&rmdemux->segment, rate, format, flags,
            cur_type, cur, stop_type, stop, &update)) {
      ret = FALSE;
      goto done;
    }
  }

  GST_DEBUG_OBJECT (rmdemux, "segment positions set to %" GST_TIME_FORMAT "-%"
      GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment.start),
      GST_TIME_ARGS (rmdemux->segment.stop));

  /* we need to stop flushing on the sinkpad as we're going to use it
   * next. We can do this as we have the STREAM lock now. */
  gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_stop (TRUE));

  GST_LOG_OBJECT (rmdemux, "Pushed FLUSH_STOP event");

  /* For each stream, find the first index offset equal to or before our seek 
   * target. Of these, find the smallest offset. That's where we seek to.
   *
   * Then we pull 4 bytes from that offset, and validate that we've seeked to a
   * what looks like a plausible packet.
   * If that fails, restart, with the seek target set to one less than the
   * offset we just tried. If we run out of places to try, treat that as a fatal
   * error.
   */
  if (!find_seek_offset_time (rmdemux, rmdemux->segment.position)) {
    GST_LOG_OBJECT (rmdemux, "Failed to find seek offset by time");
    ret = FALSE;
    goto done;
  }

  GST_LOG_OBJECT (rmdemux, "Validating offset %u", rmdemux->offset);
  validated = gst_rmdemux_validate_offset (rmdemux);
  while (!validated) {
    GST_INFO_OBJECT (rmdemux, "Failed to validate offset at %u",
        rmdemux->offset);
    if (!find_seek_offset_bytes (rmdemux, rmdemux->offset - 1)) {
      ret = FALSE;
      goto done;
    }
    validated = gst_rmdemux_validate_offset (rmdemux);
  }

  GST_LOG_OBJECT (rmdemux, "Found final offset. Excellent!");

  /* now we have a new position, prepare for streaming again */
  {
    /* Reset the demuxer state */
    rmdemux->state = RMDEMUX_STATE_DATA_PACKET;

    if (flush)
      gst_rmdemux_send_event (rmdemux, gst_event_new_flush_stop (TRUE));

    /* must send newsegment event from streaming thread, so just set flag */
    rmdemux->need_newsegment = TRUE;

    /* notify start of new segment */
    if (rmdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
      gst_element_post_message (GST_ELEMENT_CAST (rmdemux),
          gst_message_new_segment_start (GST_OBJECT_CAST (rmdemux),
              GST_FORMAT_TIME, rmdemux->segment.position));
    }

    /* restart our task since it might have been stopped when we did the 
     * flush. */
    gst_pad_start_task (rmdemux->sinkpad, (GstTaskFunction) gst_rmdemux_loop,
        rmdemux->sinkpad, NULL);
  }

done:
  /* streaming can continue now */
  GST_PAD_STREAM_UNLOCK (rmdemux->sinkpad);

  return ret;

error:
  {
    GST_DEBUG_OBJECT (rmdemux, "seek failed");
    return FALSE;
  }
}
gst_rmdemux_perform_seek (GstRMDemux * rmdemux, GstEvent * event)
{
  gboolean validated;
  gboolean ret = TRUE;
  gboolean flush;
  GstFormat format;
  gdouble rate;
  GstSeekFlags flags;
  GstSeekType cur_type, stop_type;
  gint64 cur, stop;
  gboolean update;

  if (event) {
    GST_DEBUG_OBJECT (rmdemux, "seek with event");

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

     
    if (format != GST_FORMAT_TIME) {
      GST_DEBUG_OBJECT (rmdemux, "can only seek on TIME");
      goto error;
    }
     
    if (rate <= 0.0) {
      GST_DEBUG_OBJECT (rmdemux, "can only seek with positive rate, not %lf",
          rate);
      goto error;
    }
  } else {
    GST_DEBUG_OBJECT (rmdemux, "seek without event");

    flags = 0;
    rate = 1.0;
  }

  GST_DEBUG_OBJECT (rmdemux, "seek, rate %g", rate);

  flush = flags & GST_SEEK_FLAG_FLUSH;

   
  if (flush) {
    gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_start ());
    gst_rmdemux_send_event (rmdemux, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (rmdemux->sinkpad);
  }

  GST_LOG_OBJECT (rmdemux, "Done starting flushes");

   
  GST_PAD_STREAM_LOCK (rmdemux->sinkpad);

  GST_LOG_OBJECT (rmdemux, "Took streamlock");

  if (event) {
    if (!gst_segment_do_seek (&rmdemux->segment, rate, format, flags,
            cur_type, cur, stop_type, stop, &update)) {
      ret = FALSE;
      goto done;
    }
  }

  GST_DEBUG_OBJECT (rmdemux, "segment positions set to %" GST_TIME_FORMAT "-%"
      GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment.start),
      GST_TIME_ARGS (rmdemux->segment.stop));

   
  gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_stop (TRUE));

  GST_LOG_OBJECT (rmdemux, "Pushed FLUSH_STOP event");

   
  if (!find_seek_offset_time (rmdemux, rmdemux->segment.position)) {
    GST_LOG_OBJECT (rmdemux, "Failed to find seek offset by time");
    ret = FALSE;
    goto done;
  }

  GST_LOG_OBJECT (rmdemux, "Validating offset %u", rmdemux->offset);
  validated = gst_rmdemux_validate_offset (rmdemux);
  while (!validated) {
    GST_INFO_OBJECT (rmdemux, "Failed to validate offset at %u",
        rmdemux->offset);
    if (!find_seek_offset_bytes (rmdemux, rmdemux->offset - 1)) {
      ret = FALSE;
      goto done;
    }
    validated = gst_rmdemux_validate_offset (rmdemux);
  }

  GST_LOG_OBJECT (rmdemux, "Found final offset. Excellent!");

   
  {
     
    rmdemux->state = RMDEMUX_STATE_DATA_PACKET;

    if (flush)
      gst_rmdemux_send_event (rmdemux, gst_event_new_flush_stop (TRUE));

     
    rmdemux->need_newsegment = TRUE;

     
    if (rmdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
      gst_element_post_message (GST_ELEMENT_CAST (rmdemux),
          gst_message_new_segment_start (GST_OBJECT_CAST (rmdemux),
              GST_FORMAT_TIME, rmdemux->segment.position));
    }

     
    gst_pad_start_task (rmdemux->sinkpad, (GstTaskFunction) gst_rmdemux_loop,
        rmdemux->sinkpad, NULL);
  }

done:
   
  GST_PAD_STREAM_UNLOCK (rmdemux->sinkpad);

  return ret;

error:
  {
    GST_DEBUG_OBJECT (rmdemux, "seek failed");
    return FALSE;
  }
}