예제 #1
0
static gboolean
gst_droid_cam_src_vfsrc_activatepush (GstPad * pad, gboolean active)
{
  GstDroidCamSrc *src;

  src = GST_DROID_CAM_SRC (GST_OBJECT_PARENT (pad));

  GST_DEBUG_OBJECT (src, "vfsrc activatepush: %d", active);

  if (active) {
    gboolean started;
    src->send_new_segment = TRUE;

    /* First we do caps negotiation */
    if (!gst_droid_cam_src_vfsrc_negotiate (src)) {
      return FALSE;
    }

    /* Then we start our task */
    GST_PAD_STREAM_LOCK (pad);

    started = gst_vf_src_pad_start_task (pad);
    if (!started) {
      GST_CAMERA_BUFFER_POOL_LOCK (src->pool);
      src->pool->flushing = TRUE;
      GST_CAMERA_BUFFER_POOL_UNLOCK (src->pool);

      GST_PAD_STREAM_UNLOCK (pad);

      GST_ERROR_OBJECT (src, "Failed to start task");
      gst_pad_stop_task (pad);
      return FALSE;
    }

    GST_CAMERA_BUFFER_POOL_LOCK (src->pool);
    src->pool->flushing = FALSE;
    GST_CAMERA_BUFFER_POOL_UNLOCK (src->pool);

    GST_PAD_STREAM_UNLOCK (pad);

    GST_DEBUG_OBJECT (src, "task started");
  } else {
    GST_CAMERA_BUFFER_POOL_LOCK (src->pool);
    src->pool->flushing = TRUE;
    GST_CAMERA_BUFFER_POOL_UNLOCK (src->pool);

    GST_DEBUG_OBJECT (src, "stopping task");

    gst_camera_buffer_pool_unlock_app_queue (src->pool);

    gst_pad_stop_task (pad);

    GST_DEBUG_OBJECT (src, "stopped task");
  }

  return TRUE;
}
예제 #2
0
static void
gst_omx_audio_enc_flush (GstAudioEncoder * encoder)
{
  GstOMXAudioEnc *self;

  self = GST_OMX_AUDIO_ENC (encoder);

  GST_DEBUG_OBJECT (self, "Resetting encoder");

  gst_omx_audio_enc_drain (self);

  gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
  gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);

  /* Wait until the srcpad loop is finished */
  GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
  GST_PAD_STREAM_LOCK (GST_AUDIO_ENCODER_SRC_PAD (self));
  GST_PAD_STREAM_UNLOCK (GST_AUDIO_ENCODER_SRC_PAD (self));
  GST_AUDIO_ENCODER_STREAM_LOCK (self);

  gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
  gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
  gst_omx_port_populate (self->enc_out_port);

  /* Start the srcpad loop again */
  self->last_upstream_ts = 0;
  self->downstream_flow_ret = GST_FLOW_OK;
  self->eos = FALSE;
  gst_pad_start_task (GST_AUDIO_ENCODER_SRC_PAD (self),
      (GstTaskFunction) gst_omx_audio_enc_loop, encoder, NULL);
}
예제 #3
0
static void
gst_amc_audio_dec_flush (GstAudioDecoder * decoder, gboolean hard)
{
  GstAmcAudioDec *self;

  self = GST_AMC_AUDIO_DEC (decoder);

  GST_DEBUG_OBJECT (self, "Resetting decoder");

  if (!self->started) {
    GST_DEBUG_OBJECT (self, "Codec not started yet");
    return;
  }

  self->flushing = TRUE;
  gst_amc_codec_flush (self->codec);

  /* Wait until the srcpad loop is finished,
   * unlock GST_AUDIO_DECODER_STREAM_LOCK to prevent deadlocks
   * caused by using this lock from inside the loop function */
  GST_AUDIO_DECODER_STREAM_UNLOCK (self);
  GST_PAD_STREAM_LOCK (GST_AUDIO_DECODER_SRC_PAD (self));
  GST_PAD_STREAM_UNLOCK (GST_AUDIO_DECODER_SRC_PAD (self));
  GST_AUDIO_DECODER_STREAM_LOCK (self);
  self->flushing = FALSE;

  /* Start the srcpad loop again */
  self->last_upstream_ts = 0;
  self->eos = FALSE;
  self->downstream_flow_ret = GST_FLOW_OK;
  gst_pad_start_task (GST_AUDIO_DECODER_SRC_PAD (self),
      (GstTaskFunction) gst_amc_audio_dec_loop, decoder, NULL);

  GST_DEBUG_OBJECT (self, "Reset decoder");
}
예제 #4
0
static gboolean
gst_base_video_decoder_sink_activate (GstBaseVideoDecoder * decoder,
    gboolean active)
{
  GstBaseVideoDecoderClass *klass;
  gboolean result = FALSE;

  GST_DEBUG_OBJECT (decoder, "activate");

  klass = GST_BASE_VIDEO_DECODER_GET_CLASS (decoder);

  if (active) {
    if (klass->start)
      result = klass->start (decoder);
  } else {
    /* We must make sure streaming has finished before resetting things
     * and calling the ::stop vfunc */
    GST_PAD_STREAM_LOCK (GST_BASE_VIDEO_CODEC_SINK_PAD (decoder));
    GST_PAD_STREAM_UNLOCK (GST_BASE_VIDEO_CODEC_SINK_PAD (decoder));

    if (klass->stop)
      result = klass->stop (decoder);
  }

  GST_DEBUG_OBJECT (decoder, "activate: %d", result);

  return result;
}
예제 #5
0
static gboolean
gst_cdxa_parse_do_seek (GstCDXAParse * cdxa, GstEvent * event)
{
  GstSeekFlags flags;
  GstSeekType start_type;
  GstFormat format;
  gint64 start, off, upstream_size;

  gst_event_parse_seek (event, NULL, &format, &flags, &start_type, &start,
      NULL, NULL);

  if (format != GST_FORMAT_BYTES) {
    GST_DEBUG_OBJECT (cdxa, "Can only handle seek in BYTES format");
    return FALSE;
  }

  if (start_type != GST_SEEK_TYPE_SET) {
    GST_DEBUG_OBJECT (cdxa, "Can only handle seek from start (SEEK_TYPE_SET)");
    return FALSE;
  }

  GST_OBJECT_LOCK (cdxa);
  off = gst_cdxa_parse_convert_src_to_sink_offset (cdxa, start);
  upstream_size = cdxa->datasize;
  GST_OBJECT_UNLOCK (cdxa);

  if (off >= upstream_size) {
    GST_DEBUG_OBJECT (cdxa, "Invalid target offset %" G_GINT64_FORMAT ", file "
        "is only %" G_GINT64_FORMAT " bytes in size", off, upstream_size);
    return FALSE;
  }

  /* unlock upstream pull_range */
  gst_pad_push_event (cdxa->sinkpad, gst_event_new_flush_start ());

  /* make sure our loop function exits */
  gst_pad_push_event (cdxa->srcpad, gst_event_new_flush_start ());

  /* wait for streaming to finish */
  GST_PAD_STREAM_LOCK (cdxa->sinkpad);

  /* prepare for streaming again */
  gst_pad_push_event (cdxa->sinkpad, gst_event_new_flush_stop ());
  gst_pad_push_event (cdxa->srcpad, gst_event_new_flush_stop ());

  gst_pad_push_event (cdxa->srcpad,
      gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
          start, GST_CLOCK_TIME_NONE, 0));

  GST_OBJECT_LOCK (cdxa);
  cdxa->offset = off;
  GST_OBJECT_UNLOCK (cdxa);

  /* and restart */
  gst_pad_start_task (cdxa->sinkpad,
      (GstTaskFunction) gst_cdxa_parse_loop, cdxa->sinkpad, NULL);

  GST_PAD_STREAM_UNLOCK (cdxa->sinkpad);
  return TRUE;
}
예제 #6
0
static GstFlowReturn
gst_funnel_sink_chain_object (GstPad * pad, GstFunnel * funnel,
    gboolean is_list, GstMiniObject * obj)
{
  GstFlowReturn res;

  GST_DEBUG_OBJECT (pad, "received %" GST_PTR_FORMAT, obj);

  GST_PAD_STREAM_LOCK (funnel->srcpad);

  if ((funnel->last_sinkpad == NULL)
      || ((funnel->forward_sticky_events_mode !=
              GST_FUNNEL_FORWARD_STICKY_EVENTS_MODE_NEVER)
          && (funnel->last_sinkpad != pad))) {

    GST_DEBUG_OBJECT (pad, "Forwarding sticky events");
    gst_pad_sticky_events_foreach (pad, forward_events_on_stream_changed,
        funnel);

    gst_object_replace ((GstObject **) & funnel->last_sinkpad,
        GST_OBJECT (pad));
  }

  if (is_list)
    res = gst_pad_push_list (funnel->srcpad, GST_BUFFER_LIST_CAST (obj));
  else
    res = gst_pad_push (funnel->srcpad, GST_BUFFER_CAST (obj));

  GST_PAD_STREAM_UNLOCK (funnel->srcpad);

  GST_LOG_OBJECT (pad, "handled buffer%s %s", (is_list ? "list" : ""),
      gst_flow_get_name (res));

  return res;
}
예제 #7
0
static gboolean
gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
{
  GstWavpackParse *parse;

  gboolean ret = TRUE;

  parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:{
      if (parse->adapter) {
        gst_adapter_clear (parse->adapter);
      }
      if (parse->pending_buffer) {
        gst_buffer_unref (parse->pending_buffer);
        parse->pending_buffer = NULL;
        parse->pending_offset = 0;
      }
      ret = gst_pad_push_event (parse->srcpad, event);
      break;
    }
    case GST_EVENT_NEWSEGMENT:{
      parse->need_newsegment = TRUE;
      gst_event_unref (event);
      ret = TRUE;
      break;
    }
    case GST_EVENT_EOS:{
      if (parse->adapter) {
        /* remove all bytes that are left in the adapter after EOS. They can't
         * be a complete Wavpack block and we can't do anything with them */
        gst_adapter_clear (parse->adapter);
      }
      if (parse->pending_buffer) {
        gst_buffer_unref (parse->pending_buffer);
        parse->pending_buffer = NULL;
        parse->pending_offset = 0;
      }
      ret = gst_pad_push_event (parse->srcpad, event);
      break;
    }
    default:{
      /* stream lock is recursive, should be fine for all events */
      GST_PAD_STREAM_LOCK (pad);
      if (parse->srcpad == NULL) {
        parse->queued_events = g_list_append (parse->queued_events, event);
      } else {
        ret = gst_pad_push_event (parse->srcpad, event);
      }
      GST_PAD_STREAM_UNLOCK (pad);
    }
  }


  gst_object_unref (parse);
  return ret;
}
예제 #8
0
static gboolean
speex_dec_src_query (GstPad * pad, GstQuery * query)
{
  GstSpeexDec *dec;
  gboolean res = FALSE;

  dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:{
      GstSegment segment;
      GstFormat format;
      gint64 cur;

      gst_query_parse_position (query, &format, NULL);

      GST_PAD_STREAM_LOCK (dec->sinkpad);
      segment = dec->segment;
      GST_PAD_STREAM_UNLOCK (dec->sinkpad);

      if (segment.format != GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (dec, "segment not initialised yet");
        break;
      }

      if ((res = speex_dec_convert (dec->srcpad, GST_FORMAT_TIME,
                  segment.last_stop, &format, &cur))) {
        gst_query_set_position (query, format, cur);
      }
      break;
    }
    case GST_QUERY_DURATION:{
      GstFormat format = GST_FORMAT_TIME;
      gint64 dur;

      /* get duration from demuxer */
      if (!gst_pad_query_peer_duration (dec->sinkpad, &format, &dur))
        break;

      gst_query_parse_duration (query, &format, NULL);

      /* and convert it into the requested format */
      if ((res = speex_dec_convert (dec->srcpad, GST_FORMAT_TIME,
                  dur, &format, &dur))) {
        gst_query_set_duration (query, format, dur);
      }
      break;
    }
    default:
      res = gst_pad_query_default (pad, query);
      break;
  }

  gst_object_unref (dec);
  return res;
}
예제 #9
0
static gboolean
gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstFunnel *funnel = GST_FUNNEL (parent);
  GstFunnelPad *fpad = GST_FUNNEL_PAD_CAST (pad);
  gboolean forward = TRUE;
  gboolean res = TRUE;
  gboolean unlock = FALSE;

  GST_DEBUG_OBJECT (pad, "received event %" GST_PTR_FORMAT, event);

  if (GST_EVENT_IS_STICKY (event)) {
    unlock = TRUE;
    GST_PAD_STREAM_LOCK (funnel->srcpad);

    if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
      GST_OBJECT_LOCK (funnel);
      fpad->got_eos = TRUE;
      if (!gst_funnel_all_sinkpads_eos_unlocked (funnel, pad)) {
        forward = FALSE;
      } else {
        forward = TRUE;
      }
      GST_OBJECT_UNLOCK (funnel);
    } else if (pad != funnel->last_sinkpad) {
      forward = FALSE;
    }
  } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
    unlock = TRUE;
    GST_PAD_STREAM_LOCK (funnel->srcpad);
    GST_OBJECT_LOCK (funnel);
    fpad->got_eos = FALSE;
    GST_OBJECT_UNLOCK (funnel);
  } else if (GST_EVENT_TYPE (event) == GST_EVENT_GAP) {
    /* If no data is coming and we receive GAP event, need to forward sticky events. */
    unlock = TRUE;
    GST_PAD_STREAM_LOCK (funnel->srcpad);
    GST_OBJECT_LOCK (funnel);
    gst_object_replace ((GstObject **) & funnel->last_sinkpad,
        GST_OBJECT (pad));
    GST_OBJECT_UNLOCK (funnel);
    gst_pad_sticky_events_foreach (pad, forward_events, funnel->srcpad);
  }

  if (forward)
    res = gst_pad_push_event (funnel->srcpad, event);
  else
    gst_event_unref (event);

  if (unlock)
    GST_PAD_STREAM_UNLOCK (funnel->srcpad);

  return res;
}
예제 #10
0
static gboolean
gst_rnd_buffer_size_src_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstRndBufferSize *self;
  GstSeekType start_type;
  GstSeekFlags flags;
  GstFormat format;
  gint64 start;

  if (GST_EVENT_TYPE (event) != GST_EVENT_SEEK) {
    GST_WARNING_OBJECT (pad, "dropping %s event", GST_EVENT_TYPE_NAME (event));
    return FALSE;
  }

  self = GST_RND_BUFFER_SIZE (parent);
  gst_event_parse_seek (event, NULL, &format, &flags, &start_type, &start,
      NULL, NULL);

  if (format != GST_FORMAT_BYTES) {
    GST_WARNING_OBJECT (pad, "only BYTE format supported");
    return FALSE;
  }
  if (start_type != GST_SEEK_TYPE_SET) {
    GST_WARNING_OBJECT (pad, "only SEEK_TYPE_SET supported");
    return FALSE;
  }

  if ((flags & GST_SEEK_FLAG_FLUSH)) {
    gst_pad_push_event (self->srcpad, gst_event_new_flush_start ());
    gst_pad_push_event (self->sinkpad, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (self->sinkpad);
  }

  GST_PAD_STREAM_LOCK (self->sinkpad);

  if ((flags & GST_SEEK_FLAG_FLUSH)) {
    gst_pad_push_event (self->srcpad, gst_event_new_flush_stop (TRUE));
    gst_pad_push_event (self->sinkpad, gst_event_new_flush_stop (TRUE));
  }

  GST_INFO_OBJECT (pad, "seeking to offset %" G_GINT64_FORMAT, start);

  self->offset = start;
  self->need_newsegment = TRUE;

  gst_pad_start_task (self->sinkpad, (GstTaskFunction) gst_rnd_buffer_size_loop,
      self);

  GST_PAD_STREAM_UNLOCK (self->sinkpad);
  return TRUE;
}
예제 #11
0
/** call control(FLUSH), and then process() to pop out all buffers */
static gboolean
codec_flush (GstDucatiVidDec * self, gboolean eos)
{
  gint err;

  GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);

  /* note: flush is synchronized against _chain() to avoid calling
   * the codec from multiple threads
   */
  GST_PAD_STREAM_LOCK (self->sinkpad);

  if (G_UNLIKELY (self->first_in_buffer)) {
    return TRUE;
  }

  if (G_UNLIKELY (!self->codec)) {
    GST_WARNING_OBJECT (self, "no codec");
    return TRUE;
  }

  err = VIDDEC3_control (self->codec, XDM_FLUSH,
      self->dynParams, self->status);
  if (err) {
    GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
    goto out;
  }

  self->inBufs->descs[0].bufSize.bytes = 0;
  self->inArgs->numBytes = 0;
  self->inArgs->inputID = 0;

  do {
    err = codec_process (self, eos, TRUE);
  } while (err != XDM_EFAIL);

  /* on a flush, it is normal (and not an error) for the last _process() call
   * to return an error..
   */
  err = XDM_EOK;

out:
  GST_PAD_STREAM_UNLOCK (self->sinkpad);
  GST_DEBUG_OBJECT (self, "done");

  return !err;
}
static gboolean
set_element_zoom (GstWrapperCameraBinSrc * self, gfloat zoom)
{
  gboolean ret = FALSE;
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
  gint w2_crop = 0, h2_crop = 0;
  GstPad *pad_zoom_sink = NULL;
  gint left = self->base_crop_left;
  gint right = self->base_crop_right;
  gint top = self->base_crop_top;
  gint bottom = self->base_crop_bottom;

  if (self->src_zoom_crop) {
    /* Update capsfilters to apply the zoom */
    GST_INFO_OBJECT (self, "zoom: %f, orig size: %dx%d", zoom,
        bcamsrc->width, bcamsrc->height);

    if (zoom != ZOOM_1X) {
      w2_crop = (bcamsrc->width - (gint) (bcamsrc->width * ZOOM_1X / zoom)) / 2;
      h2_crop =
          (bcamsrc->height - (gint) (bcamsrc->height * ZOOM_1X / zoom)) / 2;

      left += w2_crop;
      right += w2_crop;
      top += h2_crop;
      bottom += h2_crop;

      /* force number of pixels cropped from left to be even, to avoid slow code
       * path on videoscale */
      left &= 0xFFFE;
    }

    pad_zoom_sink = gst_element_get_static_pad (self->src_zoom_crop, "sink");

    GST_INFO_OBJECT (self,
        "sw cropping: left:%d, right:%d, top:%d, bottom:%d", left, right, top,
        bottom);

    GST_PAD_STREAM_LOCK (pad_zoom_sink);
    g_object_set (self->src_zoom_crop, "left", left, "right", right, "top",
        top, "bottom", bottom, NULL);
    GST_PAD_STREAM_UNLOCK (pad_zoom_sink);
    gst_object_unref (pad_zoom_sink);
    ret = TRUE;
  }
  return ret;
}
예제 #13
0
static gboolean
gst_amc_video_enc_flush (GstVideoEncoder * encoder)
{
  GstAmcVideoEnc *self;
  GError *err = NULL;

  self = GST_AMC_VIDEO_ENC (encoder);

  GST_DEBUG_OBJECT (self, "Flushing encoder");

  if (!self->started) {
    GST_DEBUG_OBJECT (self, "Codec not started yet");
    return TRUE;
  }

  self->flushing = TRUE;
  gst_amc_codec_flush (self->codec, &err);
  if (err)
    GST_ELEMENT_WARNING_FROM_ERROR (self, err);

  /* Wait until the srcpad loop is finished,
   * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
   * caused by using this lock from inside the loop function */
  GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
  GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
  GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
  GST_VIDEO_ENCODER_STREAM_LOCK (self);
  self->flushing = FALSE;

  /* Start the srcpad loop again */
  self->last_upstream_ts = 0;
  self->drained = TRUE;
  self->downstream_flow_ret = GST_FLOW_OK;
  gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
      (GstTaskFunction) gst_amc_video_enc_loop, encoder, NULL);

  GST_DEBUG_OBJECT (self, "Flush encoder");

  return TRUE;
}
예제 #14
0
static gboolean
gst_dvd_spu_subpic_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstDVDSpu *dvdspu = (GstDVDSpu *) parent;
  gboolean res = TRUE;

  /* Some events on the subpicture sink pad just get ignored, like 
   * FLUSH_START */
  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      res = gst_dvd_spu_subpic_set_caps (pad, caps);
      gst_event_unref (event);
      break;
    }
    case GST_EVENT_CUSTOM_DOWNSTREAM:
    case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:
    case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
    {
      const GstStructure *structure = gst_event_get_structure (event);
      gboolean need_push;

      if (!gst_structure_has_name (structure, "application/x-gst-dvd")) {
        res = gst_pad_event_default (pad, parent, event);
        break;
      }

      DVD_SPU_LOCK (dvdspu);
      if (GST_EVENT_IS_SERIALIZED (event)) {
        SpuPacket *spu_packet = g_new0 (SpuPacket, 1);
        GST_DEBUG_OBJECT (dvdspu,
            "Enqueueing DVD event on subpicture pad for later");
        spu_packet->event = event;
        g_queue_push_tail (dvdspu->pending_spus, spu_packet);
      } else {
        gst_dvd_spu_handle_dvd_event (dvdspu, event);
      }

      /* If the handle_dvd_event generated a pending frame, we
       * need to synchronise with the video pad's stream lock and push it.
       * This requires some dancing to preserve locking order and handle
       * flushes correctly */
      need_push = (dvdspu->pending_frame != NULL);
      DVD_SPU_UNLOCK (dvdspu);
      if (need_push) {
        GstBuffer *to_push = NULL;
        gboolean flushing;

        GST_LOG_OBJECT (dvdspu, "Going for stream lock");
        GST_PAD_STREAM_LOCK (dvdspu->videosinkpad);
        GST_LOG_OBJECT (dvdspu, "Got stream lock");
        GST_OBJECT_LOCK (dvdspu->videosinkpad);
        flushing = GST_PAD_IS_FLUSHING (dvdspu->videosinkpad);
        GST_OBJECT_UNLOCK (dvdspu->videosinkpad);

        DVD_SPU_LOCK (dvdspu);
        if (dvdspu->pending_frame == NULL || flushing) {
          /* Got flushed while waiting for the stream lock */
          DVD_SPU_UNLOCK (dvdspu);
        } else {
          to_push = dvdspu->pending_frame;
          dvdspu->pending_frame = NULL;

          DVD_SPU_UNLOCK (dvdspu);
          gst_pad_push (dvdspu->srcpad, to_push);
        }
        GST_LOG_OBJECT (dvdspu, "Dropping stream lock");
        GST_PAD_STREAM_UNLOCK (dvdspu->videosinkpad);
      }

      break;
    }
    case GST_EVENT_SEGMENT:
    {
      GstSegment seg;

      gst_event_copy_segment (event, &seg);

      /* Only print updates if they have an end time (don't print start_time
       * updates */
      GST_DEBUG_OBJECT (dvdspu, "subpic pad Segment: %" GST_SEGMENT_FORMAT,
          &seg);

      DVD_SPU_LOCK (dvdspu);

      dvdspu->subp_seg = seg;
      GST_LOG_OBJECT (dvdspu, "Subpicture segment now: %" GST_SEGMENT_FORMAT,
          &dvdspu->subp_seg);
      DVD_SPU_UNLOCK (dvdspu);

      gst_event_unref (event);
      break;
    }
    case GST_EVENT_GAP:
    {
      GstClockTime timestamp, duration;
      gst_event_parse_gap (event, &timestamp, &duration);
      if (GST_CLOCK_TIME_IS_VALID (duration))
        timestamp += duration;

      DVD_SPU_LOCK (dvdspu);
      dvdspu->subp_seg.position = timestamp;
      GST_LOG_OBJECT (dvdspu, "Received GAP. Segment now: %" GST_SEGMENT_FORMAT,
          &dvdspu->subp_seg);
      DVD_SPU_UNLOCK (dvdspu);

      gst_event_unref (event);
      break;
    }
    case GST_EVENT_FLUSH_START:
      gst_event_unref (event);
      goto done;
    case GST_EVENT_FLUSH_STOP:
      GST_DEBUG_OBJECT (dvdspu, "Have flush-stop event on SPU pad");
      DVD_SPU_LOCK (dvdspu);
      gst_segment_init (&dvdspu->subp_seg, GST_FORMAT_UNDEFINED);
      gst_dvd_spu_flush_spu_info (dvdspu, TRUE);
      DVD_SPU_UNLOCK (dvdspu);

      /* We don't forward flushes on the spu pad */
      gst_event_unref (event);
      goto done;
    case GST_EVENT_EOS:
      /* drop EOS on the subtitle pad, it means there are no more subtitles,
       * video might still continue, though */
      gst_event_unref (event);
      goto done;
      break;
    default:
      res = gst_pad_event_default (pad, parent, event);
      break;
  }

done:

  return res;
}
예제 #15
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;
  }
}
static gboolean
gst_type_find_element_seek (GstTypeFindElement * typefind, GstEvent * event)
{
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  GstFormat format;
  gboolean flush;
  gdouble rate;
  gint64 start, stop;
  GstSegment seeksegment = { 0, };

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

  /* we can only seek on bytes */
  if (format != GST_FORMAT_BYTES) {
    GST_DEBUG_OBJECT (typefind, "Can only seek on BYTES");
    return FALSE;
  }

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

  GST_DEBUG_OBJECT (typefind, "configuring seek");
  gst_segment_do_seek (&seeksegment, rate, format, flags,
      start_type, start, stop_type, stop, NULL);

  flush = ! !(flags & GST_SEEK_FLAG_FLUSH);

  GST_DEBUG_OBJECT (typefind, "New segment %" GST_SEGMENT_FORMAT, &seeksegment);

  if (flush) {
    GST_DEBUG_OBJECT (typefind, "Starting flush");
    gst_pad_push_event (typefind->sink, gst_event_new_flush_start ());
    gst_pad_push_event (typefind->src, gst_event_new_flush_start ());
  } else {
    GST_DEBUG_OBJECT (typefind, "Non-flushing seek, pausing task");
    gst_pad_pause_task (typefind->sink);
  }

  /* 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_DEBUG_OBJECT (typefind, "Waiting for streaming to stop");
  GST_PAD_STREAM_LOCK (typefind->sink);

  if (flush) {
    GST_DEBUG_OBJECT (typefind, "Stopping flush");
    gst_pad_push_event (typefind->sink, gst_event_new_flush_stop (TRUE));
    gst_pad_push_event (typefind->src, gst_event_new_flush_stop (TRUE));
  }

  /* now update the real segment info */
  GST_DEBUG_OBJECT (typefind, "Committing new seek segment");
  memcpy (&typefind->segment, &seeksegment, sizeof (GstSegment));
  typefind->offset = typefind->segment.start;

  /* notify start of new segment */
  if (typefind->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
    GstMessage *msg;

    msg = gst_message_new_segment_start (GST_OBJECT (typefind),
        GST_FORMAT_BYTES, typefind->segment.start);
    gst_element_post_message (GST_ELEMENT (typefind), msg);
  }

  typefind->need_segment = TRUE;

  /* restart our task since it might have been stopped when we did the
   * flush. */
  gst_pad_start_task (typefind->sink,
      (GstTaskFunction) gst_type_find_element_loop, typefind->sink, NULL);

  /* streaming can continue now */
  GST_PAD_STREAM_UNLOCK (typefind->sink);

  return TRUE;
}
예제 #17
0
/* GstAggregator vmethods default implementations */
static gboolean
_sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event)
{
  gboolean res = TRUE;
  GstPad *pad = GST_PAD (aggpad);
  GstAggregatorPrivate *priv = self->priv;
  GstAggregatorPadPrivate *padpriv = aggpad->priv;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
    {
      GstBuffer *tmpbuf;

      g_atomic_int_set (&aggpad->priv->flushing, TRUE);
      /*  Remove pad buffer and wake up the streaming thread */
      tmpbuf = gst_aggregator_pad_steal_buffer (aggpad);
      gst_buffer_replace (&tmpbuf, NULL);
      if (g_atomic_int_compare_and_exchange (&padpriv->pending_flush_start,
              TRUE, FALSE) == TRUE) {
        GST_DEBUG_OBJECT (aggpad, "Expecting FLUSH_STOP now");
        g_atomic_int_set (&padpriv->pending_flush_stop, TRUE);
      }

      if (g_atomic_int_get (&priv->flush_seeking)) {
        /* If flush_seeking we forward the first FLUSH_START */
        if (g_atomic_int_compare_and_exchange (&priv->pending_flush_start,
                TRUE, FALSE) == TRUE) {

          GST_DEBUG_OBJECT (self, "Flushing, pausing srcpad task");
          _stop_srcpad_task (self, event);
          priv->flow_return = GST_FLOW_OK;

          GST_INFO_OBJECT (self, "Getting STREAM_LOCK while seeking");
          GST_PAD_STREAM_LOCK (self->srcpad);
          GST_LOG_OBJECT (self, "GOT STREAM_LOCK");
          event = NULL;
          goto eat;
        }
      }

      /* We forward only in one case: right after flush_seeking */
      goto eat;
    }
    case GST_EVENT_FLUSH_STOP:
    {
      GST_DEBUG_OBJECT (aggpad, "Got FLUSH_STOP");

      _aggpad_flush (aggpad, self);
      if (g_atomic_int_get (&priv->flush_seeking)) {
        g_atomic_int_set (&aggpad->priv->pending_flush_stop, FALSE);

        if (g_atomic_int_get (&priv->flush_seeking)) {
          if (_all_flush_stop_received (self)) {
            /* That means we received FLUSH_STOP/FLUSH_STOP on
             * all sinkpads -- Seeking is Done... sending FLUSH_STOP */
            _flush (self);
            gst_pad_push_event (self->srcpad, event);
            priv->send_eos = TRUE;
            event = NULL;
            _add_aggregate_gsource (self);

            GST_INFO_OBJECT (self, "Releasing source pad STREAM_LOCK");
            GST_PAD_STREAM_UNLOCK (self->srcpad);
            _start_srcpad_task (self);
          }
        }
      }

      /* We never forward the event */
      goto eat;
    }
    case GST_EVENT_EOS:
    {
      GST_DEBUG_OBJECT (aggpad, "EOS");

      /* We still have a buffer, and we don't want the subclass to have to
       * check for it. Mark pending_eos, eos will be set when steal_buffer is
       * called
       */
      PAD_LOCK_EVENT (aggpad);
      if (!aggpad->buffer) {
        aggpad->eos = TRUE;
      } else {
        aggpad->priv->pending_eos = TRUE;
      }
      PAD_UNLOCK_EVENT (aggpad);

      _add_aggregate_gsource (self);
      goto eat;
    }
    case GST_EVENT_SEGMENT:
    {
      PAD_LOCK_EVENT (aggpad);
      gst_event_copy_segment (event, &aggpad->segment);
      PAD_UNLOCK_EVENT (aggpad);
      goto eat;
    }
    case GST_EVENT_STREAM_START:
    {
      goto eat;
    }
    case GST_EVENT_TAG:
    {
      GstTagList *tags;

      gst_event_parse_tag (event, &tags);

      if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) {
        gst_aggregator_merge_tags (self, tags, GST_TAG_MERGE_REPLACE);
        gst_event_unref (event);
        event = NULL;
        goto eat;
      }
      break;
    }
    default:
    {
      break;
    }
  }

  GST_DEBUG_OBJECT (pad, "Forwarding event: %" GST_PTR_FORMAT, event);
  return gst_pad_event_default (pad, GST_OBJECT (self), event);

eat:
  GST_DEBUG_OBJECT (pad, "Eating event: %" GST_PTR_FORMAT, event);
  if (event)
    gst_event_unref (event);

  return res;
}
예제 #18
0
static gboolean
gst_midi_parse_perform_seek (GstMidiParse * midiparse, GstEvent * event)
{
  gboolean res = TRUE, tres;
  gdouble rate;
  GstFormat seek_format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  gboolean flush;
  gboolean update;
  GstSegment seeksegment;
  guint32 seqnum;
  GstEvent *tevent;

  GST_DEBUG_OBJECT (midiparse, "doing seek: %" GST_PTR_FORMAT, event);

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

    if (seek_format != GST_FORMAT_TIME)
      goto invalid_format;

    flush = flags & GST_SEEK_FLAG_FLUSH;
    seqnum = gst_event_get_seqnum (event);
  } else {
    flush = FALSE;
    /* get next seqnum */
    seqnum = gst_util_seqnum_next ();
  }

  /* send flush start */
  if (flush) {
    tevent = gst_event_new_flush_start ();
    gst_event_set_seqnum (tevent, seqnum);
    gst_pad_push_event (midiparse->srcpad, tevent);
  } else
    gst_pad_pause_task (midiparse->srcpad);

  /* grab streaming lock, this should eventually be possible, either
   * because the task is paused, our streaming thread stopped
   * or because our peer is flushing. */
  GST_PAD_STREAM_LOCK (midiparse->sinkpad);
  if (G_UNLIKELY (midiparse->seqnum == seqnum)) {
    /* we have seen this event before, issue a warning for now */
    GST_WARNING_OBJECT (midiparse, "duplicate event found %" G_GUINT32_FORMAT,
        seqnum);
  } else {
    midiparse->seqnum = seqnum;
    GST_DEBUG_OBJECT (midiparse, "seek with seqnum %" G_GUINT32_FORMAT, seqnum);
  }

  /* Copy the current segment info into the temp segment that we can actually
   * attempt the seek with. We only update the real segment if the seek succeeds. */
  memcpy (&seeksegment, &midiparse->segment, sizeof (GstSegment));

  /* now configure the final seek segment */
  if (event) {
    gst_segment_do_seek (&seeksegment, rate, seek_format, flags,
        start_type, start, stop_type, stop, &update);
  }

  /* Else, no seek event passed, so we're just (re)starting the
     current segment. */
  GST_DEBUG_OBJECT (midiparse, "segment configured from %" G_GINT64_FORMAT
      " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
      seeksegment.start, seeksegment.stop, seeksegment.position);

  /* do the seek, segment.position contains the new position. */
  res = gst_midi_parse_do_seek (midiparse, &seeksegment);

  /* and prepare to continue streaming */
  if (flush) {
    tevent = gst_event_new_flush_stop (TRUE);
    gst_event_set_seqnum (tevent, seqnum);
    /* send flush stop, peer will accept data and events again. We
     * are not yet providing data as we still have the STREAM_LOCK. */
    gst_pad_push_event (midiparse->srcpad, tevent);
  }

  /* if the seek was successful, we update our real segment and push
   * out the new segment. */
  if (res) {
    GST_OBJECT_LOCK (midiparse);
    memcpy (&midiparse->segment, &seeksegment, sizeof (GstSegment));
    GST_OBJECT_UNLOCK (midiparse);

    if (seeksegment.flags & GST_SEGMENT_FLAG_SEGMENT) {
      GstMessage *message;

      message = gst_message_new_segment_start (GST_OBJECT (midiparse),
          seeksegment.format, seeksegment.position);
      gst_message_set_seqnum (message, seqnum);

      gst_element_post_message (GST_ELEMENT (midiparse), message);
    }
    /* 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 = seeksegment.stop) == -1)
      stop = seeksegment.duration;

    midiparse->segment_pending = TRUE;
    midiparse->discont = TRUE;
  }

  /* and restart the task in case it got paused explicitly or by
   * the FLUSH_START event we pushed out. */
  tres =
      gst_pad_start_task (midiparse->sinkpad,
      (GstTaskFunction) gst_midi_parse_loop, midiparse->sinkpad, NULL);
  if (res && !tres)
    res = FALSE;

  /* and release the lock again so we can continue streaming */
  GST_PAD_STREAM_UNLOCK (midiparse->sinkpad);

  return res;

  /* ERROR */
invalid_format:
  {
    GST_DEBUG_OBJECT (midiparse, "Unsupported seek format %s",
        gst_format_get_name (seek_format));
    return FALSE;
  }
}
예제 #19
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;
}
예제 #20
0
/***********************************************************************************
 * Seek implementation
 ***********************************************************************************/
static gboolean progress_buffer_perform_push_seek(ProgressBuffer *element, GstPad *pad, GstEvent *event)
{
    GstFormat    format;
    gdouble      rate;
    GstSeekFlags flags;
    GstSeekType  start_type, stop_type;
    gint64       position;
    GstSegment   segment;

    gst_event_parse_seek(event, &rate, &format, &flags, &start_type, &position, &stop_type, NULL);

    if (format != GST_FORMAT_BYTES || start_type != GST_SEEK_TYPE_SET)
        return FALSE;

    if (stop_type != GST_SEEK_TYPE_NONE)
    {
        gst_element_message_full(GST_ELEMENT(element),
            GST_MESSAGE_WARNING,
            GST_CORE_ERROR,
            GST_CORE_ERROR_SEEK, g_strdup("stop_type != GST_SEEK_TYPE_NONE. Seeking to stop is not supported."), NULL,
            ("progressbuffer.c"), ("progress_buffer_perform_push_seek"), 0);
        return FALSE;
    }

    if (flags & GST_SEEK_FLAG_FLUSH)
        gst_pad_push_event(pad, gst_event_new_flush_start());

    // Signal the task to stop if it's waiting.
    g_mutex_lock(&element->lock);
    element->srcresult = GST_FLOW_FLUSHING;
    g_cond_signal(&element->add_cond);
    g_mutex_unlock(&element->lock);

    GST_PAD_STREAM_LOCK(pad); // Wait for task to stop

    g_mutex_lock(&element->lock);
    element->srcresult = GST_FLOW_OK;

#ifdef ENABLE_SOURCE_SEEKING
    element->instant_seek = (position >= element->sink_segment.start &&
                             (position - (gint64)element->sink_segment.position) <= element->bandwidth * element->wait_tolerance);

    if (element->instant_seek)
    {
        cache_set_read_position(element->cache, position - element->cache_read_offset);
        gst_segment_init(&segment, GST_FORMAT_BYTES);
        segment.rate = rate;
        segment.start = position;
        segment.stop = element->sink_segment.stop;
        segment.position = position;
        progress_buffer_set_pending_event(element, gst_event_new_segment(&segment));
    }
    else
    {
        // Clear any pending events, since we doing seek.
        reset_eos(element, TRUE);
    }
#else
    cache_set_read_position(element->cache, position - element->cache_read_offset);
    gst_segment_init(&segment, GST_FORMAT_BYTES);
    segment.rate = rate;
    segment.start = position;
    segment.stop = element->sink_segment.stop;
    segment.position = position;
    progress_buffer_set_pending_event(element, gst_event_new_segment(&segment));
#endif

    g_mutex_unlock(&element->lock);

#ifdef ENABLE_SOURCE_SEEKING
    if (!element->instant_seek)
    {
        element->is_source_seeking = TRUE;
        if (!gst_pad_push_event(element->sinkpad, gst_event_new_seek(rate, GST_FORMAT_BYTES, flags, GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, 0)))
        {
            element->instant_seek = TRUE;
            cache_set_read_position(element->cache, position - element->cache_read_offset);
            gst_segment_init(&segment, GST_FORMAT_BYTES);
            segment.rate = rate;
            segment.start = position;
            segment.stop = element->sink_segment.stop;
            segment.position = position;
            progress_buffer_set_pending_event(element, gst_event_new_segment(&segment));
        }
        element->is_source_seeking = FALSE;
    }
#endif

    if (flags & GST_SEEK_FLAG_FLUSH)
        gst_pad_push_event(pad, gst_event_new_flush_stop(TRUE));

    gst_pad_start_task(element->srcpad, progress_buffer_loop, element, NULL);
    GST_PAD_STREAM_UNLOCK(pad);

// INLINE - gst_event_unref()
    gst_event_unref(event);
    return TRUE;
}
예제 #21
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;
#ifdef HAVE_WILDMIDI_0_2_2
  gboolean accurate;
#endif
  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);
#ifdef HAVE_WILDMIDI_0_2_2
  accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
#endif

  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 (TRUE));
  }

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

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

  GST_OBJECT_LOCK (wildmidi);
#ifdef HAVE_WILDMIDI_0_2_2
  if (accurate) {
    WildMidi_SampledSeek (wildmidi->song, &sample);
  } else {
    WildMidi_FastSeek (wildmidi->song, &sample);
  }
#else
  WildMidi_FastSeek (wildmidi->song, &sample);
#endif

  GST_OBJECT_UNLOCK (wildmidi);

  segment->start = segment->time = segment->position = 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, NULL);

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

  return TRUE;
}
예제 #22
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_do_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 (TRUE));

  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 >= segment.duration) {
    GST_WARNING_OBJECT (dec, "seek out of bounds");
    goto failed;
  }
  if (mpc_demux_seek_sample (dec->d, segment.start) != MPC_STATUS_OK)
    goto failed;

  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 (TRUE));
  }

  segment.position = 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, NULL);

  GST_PAD_STREAM_UNLOCK (dec->sinkpad);

  return TRUE;

failed:
  {
    GST_WARNING_OBJECT (dec, "seek failed");
    GST_PAD_STREAM_UNLOCK (dec->sinkpad);
    return FALSE;
  }
}
예제 #23
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;
}
예제 #24
0
gboolean
mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
    GstEvent * event)
{
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
  GstFlowReturn ret = GST_FLOW_ERROR;
  gdouble rate;
  gboolean flush;
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  GstEvent *flush_event = NULL;

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

  if (format != GST_FORMAT_TIME)
    return FALSE;

  if (GST_EVENT_SEQNUM (event) == base->last_seek_seqnum) {
    GST_DEBUG_OBJECT (base, "Skipping already handled seek");
    return TRUE;
  }

  if (base->mode == BASE_MODE_PUSHING) {
    /* First try if upstream supports seeking in TIME format */
    if (gst_pad_push_event (base->sinkpad, gst_event_ref (event))) {
      GST_DEBUG ("upstream handled SEEK event");
      return TRUE;
    }

    /* If the subclass can seek, do that */
    if (klass->seek) {
      ret = klass->seek (base, event);
      if (G_UNLIKELY (ret != GST_FLOW_OK))
        GST_WARNING ("seeking failed %s", gst_flow_get_name (ret));
      else {
        GstEvent *new_seek;

        if (GST_CLOCK_TIME_IS_VALID (base->seek_offset)) {
          base->mode = BASE_MODE_SEEKING;
          new_seek = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
              GST_SEEK_TYPE_SET, base->seek_offset, GST_SEEK_TYPE_NONE, -1);
          gst_event_set_seqnum (new_seek, GST_EVENT_SEQNUM (event));
          if (!gst_pad_push_event (base->sinkpad, new_seek))
            ret = GST_FLOW_ERROR;
          else
            base->last_seek_seqnum = GST_EVENT_SEQNUM (event);
        }
        base->mode = BASE_MODE_PUSHING;
      }
    } else {
      GST_WARNING ("subclass has no seek implementation");
    }

    return ret == GST_FLOW_OK;
  }

  if (!klass->seek) {
    GST_WARNING ("subclass has no seek implementation");
    return FALSE;
  }

  if (rate <= 0.0) {
    GST_WARNING ("Negative rate not supported");
    return FALSE;
  }

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

  flush = flags & GST_SEEK_FLAG_FLUSH;

  /* stop streaming, either by flushing or by pausing the task */
  base->mode = BASE_MODE_SEEKING;
  if (flush) {
    GST_DEBUG_OBJECT (base, "sending flush start");
    flush_event = gst_event_new_flush_start ();
    gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event));
    gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event));
    GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event);
  } else
    gst_pad_pause_task (base->sinkpad);

  /* wait for streaming to finish */
  GST_PAD_STREAM_LOCK (base->sinkpad);

  if (flush) {
    /* send a FLUSH_STOP for the sinkpad, since we need data for seeking */
    GST_DEBUG_OBJECT (base, "sending flush stop");
    flush_event = gst_event_new_flush_stop (TRUE);
    gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event));

    /* ref for it to be reused later */
    gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event));
    /* And actually flush our pending data but allow to preserve some info
     * to perform the seek */
    mpegts_base_flush (base, FALSE);
    mpegts_packetizer_flush (base->packetizer, FALSE);
  }

  if (flags & (GST_SEEK_FLAG_SEGMENT)) {
    GST_WARNING ("seek flags 0x%x are not supported", (int) flags);
    goto done;
  }


  /* If the subclass can seek, do that */
  ret = klass->seek (base, event);
  if (G_UNLIKELY (ret != GST_FLOW_OK))
    GST_WARNING ("seeking failed %s", gst_flow_get_name (ret));
  else
    base->last_seek_seqnum = GST_EVENT_SEQNUM (event);

  if (flush_event) {
    /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
    GST_DEBUG_OBJECT (base, "sending flush stop");
    GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event);
    flush_event = NULL;
  }
done:
  if (flush_event)
    gst_event_unref (flush_event);
  gst_pad_start_task (base->sinkpad, (GstTaskFunction) mpegts_base_loop, base,
      NULL);

  GST_PAD_STREAM_UNLOCK (base->sinkpad);
  return ret == GST_FLOW_OK;
}
예제 #25
0
static gboolean
gst_spc_dec_src_event (GstPad * pad, GstEvent * event)
{
  GstSpcDec *spc = GST_SPC_DEC (gst_pad_get_parent (pad));
  gboolean result = FALSE;

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

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

      if (format != GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (spc, "seeking is only supported in TIME format");
        break;
      }

      if (start_type != GST_SEEK_TYPE_SET || stop_type != GST_SEEK_TYPE_NONE) {
        GST_DEBUG_OBJECT (spc, "unsupported seek type");
        break;
      }

      if (stop_type == GST_SEEK_TYPE_NONE)
        stop = GST_CLOCK_TIME_NONE;

      if (start_type == GST_SEEK_TYPE_SET) {
        guint64 cur =
            gst_util_uint64_scale (spc->byte_pos, GST_SECOND, 32000 * 2 * 2);
        guint64 dest = (guint64) start;

        dest = CLAMP (dest, 0, gst_spc_duration (spc) + gst_spc_fadeout (spc));

        if (dest == cur)
          break;

        flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;

        if (flush) {
          gst_pad_push_event (spc->srcpad, gst_event_new_flush_start ());
        } else {
          gst_pad_stop_task (spc->srcpad);
        }

        GST_PAD_STREAM_LOCK (spc->srcpad);

        if (flags & GST_SEEK_FLAG_SEGMENT) {
          gst_element_post_message (GST_ELEMENT (spc),
              gst_message_new_segment_start (GST_OBJECT (spc), format, cur));
        }

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

        if (stop == GST_CLOCK_TIME_NONE)
          stop = (guint64) (gst_spc_duration (spc) + gst_spc_fadeout (spc));

        gst_pad_push_event (spc->srcpad, gst_event_new_new_segment (FALSE, rate,
                GST_FORMAT_TIME, dest, stop, dest));

        /* spc->byte_pos += OSPC_Run(-1, NULL, (unsigned int) (gst_util_uint64_scale(dest - cur, 32000*2*2, GST_SECOND))); */
        spc->seekpoint =
            gst_util_uint64_scale (dest, 32000 * 2 * 2, GST_SECOND);
        spc->seeking = TRUE;

        gst_pad_start_task (spc->srcpad, (GstTaskFunction) spc_play,
            spc->srcpad);

        GST_PAD_STREAM_UNLOCK (spc->srcpad);
        result = TRUE;
      }
      break;
    }
    default:
      break;
  }

  gst_event_unref (event);
  gst_object_unref (spc);

  return result;
}
예제 #26
0
static gboolean
gst_gme_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstGmeDec *gme = GST_GME_DEC (parent);
  gboolean result = FALSE;

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

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

      gst_event_unref (event);

      if (format != GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (gme, "seeking is only supported in TIME format");
        break;
      }

      if (start_type != GST_SEEK_TYPE_SET || stop_type != GST_SEEK_TYPE_NONE) {
        GST_DEBUG_OBJECT (gme, "unsupported seek type");
        break;
      }

      if (stop_type == GST_SEEK_TYPE_NONE)
        stop = GST_CLOCK_TIME_NONE;

      if (start_type == GST_SEEK_TYPE_SET) {
        GstSegment seg;
        guint64 cur = gme_tell (gme->player) * GST_MSECOND;
        guint64 dest = (guint64) start;

        if (gme->total_duration != GST_CLOCK_TIME_NONE)
          dest = CLAMP (dest, 0, gme->total_duration);
        else
          dest = MAX (0, dest);

        if (dest == cur)
          break;

        flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;

        if (flush) {
          gst_pad_push_event (gme->srcpad, gst_event_new_flush_start ());
        } else {
          gst_pad_stop_task (gme->srcpad);
        }

        GST_PAD_STREAM_LOCK (gme->srcpad);

        if (flags & GST_SEEK_FLAG_SEGMENT) {
          gst_element_post_message (GST_ELEMENT (gme),
              gst_message_new_segment_start (GST_OBJECT (gme), format, cur));
        }

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

        if (stop == GST_CLOCK_TIME_NONE
            && gme->total_duration != GST_CLOCK_TIME_NONE)
          stop = gme->total_duration;

        gst_segment_init (&seg, GST_FORMAT_TIME);
        seg.rate = rate;
        seg.start = dest;
        seg.stop = stop;
        seg.time = dest;
        gst_pad_push_event (gme->srcpad, gst_event_new_segment (&seg));

        gme->seekpoint = dest / GST_MSECOND;    /* nsecs to msecs */
        gme->seeking = TRUE;

        gst_pad_start_task (gme->srcpad, (GstTaskFunction) gst_gme_play,
            gme->srcpad, NULL);

        GST_PAD_STREAM_UNLOCK (gme->srcpad);
        result = TRUE;
      }
      break;
    }
    default:
      result = gst_pad_push_event (gme->sinkpad, event);
      break;
  }

  return result;
}
예제 #27
0
static gboolean
gst_image_freeze_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
    GstImageFreeze *self = GST_IMAGE_FREEZE (parent);
    gboolean ret;

    GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));

    switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NAVIGATION:
    case GST_EVENT_QOS:
    case GST_EVENT_LATENCY:
    case GST_EVENT_STEP:
        GST_DEBUG_OBJECT (pad, "Dropping event");
        gst_event_unref (event);
        ret = TRUE;
        break;
    case GST_EVENT_SEEK: {
        gdouble rate;
        GstFormat format;
        GstSeekFlags flags;
        GstSeekType start_type, stop_type;
        gint64 start, stop;
        gint64 last_stop;
        gboolean start_task;
        gboolean flush;

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

        flush = ! !(flags & GST_SEEK_FLAG_FLUSH);

        if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
            GST_ERROR_OBJECT (pad, "Seek in invalid format: %s",
                              gst_format_get_name (format));
            ret = FALSE;
            break;
        }

        if (format == GST_FORMAT_DEFAULT) {
            format = GST_FORMAT_TIME;
            if (!gst_image_freeze_convert (self, GST_FORMAT_DEFAULT, start, &format,
                                           &start)
                    || !gst_image_freeze_convert (self, GST_FORMAT_DEFAULT, stop,
                                                  &format, &stop)
                    || start == -1 || stop == -1) {
                GST_ERROR_OBJECT (pad,
                                  "Failed to convert seek from DEFAULT format into TIME format");
                ret = FALSE;
                break;
            }
        }

        if (flush) {
            GstEvent *e;

            g_atomic_int_set (&self->seeking, 1);
            e = gst_event_new_flush_start ();
            gst_pad_push_event (self->srcpad, e);
        } else {
            gst_pad_pause_task (self->srcpad);
        }

        GST_PAD_STREAM_LOCK (self->srcpad);

        g_mutex_lock (&self->lock);

        gst_segment_do_seek (&self->segment, rate, format, flags, start_type,
                             start, stop_type, stop, NULL);
        self->need_segment = TRUE;
        last_stop = self->segment.position;

        start_task = self->buffer != NULL;
        g_mutex_unlock (&self->lock);

        if (flush) {
            GstEvent *e;

            e = gst_event_new_flush_stop (TRUE);
            gst_pad_push_event (self->srcpad, e);
            g_atomic_int_set (&self->seeking, 0);
        }

        if (flags & GST_SEEK_FLAG_SEGMENT) {
            GstMessage *m;

            m = gst_message_new_segment_start (GST_OBJECT (self),
                                               format, last_stop);
            gst_element_post_message (GST_ELEMENT (self), m);
        }

        GST_PAD_STREAM_UNLOCK (self->srcpad);

        GST_DEBUG_OBJECT (pad, "Seek successful");

        if (start_task) {
            g_mutex_lock (&self->lock);

            if (self->buffer != NULL)
                gst_pad_start_task (self->srcpad,
                                    (GstTaskFunction) gst_image_freeze_src_loop, self->srcpad, NULL);

            g_mutex_unlock (&self->lock);
        }

        ret = TRUE;
        break;
    }
    case GST_EVENT_FLUSH_START:
        gst_image_freeze_reset (self);
    /* fall through */
    default:
        ret = gst_pad_push_event (self->sinkpad, event);
        break;
    }

    return ret;
}
예제 #28
0
/* GstAggregator vmethods default implementations */
static gboolean
_sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event)
{
  gboolean res = TRUE;
  GstPad *pad = GST_PAD (aggpad);
  GstAggregatorPrivate *priv = self->priv;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
    {
      _flush_start (self, aggpad, event);
      /* We forward only in one case: right after flush_seeking */
      event = NULL;
      goto eat;
    }
    case GST_EVENT_FLUSH_STOP:
    {
      GST_DEBUG_OBJECT (aggpad, "Got FLUSH_STOP");

      _aggpad_flush (aggpad, self);
      if (g_atomic_int_get (&priv->flush_seeking)) {
        g_atomic_int_set (&aggpad->priv->pending_flush_stop, FALSE);

        if (g_atomic_int_get (&priv->flush_seeking)) {
          if (_all_flush_stop_received (self)) {
            /* That means we received FLUSH_STOP/FLUSH_STOP on
             * all sinkpads -- Seeking is Done... sending FLUSH_STOP */
            _flush (self);
            gst_pad_push_event (self->srcpad, event);
            priv->send_eos = TRUE;
            event = NULL;
            QUEUE_PUSH (self);

            GST_INFO_OBJECT (self, "Releasing source pad STREAM_LOCK");
            GST_PAD_STREAM_UNLOCK (self->srcpad);
            _start_srcpad_task (self);
          }
        }
      }

      /* We never forward the event */
      goto eat;
    }
    case GST_EVENT_EOS:
    {
      GST_DEBUG_OBJECT (aggpad, "EOS");

      /* We still have a buffer, and we don't want the subclass to have to
       * check for it. Mark pending_eos, eos will be set when steal_buffer is
       * called
       */
      PAD_LOCK_EVENT (aggpad);
      if (!aggpad->buffer) {
        aggpad->eos = TRUE;
      } else {
        aggpad->priv->pending_eos = TRUE;
      }
      PAD_UNLOCK_EVENT (aggpad);

      QUEUE_PUSH (self);
      goto eat;
    }
    case GST_EVENT_SEGMENT:
    {
      PAD_LOCK_EVENT (aggpad);
      gst_event_copy_segment (event, &aggpad->segment);
      self->priv->seqnum = gst_event_get_seqnum (event);
      PAD_UNLOCK_EVENT (aggpad);
      goto eat;
    }
    case GST_EVENT_STREAM_START:
    {
      goto eat;
    }
    case GST_EVENT_TAG:
    {
      GstTagList *tags;

      gst_event_parse_tag (event, &tags);

      if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) {
        gst_aggregator_merge_tags (self, tags, GST_TAG_MERGE_REPLACE);
        gst_event_unref (event);
        event = NULL;
        goto eat;
      }
      break;
    }
    default:
    {
      break;
    }
  }

  GST_DEBUG_OBJECT (pad, "Forwarding event: %" GST_PTR_FORMAT, event);
  return gst_pad_event_default (pad, GST_OBJECT (self), event);

eat:
  GST_DEBUG_OBJECT (pad, "Eating event: %" GST_PTR_FORMAT, event);
  if (event)
    gst_event_unref (event);

  return res;
}
예제 #29
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;
  }
}
예제 #30
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_do_seek (&seeksegment, rate, format, flags,
        start_type, start, stop_type, stop, NULL);
  }

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

  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 (TRUE));
    gst_pad_push_event (rp->srcpad, gst_event_new_flush_stop (TRUE));
  }

  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.position));
    }

    /* 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);
    rp->start_segment = gst_event_new_segment (&rp->segment);
  }
  rp->discont = TRUE;

  GST_LOG_OBJECT (rp, "start streaming");
  gst_pad_start_task (rp->sinkpad, (GstTaskFunction) gst_raw_parse_loop, rp,
      NULL);

  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;
  }
}