Exemplo n.º 1
0
/* chain function
 * this function does the actual processing
 */
static GstFlowReturn gst_throttle_chain(GstPad * pad, GstBuffer * buf)
{
	GstThrottle * filter = GST_THROTTLE(GST_OBJECT_PARENT(pad));
	
	if (filter->printOnly)
	{
		GstCaps * caps = gst_buffer_get_caps(buf);
		gchar * capsStr = gst_caps_to_string(caps);
		gst_caps_unref(caps);
		GST_LOG_OBJECT(filter, "ts: %" GST_TIME_FORMAT " %sof type %s",
			GST_TIME_ARGS(buf->timestamp),
			GST_BUFFER_IS_DISCONT(buf) ? "and discontinuity " : "",
			capsStr
		);
		g_free(capsStr);
		
		GstFlowReturn ret = gst_pad_push(filter->srcpad, buf);
		GST_TRACE_OBJECT(filter, "ts: %" GST_TIME_FORMAT " processed with status %d", GST_TIME_ARGS(buf->timestamp), ret);
		return ret;
	}
	
	if (filter->clock == NULL)
	{
		return gst_pad_push(filter->srcpad, buf);
	}
	
	GstClockTime realTs = gst_clock_get_time(filter->clock);
	
	if (filter->haveStartTime)
	{
		const char * discont = GST_BUFFER_IS_DISCONT(buf) ? " with discotinuity" : "";
		
		GstClockTime expectedRealTs = filter->streamStartRealTime + buf->timestamp;
		gboolean early = realTs < expectedRealTs;
		if (early)
		{
			GstClockID * cid = gst_clock_new_single_shot_id(filter->clock, expectedRealTs);
			GST_TRACE_OBJECT(filter, "ts: %" GST_TIME_FORMAT " %s, waiting for %ld ms", GST_TIME_ARGS(buf->timestamp), discont, (expectedRealTs - realTs)/1000000);
			gst_clock_id_wait(cid, NULL);
			gst_clock_id_unref(cid);
		}
		else
		{
			GST_TRACE_OBJECT(filter, "ts: %" GST_TIME_FORMAT " %s, pad on time", GST_TIME_ARGS(buf->timestamp), discont);
		}
	}
	else
	{
		filter->streamStartRealTime = realTs - buf->timestamp;
		filter->haveStartTime = TRUE;
	}
	
	return gst_pad_push(filter->srcpad, buf);
}
Exemplo n.º 2
0
/**
 * dxr3videosink_wait:
 *
 * Make the sink wait the specified amount of time.
 */
static void
dxr3videosink_wait (Dxr3VideoSink * sink, GstClockTime time)
{
  GstClockID id;
  GstClockTimeDiff jitter;
  GstClockReturn ret;
  GstClockTime current_time = gst_clock_get_time (sink->clock);

  id = gst_clock_new_single_shot_id (sink->clock, current_time + time);
  ret = gst_clock_id_wait (id, &jitter);
  gst_clock_id_free (id);
}
Exemplo n.º 3
0
static gpointer
no_rtcp_timeout_func (gpointer user_data)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data);
  GstClock *sysclock = NULL;
  GstClockID id;
  gboolean emit = TRUE;

  sysclock = gst_system_clock_obtain ();
  if (sysclock == NULL)
    goto no_sysclock;

  FS_RTP_SUB_STREAM_LOCK(self);
  id = self->priv->no_rtcp_timeout_id = gst_clock_new_single_shot_id (sysclock,
      self->priv->next_no_rtcp_timeout);

  FS_RTP_SUB_STREAM_UNLOCK(self);
  gst_clock_id_wait (id, NULL);
  FS_RTP_SUB_STREAM_LOCK(self);

  gst_clock_id_unref (id);
  self->priv->no_rtcp_timeout_id = NULL;

  if (self->priv->next_no_rtcp_timeout == 0)
    emit = FALSE;

  FS_RTP_SUB_STREAM_UNLOCK(self);

  gst_object_unref (sysclock);

  if (emit)
    g_signal_emit (self, signals[NO_RTCP_TIMEDOUT], 0);

  return NULL;

 no_sysclock:
  {
    fs_rtp_sub_stream_emit_error (self, FS_ERROR_INTERNAL,
        "Could not get system clock",
        "Could not get system clock");
    return NULL;
  }
}
Exemplo n.º 4
0
static GstFlowReturn
gst_identity_do_sync (GstIdentity * identity, GstClockTime running_time)
{
  GstFlowReturn ret = GST_FLOW_OK;

  if (identity->sync &&
      GST_BASE_TRANSFORM_CAST (identity)->segment.format == GST_FORMAT_TIME) {
    GstClock *clock;

    GST_OBJECT_LOCK (identity);

    while (identity->blocked)
      g_cond_wait (&identity->blocked_cond, GST_OBJECT_GET_LOCK (identity));


    if ((clock = GST_ELEMENT (identity)->clock)) {
      GstClockReturn cret;
      GstClockTime timestamp;

      timestamp = running_time + GST_ELEMENT (identity)->base_time +
          identity->upstream_latency;

      /* save id if we need to unlock */
      identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp);
      GST_OBJECT_UNLOCK (identity);

      cret = gst_clock_id_wait (identity->clock_id, NULL);

      GST_OBJECT_LOCK (identity);
      if (identity->clock_id) {
        gst_clock_id_unref (identity->clock_id);
        identity->clock_id = NULL;
      }
      if (cret == GST_CLOCK_UNSCHEDULED)
        ret = GST_FLOW_EOS;
    }
    GST_OBJECT_UNLOCK (identity);
  }

  return ret;
}
Exemplo n.º 5
0
static GstFlowReturn
gst_wasapi_src_create (GstPushSrc * src, GstBuffer ** buf)
{
  GstWasapiSrc *self = GST_WASAPI_SRC (src);
  GstFlowReturn ret = GST_FLOW_OK;
  GstClock *clock;
  GstClockTime timestamp, duration = self->period_time;
  HRESULT hr;
  gint16 *samples = NULL;
  guint32 nsamples_read = 0, nsamples;
  DWORD flags = 0;
  guint64 devpos;

  GST_OBJECT_LOCK (self);
  clock = GST_ELEMENT_CLOCK (self);
  if (clock != NULL)
    gst_object_ref (clock);
  GST_OBJECT_UNLOCK (self);

  if (clock != NULL && GST_CLOCK_TIME_IS_VALID (self->next_time)) {
    GstClockID id;

    id = gst_clock_new_single_shot_id (clock, self->next_time);
    gst_clock_id_wait (id, NULL);
    gst_clock_id_unref (id);
  }

  do {
    hr = IAudioCaptureClient_GetBuffer (self->capture_client,
        (BYTE **) & samples, &nsamples_read, &flags, &devpos, NULL);
  }
  while (hr == AUDCLNT_S_BUFFER_EMPTY);

  if (hr != S_OK) {
    GST_ERROR_OBJECT (self, "IAudioCaptureClient::GetBuffer () failed: %s",
        gst_wasapi_util_hresult_to_string (hr));
    ret = GST_FLOW_ERROR;
    goto beach;
  }

  if (flags != 0) {
    GST_WARNING_OBJECT (self, "devpos %" G_GUINT64_FORMAT ": flags=0x%08x",
        devpos, flags);
  }

  /* FIXME: Why do we get 1024 sometimes and not a multiple of
   *        samples_per_buffer? Shouldn't WASAPI provide a DISCONT
   *        flag if we read too slow?
   */
  nsamples = nsamples_read;
  g_assert (nsamples >= self->samples_per_buffer);
  if (nsamples > self->samples_per_buffer) {
    GST_WARNING_OBJECT (self,
        "devpos %" G_GUINT64_FORMAT ": got %d samples, expected %d, clipping!",
        devpos, nsamples, self->samples_per_buffer);

    nsamples = self->samples_per_buffer;
  }

  if (clock == NULL || clock == self->clock) {
    timestamp =
        gst_util_uint64_scale (devpos, GST_SECOND, self->client_clock_freq);
  } else {
    GstClockTime base_time;

    timestamp = gst_clock_get_time (clock);

    base_time = GST_ELEMENT_CAST (self)->base_time;
    if (timestamp > base_time)
      timestamp -= base_time;
    else
      timestamp = 0;

    if (timestamp > duration)
      timestamp -= duration;
    else
      timestamp = 0;
  }

  ret = gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (self),
      devpos,
      nsamples * sizeof (gint16), GST_PAD_CAPS (GST_BASE_SRC_PAD (self)), buf);

  if (ret == GST_FLOW_OK) {
    guint i;
    gint16 *dst;

    GST_BUFFER_OFFSET_END (*buf) = devpos + self->samples_per_buffer;
    GST_BUFFER_TIMESTAMP (*buf) = timestamp;
    GST_BUFFER_DURATION (*buf) = duration;

    dst = (gint16 *) GST_BUFFER_DATA (*buf);
    for (i = 0; i < nsamples; i++) {
      *dst = *samples;

      samples += 2;
      dst++;
    }
  }

  hr = IAudioCaptureClient_ReleaseBuffer (self->capture_client, nsamples_read);
  if (hr != S_OK) {
    GST_ERROR_OBJECT (self, "IAudioCaptureClient::ReleaseBuffer () failed: %s",
        gst_wasapi_util_hresult_to_string (hr));
    ret = GST_FLOW_ERROR;
    goto beach;
  }

beach:
  if (clock != NULL)
    gst_object_unref (clock);

  return ret;
}
Exemplo n.º 6
0
static GstFlowReturn
gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstIdentity *identity = GST_IDENTITY (trans);
  GstClockTime runtimestamp = G_GINT64_CONSTANT (0);

  if (identity->check_perfect)
    gst_identity_check_perfect (identity, buf);
  if (identity->check_imperfect_timestamp)
    gst_identity_check_imperfect_timestamp (identity, buf);
  if (identity->check_imperfect_offset)
    gst_identity_check_imperfect_offset (identity, buf);

  /* update prev values */
  identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf);
  identity->prev_duration = GST_BUFFER_DURATION (buf);
  identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf);
  identity->prev_offset = GST_BUFFER_OFFSET (buf);

  if (identity->error_after >= 0) {
    identity->error_after--;
    if (identity->error_after == 0) {
      GST_ELEMENT_ERROR (identity, CORE, FAILED,
          (_("Failed after iterations as requested.")), (NULL));
      return GST_FLOW_ERROR;
    }
  }

  if (identity->drop_probability > 0.0) {
    if ((gfloat) (1.0 * rand () / (RAND_MAX)) < identity->drop_probability) {
      if (!identity->silent) {
        GST_OBJECT_LOCK (identity);
        g_free (identity->last_message);
        identity->last_message =
            g_strdup_printf
            ("dropping   ******* (%s:%s)i (%d bytes, timestamp: %"
            GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
            G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT
            ", flags: %d) %p", GST_DEBUG_PAD_NAME (trans->sinkpad),
            GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
            GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
            GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
        GST_OBJECT_UNLOCK (identity);
        g_object_notify (G_OBJECT (identity), "last-message");
      }
      /* return DROPPED to basetransform. */
      return GST_BASE_TRANSFORM_FLOW_DROPPED;
    }
  }

  if (identity->dump) {
    gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
  }

  if (!identity->silent) {
    GST_OBJECT_LOCK (identity);
    g_free (identity->last_message);
    identity->last_message =
        g_strdup_printf ("chain   ******* (%s:%s)i (%d bytes, timestamp: %"
        GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
        G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
        GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (buf),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
        GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf),
        GST_BUFFER_FLAGS (buf), buf);
    GST_OBJECT_UNLOCK (identity);
    g_object_notify (G_OBJECT (identity), "last-message");
  }

  if (identity->datarate > 0) {
    GstClockTime time = gst_util_uint64_scale_int (identity->offset,
        GST_SECOND, identity->datarate);

    GST_BUFFER_TIMESTAMP (buf) = time;
    GST_BUFFER_DURATION (buf) =
        GST_BUFFER_SIZE (buf) * GST_SECOND / identity->datarate;
  }

  if (identity->signal_handoffs)
    g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
        buf);

  if (trans->segment.format == GST_FORMAT_TIME)
    runtimestamp = gst_segment_to_running_time (&trans->segment,
        GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));

  if ((identity->sync) && (trans->segment.format == GST_FORMAT_TIME)) {
    GstClock *clock;

    GST_OBJECT_LOCK (identity);
    if ((clock = GST_ELEMENT (identity)->clock)) {
      GstClockReturn cret;
      GstClockTime timestamp;

      timestamp = runtimestamp + GST_ELEMENT (identity)->base_time;

      /* save id if we need to unlock */
      /* FIXME: actually unlock this somewhere in the state changes */
      identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp);
      GST_OBJECT_UNLOCK (identity);

      cret = gst_clock_id_wait (identity->clock_id, NULL);

      GST_OBJECT_LOCK (identity);
      if (identity->clock_id) {
        gst_clock_id_unref (identity->clock_id);
        identity->clock_id = NULL;
      }
      if (cret == GST_CLOCK_UNSCHEDULED)
        ret = GST_FLOW_UNEXPECTED;
    }
    GST_OBJECT_UNLOCK (identity);
  }

  identity->offset += GST_BUFFER_SIZE (buf);

  if (identity->sleep_time && ret == GST_FLOW_OK)
    g_usleep (identity->sleep_time);

  if (identity->single_segment && (trans->segment.format == GST_FORMAT_TIME)
      && (ret == GST_FLOW_OK)) {
    GST_BUFFER_TIMESTAMP (buf) = runtimestamp;
    GST_BUFFER_OFFSET (buf) = GST_CLOCK_TIME_NONE;
    GST_BUFFER_OFFSET_END (buf) = GST_CLOCK_TIME_NONE;
  }

  return ret;
}
Exemplo n.º 7
0
static GstFlowReturn
gst_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
    guint length, GstBuffer ** buffer)
{
  GstBuffer *buf = NULL;
  GstDTMFSrcEvent *event;
  GstDTMFSrc *dtmfsrc;
  GstClock *clock;
  GstClockID *clockid;
  GstClockReturn clockret;

  dtmfsrc = GST_DTMF_SRC (basesrc);

  do {

    if (dtmfsrc->last_event == NULL) {
      GST_DEBUG_OBJECT (dtmfsrc, "popping");
      event = g_async_queue_pop (dtmfsrc->event_queue);

      GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);

      switch (event->event_type) {
        case DTMF_EVENT_TYPE_STOP:
          GST_WARNING_OBJECT (dtmfsrc,
              "Received a DTMF stop event when already stopped");
          gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
          break;
        case DTMF_EVENT_TYPE_START:
          gst_dtmf_prepare_timestamps (dtmfsrc);

          event->packet_count = 0;
          dtmfsrc->last_event = event;
          event = NULL;
          gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-processed",
              dtmfsrc->last_event);
          break;
        case DTMF_EVENT_TYPE_PAUSE_TASK:
          /*
           * We're pushing it back because it has to stay in there until
           * the task is really paused (and the queue will then be flushed)
           */
          GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
          GST_OBJECT_LOCK (dtmfsrc);
          if (dtmfsrc->paused) {
            g_async_queue_push (dtmfsrc->event_queue, event);
            goto paused_locked;
          }
          GST_OBJECT_UNLOCK (dtmfsrc);
          break;
      }
      if (event)
        g_slice_free (GstDTMFSrcEvent, event);
    } else if (dtmfsrc->last_event->packet_count * dtmfsrc->interval >=
        MIN_DUTY_CYCLE) {
      event = g_async_queue_try_pop (dtmfsrc->event_queue);

      if (event != NULL) {

        switch (event->event_type) {
          case DTMF_EVENT_TYPE_START:
            GST_WARNING_OBJECT (dtmfsrc,
                "Received two consecutive DTMF start events");
            gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
            break;
          case DTMF_EVENT_TYPE_STOP:
            g_slice_free (GstDTMFSrcEvent, dtmfsrc->last_event);
            dtmfsrc->last_event = NULL;
            gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-processed", event);
            break;
          case DTMF_EVENT_TYPE_PAUSE_TASK:
            /*
             * We're pushing it back because it has to stay in there until
             * the task is really paused (and the queue will then be flushed)
             */
            GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");

            GST_OBJECT_LOCK (dtmfsrc);
            if (dtmfsrc->paused) {
              g_async_queue_push (dtmfsrc->event_queue, event);
              goto paused_locked;
            }
            GST_OBJECT_UNLOCK (dtmfsrc);

            break;
        }
        g_slice_free (GstDTMFSrcEvent, event);
      }
    }
  } while (dtmfsrc->last_event == NULL);

  GST_LOG_OBJECT (dtmfsrc, "end event check, now wait for the proper time");

  clock = gst_element_get_clock (GST_ELEMENT (basesrc));

  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
      gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
  gst_object_unref (clock);

  GST_OBJECT_LOCK (dtmfsrc);
  if (!dtmfsrc->paused) {
    dtmfsrc->clockid = clockid;
    GST_OBJECT_UNLOCK (dtmfsrc);

    clockret = gst_clock_id_wait (clockid, NULL);

    GST_OBJECT_LOCK (dtmfsrc);
    if (dtmfsrc->paused)
      clockret = GST_CLOCK_UNSCHEDULED;
  } else {
    clockret = GST_CLOCK_UNSCHEDULED;
  }
  gst_clock_id_unref (clockid);
  dtmfsrc->clockid = NULL;
  GST_OBJECT_UNLOCK (dtmfsrc);

  if (clockret == GST_CLOCK_UNSCHEDULED) {
    goto paused;
  }

  buf = gst_dtmf_src_create_next_tone_packet (dtmfsrc, dtmfsrc->last_event);

  GST_LOG_OBJECT (dtmfsrc, "Created buffer of size %" G_GSIZE_FORMAT,
      gst_buffer_get_size (buf));
  *buffer = buf;

  return GST_FLOW_OK;

paused_locked:
  GST_OBJECT_UNLOCK (dtmfsrc);

paused:

  if (dtmfsrc->last_event) {
    GST_DEBUG_OBJECT (dtmfsrc, "Stopping current event");
    /* Don't forget to release the stream lock */
    g_slice_free (GstDTMFSrcEvent, dtmfsrc->last_event);
    dtmfsrc->last_event = NULL;
  }

  return GST_FLOW_FLUSHING;

}
Exemplo n.º 8
0
static void
gst_live_adder_loop (gpointer data)
{
    GstLiveAdder *adder = GST_LIVE_ADDER (data);
    GstClockTime buffer_timestamp = 0;
    GstClockTime sync_time = 0;
    GstClock *clock = NULL;
    GstClockID id = NULL;
    GstClockReturn ret;
    GstBuffer *buffer = NULL;
    GstFlowReturn result;
    GstEvent *newseg_event = NULL;

    GST_OBJECT_LOCK (adder);

again:

    for (;;) {
        if (adder->srcresult != GST_FLOW_OK)
            goto flushing;
        if (!g_queue_is_empty (adder->buffers))
            break;
        if (check_eos_locked (adder))
            goto eos;
        g_cond_wait (adder->not_empty_cond, GST_OBJECT_GET_LOCK (adder));
    }

    buffer_timestamp = GST_BUFFER_TIMESTAMP (g_queue_peek_head (adder->buffers));

    clock = GST_ELEMENT_CLOCK (adder);

    /* If we have no clock, then we can't do anything.. error */
    if (!clock) {
        if (adder->playing)
            goto no_clock;
        else
            goto push_buffer;
    }

    GST_DEBUG_OBJECT (adder, "sync to timestamp %" GST_TIME_FORMAT,
                      GST_TIME_ARGS (buffer_timestamp));

    sync_time = buffer_timestamp + GST_ELEMENT_CAST (adder)->base_time;
    /* add latency, this includes our own latency and the peer latency. */
    sync_time += adder->latency_ms * GST_MSECOND;
    sync_time += adder->peer_latency;

    /* create an entry for the clock */
    id = adder->clock_id = gst_clock_new_single_shot_id (clock, sync_time);
    GST_OBJECT_UNLOCK (adder);

    ret = gst_clock_id_wait (id, NULL);

    GST_OBJECT_LOCK (adder);

    /* and free the entry */
    gst_clock_id_unref (id);
    adder->clock_id = NULL;

    /* at this point, the clock could have been unlocked by a timeout, a new
     * head element was added to the queue or because we are shutting down. Check
     * for shutdown first. */

    if (adder->srcresult != GST_FLOW_OK)
        goto flushing;

    if (ret == GST_CLOCK_UNSCHEDULED) {
        GST_DEBUG_OBJECT (adder,
                          "Wait got unscheduled, will retry to push with new buffer");
        goto again;
    }

    if (ret != GST_CLOCK_OK && ret != GST_CLOCK_EARLY)
        goto clock_error;

push_buffer:

    buffer = g_queue_pop_head (adder->buffers);

    if (!buffer)
        goto again;

    /*
     * We make sure the timestamps are exactly contiguous
     * If its only small skew (due to rounding errors), we correct it
     * silently. Otherwise we put the discont flag
     */
    if (GST_CLOCK_TIME_IS_VALID (adder->next_timestamp) &&
            GST_BUFFER_TIMESTAMP (buffer) != adder->next_timestamp) {
        GstClockTimeDiff diff = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP (buffer),
                                                adder->next_timestamp);
        if (diff < 0)
            diff = -diff;

        if (diff < GST_SECOND / adder->rate) {
            GST_BUFFER_TIMESTAMP (buffer) = adder->next_timestamp;
            GST_DEBUG_OBJECT (adder, "Correcting slight skew");
            GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
        } else {
            GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
            GST_DEBUG_OBJECT (adder, "Expected buffer at %" GST_TIME_FORMAT
                              ", but is at %" GST_TIME_FORMAT ", setting discont",
                              GST_TIME_ARGS (adder->next_timestamp),
                              GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
        }
    } else {
        GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
    }

    GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
    GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;

    if (GST_BUFFER_DURATION_IS_VALID (buffer))
        adder->next_timestamp = GST_BUFFER_TIMESTAMP (buffer) +
                                GST_BUFFER_DURATION (buffer);
    else
        adder->next_timestamp = GST_CLOCK_TIME_NONE;

    if (adder->segment_pending) {
        /*
         * We set the start at 0, because we re-timestamps to the running time
         */
        newseg_event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0,
                       GST_FORMAT_TIME, 0, -1, 0);

        adder->segment_pending = FALSE;
    }

    GST_OBJECT_UNLOCK (adder);

    if (newseg_event)
        gst_pad_push_event (adder->srcpad, newseg_event);

    GST_LOG_OBJECT (adder, "About to push buffer time:%" GST_TIME_FORMAT
                    " duration:%" GST_TIME_FORMAT,
                    GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
                    GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));

    result = gst_pad_push (adder->srcpad, buffer);
    if (result != GST_FLOW_OK)
        goto pause;

    return;

flushing:
    {
        GST_DEBUG_OBJECT (adder, "we are flushing");
        gst_pad_pause_task (adder->srcpad);
        GST_OBJECT_UNLOCK (adder);
        return;
    }

clock_error:
    {
        gst_pad_pause_task (adder->srcpad);
        GST_OBJECT_UNLOCK (adder);
        GST_ELEMENT_ERROR (adder, STREAM, MUX, ("Error with the clock"),
                           ("Error with the clock: %d", ret));
        GST_ERROR_OBJECT (adder, "Error with the clock: %d", ret);
        return;
    }

no_clock:
    {
        gst_pad_pause_task (adder->srcpad);
        GST_OBJECT_UNLOCK (adder);
        GST_ELEMENT_ERROR (adder, STREAM, MUX, ("No available clock"),
                           ("No available clock"));
        GST_ERROR_OBJECT (adder, "No available clock");
        return;
    }

pause:
    {
        GST_DEBUG_OBJECT (adder, "pausing task, reason %s",
                          gst_flow_get_name (result));

        GST_OBJECT_LOCK (adder);

        /* store result */
        adder->srcresult = result;
        /* we don't post errors or anything because upstream will do that for us
         * when we pass the return value upstream. */
        gst_pad_pause_task (adder->srcpad);
        GST_OBJECT_UNLOCK (adder);
        return;
    }

eos:
    {
        /* store result, we are flushing now */
        GST_DEBUG_OBJECT (adder, "We are EOS, pushing EOS downstream");
        adder->srcresult = GST_FLOW_UNEXPECTED;
        gst_pad_pause_task (adder->srcpad);
        GST_OBJECT_UNLOCK (adder);
        gst_pad_push_event (adder->srcpad, gst_event_new_eos ());
        return;
    }
}
Exemplo n.º 9
0
static GstFlowReturn
gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstIdentity *identity = GST_IDENTITY (trans);
  GstClockTime runtimestamp = G_GINT64_CONSTANT (0);
  gsize size;

  size = gst_buffer_get_size (buf);

  if (identity->check_imperfect_timestamp)
    gst_identity_check_imperfect_timestamp (identity, buf);
  if (identity->check_imperfect_offset)
    gst_identity_check_imperfect_offset (identity, buf);

  /* update prev values */
  identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf);
  identity->prev_duration = GST_BUFFER_DURATION (buf);
  identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf);
  identity->prev_offset = GST_BUFFER_OFFSET (buf);

  if (identity->error_after >= 0) {
    identity->error_after--;
    if (identity->error_after == 0)
      goto error_after;
  }

  if (identity->drop_probability > 0.0) {
    if ((gfloat) (1.0 * rand () / (RAND_MAX)) < identity->drop_probability)
      goto dropped;
  }

  if (identity->dump) {
    GstMapInfo info;

    gst_buffer_map (buf, &info, GST_MAP_READ);
    gst_util_dump_mem (info.data, info.size);
    gst_buffer_unmap (buf, &info);
  }

  if (!identity->silent) {
    gst_identity_update_last_message_for_buffer (identity, "chain", buf, size);
  }

  if (identity->datarate > 0) {
    GstClockTime time = gst_util_uint64_scale_int (identity->offset,
        GST_SECOND, identity->datarate);

    GST_BUFFER_TIMESTAMP (buf) = time;
    GST_BUFFER_DURATION (buf) = size * GST_SECOND / identity->datarate;
  }

  if (identity->signal_handoffs)
    g_signal_emit (identity, gst_identity_signals[SIGNAL_HANDOFF], 0, buf);

  if (trans->segment.format == GST_FORMAT_TIME)
    runtimestamp = gst_segment_to_running_time (&trans->segment,
        GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));

  if ((identity->sync) && (trans->segment.format == GST_FORMAT_TIME)) {
    GstClock *clock;

    GST_OBJECT_LOCK (identity);
    if ((clock = GST_ELEMENT (identity)->clock)) {
      GstClockReturn cret;
      GstClockTime timestamp;

      timestamp = runtimestamp + GST_ELEMENT (identity)->base_time;

      /* save id if we need to unlock */
      identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp);
      GST_OBJECT_UNLOCK (identity);

      cret = gst_clock_id_wait (identity->clock_id, NULL);

      GST_OBJECT_LOCK (identity);
      if (identity->clock_id) {
        gst_clock_id_unref (identity->clock_id);
        identity->clock_id = NULL;
      }
      if (cret == GST_CLOCK_UNSCHEDULED)
        ret = GST_FLOW_EOS;
    }
    GST_OBJECT_UNLOCK (identity);
  }

  identity->offset += size;

  if (identity->sleep_time && ret == GST_FLOW_OK)
    g_usleep (identity->sleep_time);

  if (identity->single_segment && (trans->segment.format == GST_FORMAT_TIME)
      && (ret == GST_FLOW_OK)) {
    GST_BUFFER_TIMESTAMP (buf) = runtimestamp;
    GST_BUFFER_OFFSET (buf) = GST_CLOCK_TIME_NONE;
    GST_BUFFER_OFFSET_END (buf) = GST_CLOCK_TIME_NONE;
  }

  return ret;

  /* ERRORS */
error_after:
  {
    GST_ELEMENT_ERROR (identity, CORE, FAILED,
        (_("Failed after iterations as requested.")), (NULL));
    return GST_FLOW_ERROR;
  }
dropped:
  {
    if (!identity->silent) {
      gst_identity_update_last_message_for_buffer (identity, "dropping", buf,
          size);
    }
    /* return DROPPED to basetransform. */
    return GST_BASE_TRANSFORM_FLOW_DROPPED;
  }
}
Exemplo n.º 10
0
static GstFlowReturn
gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
    guint length, GstBuffer ** buffer)
{
  GstRTPDTMFSrcEvent *event;
  GstRTPDTMFSrc *dtmfsrc;
  GstClock *clock;
  GstClockID *clockid;
  GstClockReturn clockret;

  dtmfsrc = GST_RTP_DTMF_SRC (basesrc);

  do {

    if (dtmfsrc->payload == NULL) {
      GST_DEBUG_OBJECT (dtmfsrc, "popping");
      event = g_async_queue_pop (dtmfsrc->event_queue);

      GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);

      switch (event->event_type) {
        case RTP_DTMF_EVENT_TYPE_STOP:
          GST_WARNING_OBJECT (dtmfsrc,
              "Received a DTMF stop event when already stopped");
          break;

        case RTP_DTMF_EVENT_TYPE_START:
          dtmfsrc->first_packet = TRUE;
          dtmfsrc->last_packet = FALSE;
          /* Set the redundancy on the first packet */
          dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
          gst_rtp_dtmf_prepare_timestamps (dtmfsrc);

          /* Don't forget to get exclusive access to the stream */
          gst_rtp_dtmf_src_set_stream_lock (dtmfsrc, TRUE);

          dtmfsrc->payload = event->payload;
          event->payload = NULL;
          break;

        case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
          /*
           * We're pushing it back because it has to stay in there until
           * the task is really paused (and the queue will then be flushed
           */
          GST_OBJECT_LOCK (dtmfsrc);
          if (dtmfsrc->paused) {
            g_async_queue_push (dtmfsrc->event_queue, event);
            goto paused_locked;
          }
          GST_OBJECT_UNLOCK (dtmfsrc);
          break;
      }

      gst_rtp_dtmf_src_event_free (event);
    } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet &&
        (dtmfsrc->timestamp - dtmfsrc->start_timestamp) / GST_MSECOND >=
        MIN_PULSE_DURATION) {
      GST_DEBUG_OBJECT (dtmfsrc, "try popping");
      event = g_async_queue_try_pop (dtmfsrc->event_queue);


      if (event != NULL) {
        GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type);

        switch (event->event_type) {
          case RTP_DTMF_EVENT_TYPE_START:
            GST_WARNING_OBJECT (dtmfsrc,
                "Received two consecutive DTMF start events");
            break;

          case RTP_DTMF_EVENT_TYPE_STOP:
            dtmfsrc->first_packet = FALSE;
            dtmfsrc->last_packet = TRUE;
            /* Set the redundancy on the last packet */
            dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
            break;

          case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
            /*
             * We're pushing it back because it has to stay in there until
             * the task is really paused (and the queue will then be flushed)
             */
            GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
            GST_OBJECT_LOCK (dtmfsrc);
            if (dtmfsrc->paused) {
              g_async_queue_push (dtmfsrc->event_queue, event);
              goto paused_locked;
            }
            GST_OBJECT_UNLOCK (dtmfsrc);
            break;
        }
        gst_rtp_dtmf_src_event_free (event);
      }
    }
  } while (dtmfsrc->payload == NULL);


  GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");

  clock = gst_element_get_clock (GST_ELEMENT (basesrc));

#ifdef MAEMO_BROKEN
  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp);
#else
  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
      gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
#endif
  gst_object_unref (clock);

  GST_OBJECT_LOCK (dtmfsrc);
  if (!dtmfsrc->paused) {
    dtmfsrc->clockid = clockid;
    GST_OBJECT_UNLOCK (dtmfsrc);

    clockret = gst_clock_id_wait (clockid, NULL);

    GST_OBJECT_LOCK (dtmfsrc);
    if (dtmfsrc->paused)
      clockret = GST_CLOCK_UNSCHEDULED;
  } else {
    clockret = GST_CLOCK_UNSCHEDULED;
  }
  gst_clock_id_unref (clockid);
  dtmfsrc->clockid = NULL;
  GST_OBJECT_UNLOCK (dtmfsrc);

  if (clockret == GST_CLOCK_UNSCHEDULED) {
    goto paused;
  }

send_last:

  if (dtmfsrc->dirty)
    if (!gst_rtp_dtmf_src_negotiate (basesrc))
      return GST_FLOW_NOT_NEGOTIATED;

  /* create buffer to hold the payload */
  *buffer = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc);

  if (dtmfsrc->redundancy_count)
    dtmfsrc->redundancy_count--;

  /* Only the very first one has a marker */
  dtmfsrc->first_packet = FALSE;

  /* This is the end of the event */
  if (dtmfsrc->last_packet == TRUE && dtmfsrc->redundancy_count == 0) {

    /* Don't forget to release the stream lock */
    gst_rtp_dtmf_src_set_stream_lock (dtmfsrc, FALSE);

    g_slice_free (GstRTPDTMFPayload, dtmfsrc->payload);
    dtmfsrc->payload = NULL;

    dtmfsrc->last_packet = FALSE;
  }

  return GST_FLOW_OK;

paused_locked:

  GST_OBJECT_UNLOCK (dtmfsrc);

paused:

  if (dtmfsrc->payload) {
    dtmfsrc->first_packet = FALSE;
    dtmfsrc->last_packet = TRUE;
    /* Set the redundanc on the last packet */
    dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
    goto send_last;
  } else {
    return GST_FLOW_WRONG_STATE;
  }
}
Exemplo n.º 11
0
/**
 * This funcion will push out buffers on the source pad.
 *
 * For each pushed buffer, the seqnum is recorded, if the next buffer B has a
 * different seqnum (missing packets before B), this function will wait for the
 * missing packet to arrive up to the timestamp of buffer B.
 */
static void
gst_rtp_jitter_buffer_loop (GstRtpJitterBuffer * jitterbuffer)
{
  GstRtpJitterBufferPrivate *priv;
  GstBuffer *outbuf;
  GstFlowReturn result;
  guint16 seqnum;
  guint32 next_seqnum;
  GstClockTime timestamp, out_time;
  gboolean discont = FALSE;
  gint gap;

  priv = jitterbuffer->priv;

  JBUF_LOCK_CHECK (priv, flushing);
again:
  GST_DEBUG_OBJECT (jitterbuffer, "Peeking item");
  while (TRUE) {
    /* always wait if we are blocked */
    if (!priv->blocked) {
      /* if we have a packet, we can exit the loop and grab it */
      if (rtp_jitter_buffer_num_packets (priv->jbuf) > 0)
        break;
      /* no packets but we are EOS, do eos logic */
      if (priv->eos)
        goto do_eos;
    }
    /* underrun, wait for packets or flushing now */
    priv->waiting = TRUE;
    JBUF_WAIT_CHECK (priv, flushing);
    priv->waiting = FALSE;
  }

  /* peek a buffer, we're just looking at the timestamp and the sequence number.
   * If all is fine, we'll pop and push it. If the sequence number is wrong we
   * wait on the timestamp. In the chain function we will unlock the wait when a
   * new buffer is available. The peeked buffer is valid for as long as we hold
   * the jitterbuffer lock. */
  outbuf = rtp_jitter_buffer_peek (priv->jbuf);

  /* get the seqnum and the next expected seqnum */
  seqnum = gst_rtp_buffer_get_seq (outbuf);
  next_seqnum = priv->next_seqnum;

  /* get the timestamp, this is already corrected for clock skew by the
   * jitterbuffer */
  timestamp = GST_BUFFER_TIMESTAMP (outbuf);

  GST_DEBUG_OBJECT (jitterbuffer,
      "Peeked buffer #%d, expect #%d, timestamp %" GST_TIME_FORMAT
      ", now %d left", seqnum, next_seqnum, GST_TIME_ARGS (timestamp),
      rtp_jitter_buffer_num_packets (priv->jbuf));

  /* apply our timestamp offset to the incomming buffer, this will be our output
   * timestamp. */
  out_time = apply_offset (jitterbuffer, timestamp);

  /* get the gap between this and the previous packet. If we don't know the
   * previous packet seqnum assume no gap. */
  if (next_seqnum != -1) {
    gap = gst_rtp_buffer_compare_seqnum (next_seqnum, seqnum);

    /* if we have a packet that we already pushed or considered dropped, pop it
     * off and get the next packet */
    if (gap < 0) {
      GST_DEBUG_OBJECT (jitterbuffer, "Old packet #%d, next #%d dropping",
          seqnum, next_seqnum);
      outbuf = rtp_jitter_buffer_pop (priv->jbuf);
      gst_buffer_unref (outbuf);
      goto again;
    }
  } else {
    GST_DEBUG_OBJECT (jitterbuffer, "no next seqnum known, first packet");
    gap = -1;
  }

  /* If we don't know what the next seqnum should be (== -1) we have to wait
   * because it might be possible that we are not receiving this buffer in-order,
   * a buffer with a lower seqnum could arrive later and we want to push that
   * earlier buffer before this buffer then.
   * If we know the expected seqnum, we can compare it to the current seqnum to
   * determine if we have missing a packet. If we have a missing packet (which
   * must be before this packet) we can wait for it until the deadline for this
   * packet expires. */
  if (gap != 0 && out_time != -1) {
    GstClockID id;
    GstClockTime sync_time;
    GstClockReturn ret;
    GstClock *clock;
    GstClockTime duration = GST_CLOCK_TIME_NONE;

    if (gap > 0) {
      /* we have a gap */
      GST_WARNING_OBJECT (jitterbuffer,
          "Sequence number GAP detected: expected %d instead of %d (%d missing)",
          next_seqnum, seqnum, gap);

      if (priv->last_out_time != -1) {
        GST_DEBUG_OBJECT (jitterbuffer,
            "out_time %" GST_TIME_FORMAT ", last %" GST_TIME_FORMAT,
            GST_TIME_ARGS (out_time), GST_TIME_ARGS (priv->last_out_time));
        /* interpolate between the current time and the last time based on
         * number of packets we are missing, this is the estimated duration
         * for the missing packet based on equidistant packet spacing. Also make
         * sure we never go negative. */
        if (out_time > priv->last_out_time)
          duration = (out_time - priv->last_out_time) / (gap + 1);
        else
          goto lost;

        GST_DEBUG_OBJECT (jitterbuffer, "duration %" GST_TIME_FORMAT,
            GST_TIME_ARGS (duration));
        /* add this duration to the timestamp of the last packet we pushed */
        out_time = (priv->last_out_time + duration);
      }
    } else {
      /* we don't know what the next_seqnum should be, wait for the last
       * possible moment to push this buffer, maybe we get an earlier seqnum
       * while we wait */
      GST_DEBUG_OBJECT (jitterbuffer, "First buffer %d, do sync", seqnum);
    }

    GST_OBJECT_LOCK (jitterbuffer);
    clock = GST_ELEMENT_CLOCK (jitterbuffer);
    if (!clock) {
      GST_OBJECT_UNLOCK (jitterbuffer);
      /* let's just push if there is no clock */
      goto push_buffer;
    }

    GST_DEBUG_OBJECT (jitterbuffer, "sync to timestamp %" GST_TIME_FORMAT,
        GST_TIME_ARGS (out_time));

    /* prepare for sync against clock */
    sync_time = out_time + GST_ELEMENT_CAST (jitterbuffer)->base_time;
    /* add latency, this includes our own latency and the peer latency. */
    sync_time += (priv->latency_ms * GST_MSECOND);
    sync_time += priv->peer_latency;

    /* create an entry for the clock */
    id = priv->clock_id = gst_clock_new_single_shot_id (clock, sync_time);
    GST_OBJECT_UNLOCK (jitterbuffer);

    /* release the lock so that the other end can push stuff or unlock */
    JBUF_UNLOCK (priv);

    ret = gst_clock_id_wait (id, NULL);

    JBUF_LOCK (priv);
    /* and free the entry */
    gst_clock_id_unref (id);
    priv->clock_id = NULL;

    /* at this point, the clock could have been unlocked by a timeout, a new
     * tail element was added to the queue or because we are shutting down. Check
     * for shutdown first. */
    if (priv->srcresult != GST_FLOW_OK)
      goto flushing;

    /* if we got unscheduled and we are not flushing, it's because a new tail
     * element became available in the queue. Grab it and try to push or sync. */
    if (ret == GST_CLOCK_UNSCHEDULED) {
      GST_DEBUG_OBJECT (jitterbuffer,
          "Wait got unscheduled, will retry to push with new buffer");
      goto again;
    }

  lost:
    /* we now timed out, this means we lost a packet or finished synchronizing
     * on the first buffer. */
    if (gap > 0) {
      GstEvent *event;

      /* we had a gap and thus we lost a packet. Create an event for this.  */
      GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d lost", next_seqnum);
      priv->num_late++;
      discont = TRUE;

      if (priv->do_lost) {
        /* create paket lost event */
        event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
            gst_structure_new ("GstRTPPacketLost",
                "seqnum", G_TYPE_UINT, (guint) next_seqnum,
                "timestamp", G_TYPE_UINT64, out_time,
                "duration", G_TYPE_UINT64, duration, NULL));
        gst_pad_push_event (priv->srcpad, event);
      }

      /* update our expected next packet */
      priv->last_popped_seqnum = next_seqnum;
      priv->last_out_time = out_time;
      priv->next_seqnum = (next_seqnum + 1) & 0xffff;
      /* look for next packet */
      goto again;
    }

    /* there was no known gap,just the first packet, exit the loop and push */
    GST_DEBUG_OBJECT (jitterbuffer, "First packet #%d synced", seqnum);

    /* get new timestamp, latency might have changed */
    out_time = apply_offset (jitterbuffer, timestamp);
  }
push_buffer:

  /* when we get here we are ready to pop and push the buffer */
  outbuf = rtp_jitter_buffer_pop (priv->jbuf);

  if (discont || priv->discont) {
    /* set DISCONT flag when we missed a packet. */
    outbuf = gst_buffer_make_metadata_writable (outbuf);
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
    priv->discont = FALSE;
  }

  /* apply timestamp with offset to buffer now */
  GST_BUFFER_TIMESTAMP (outbuf) = out_time;

  /* now we are ready to push the buffer. Save the seqnum and release the lock
   * so the other end can push stuff in the queue again. */
  priv->last_popped_seqnum = seqnum;
  priv->last_out_time = out_time;
  priv->next_seqnum = (seqnum + 1) & 0xffff;
  JBUF_UNLOCK (priv);

  /* push buffer */
  GST_DEBUG_OBJECT (jitterbuffer,
      "Pushing buffer %d, timestamp %" GST_TIME_FORMAT, seqnum,
      GST_TIME_ARGS (out_time));
  result = gst_pad_push (priv->srcpad, outbuf);
  if (result != GST_FLOW_OK)
    goto pause;

  return;

  /* ERRORS */
do_eos:
  {
    /* store result, we are flushing now */
    GST_DEBUG_OBJECT (jitterbuffer, "We are EOS, pushing EOS downstream");
    priv->srcresult = GST_FLOW_UNEXPECTED;
    gst_pad_pause_task (priv->srcpad);
    gst_pad_push_event (priv->srcpad, gst_event_new_eos ());
    JBUF_UNLOCK (priv);
    return;
  }
flushing:
  {
    GST_DEBUG_OBJECT (jitterbuffer, "we are flushing");
    gst_pad_pause_task (priv->srcpad);
    JBUF_UNLOCK (priv);
    return;
  }
pause:
  {
    const gchar *reason = gst_flow_get_name (result);

    GST_DEBUG_OBJECT (jitterbuffer, "pausing task, reason %s", reason);

    JBUF_LOCK (priv);
    /* store result */
    priv->srcresult = result;
    /* we don't post errors or anything because upstream will do that for us
     * when we pass the return value upstream. */
    gst_pad_pause_task (priv->srcpad);
    JBUF_UNLOCK (priv);
    return;
  }
}
Exemplo n.º 12
0
gint
main (gint argc, gchar ** argv)
{
    gint res = 1;
    GstElement *src, *sink;
    GstElement *bin;
    GstController *ctrl;
    GstInterpolationControlSource *csource1, *csource2;
    GstClock *clock;
    GstClockID clock_id;
    GstClockReturn wait_ret;
    GValue vol = { 0, };

    gst_init (&argc, &argv);
    gst_controller_init (&argc, &argv);

    /* build pipeline */
    bin = gst_pipeline_new ("pipeline");
    clock = gst_pipeline_get_clock (GST_PIPELINE (bin));
    src = gst_element_factory_make ("audiotestsrc", "gen_audio");
    if (!src) {
        GST_WARNING ("need audiotestsrc from gst-plugins-base");
        goto Error;
    }
    sink = gst_element_factory_make ("autoaudiosink", "play_audio");
    if (!sink) {
        GST_WARNING ("need autoaudiosink from gst-plugins-base");
        goto Error;
    }

    gst_bin_add_many (GST_BIN (bin), src, sink, NULL);
    if (!gst_element_link (src, sink)) {
        GST_WARNING ("can't link elements");
        goto Error;
    }

    /* square wave
       g_object_set (G_OBJECT(src), "wave", 1, NULL);
     */

    /* add a controller to the source */
    if (!(ctrl = gst_controller_new (G_OBJECT (src), "freq", "volume", NULL))) {
        GST_WARNING ("can't control source element");
        goto Error;
    }

    csource1 = gst_interpolation_control_source_new ();
    csource2 = gst_interpolation_control_source_new ();

    gst_controller_set_control_source (ctrl, "volume",
                                       GST_CONTROL_SOURCE (csource1));
    gst_controller_set_control_source (ctrl, "freq",
                                       GST_CONTROL_SOURCE (csource2));

    /* Set interpolation mode */

    gst_interpolation_control_source_set_interpolation_mode (csource1,
            GST_INTERPOLATE_LINEAR);
    gst_interpolation_control_source_set_interpolation_mode (csource2,
            GST_INTERPOLATE_LINEAR);

    /* set control values */
    g_value_init (&vol, G_TYPE_DOUBLE);
    g_value_set_double (&vol, 0.0);
    gst_interpolation_control_source_set (csource1, 0 * GST_SECOND, &vol);
    g_value_set_double (&vol, 1.0);
    gst_interpolation_control_source_set (csource1, 5 * GST_SECOND, &vol);

    g_object_unref (csource1);

    g_value_set_double (&vol, 220.0);
    gst_interpolation_control_source_set (csource2, 0 * GST_SECOND, &vol);
    g_value_set_double (&vol, 3520.0);
    gst_interpolation_control_source_set (csource2, 3 * GST_SECOND, &vol);
    g_value_set_double (&vol, 440.0);
    gst_interpolation_control_source_set (csource2, 6 * GST_SECOND, &vol);

    g_object_unref (csource2);

    clock_id =
        gst_clock_new_single_shot_id (clock,
                                      gst_clock_get_time (clock) + (7 * GST_SECOND));

    /* run for 7 seconds */
    if (gst_element_set_state (bin, GST_STATE_PLAYING)) {
        if ((wait_ret = gst_clock_id_wait (clock_id, NULL)) != GST_CLOCK_OK) {
            GST_WARNING ("clock_id_wait returned: %d", wait_ret);
        }
        gst_element_set_state (bin, GST_STATE_NULL);
    }

    /* cleanup */
    g_object_unref (G_OBJECT (ctrl));
    gst_clock_id_unref (clock_id);
    gst_object_unref (G_OBJECT (clock));
    gst_object_unref (G_OBJECT (bin));
    res = 0;
Error:
    return (res);
}
static gpointer
mixed_thread (MixedInfo * info)
{
  info->ret = gst_clock_id_wait (info->id, &info->jitter);
  return NULL;
}
Exemplo n.º 14
0
/* 
return number of readed bytes */
static guint
gst_directsound_src_read (GstAudioSrc * asrc, gpointer data, guint length,
    GstClockTime * timestamp)
{
  GstDirectSoundSrc *dsoundsrc;
  guint64 sleep_time_ms, sleep_until;
  GstClockID clock_id;

  HRESULT hRes;                 /* Result for windows functions */
  DWORD dwCurrentCaptureCursor = 0;
  DWORD dwBufferSize = 0;

  LPVOID pLockedBuffer1 = NULL;
  LPVOID pLockedBuffer2 = NULL;
  DWORD dwSizeBuffer1 = 0;
  DWORD dwSizeBuffer2 = 0;

  DWORD dwStatus = 0;

  GST_DEBUG_OBJECT (asrc, "reading directsoundsrc");

  dsoundsrc = GST_DIRECTSOUND_SRC (asrc);

  GST_DSOUND_LOCK (dsoundsrc);

  /* Get current buffer status */
  hRes = IDirectSoundCaptureBuffer_GetStatus (dsoundsrc->pDSBSecondary,
      &dwStatus);

  if (FAILED (hRes)) {
    GST_DSOUND_UNLOCK (dsoundsrc);
    return -1;
  }

  /* Starting capturing if not already */
  if (!(dwStatus & DSCBSTATUS_CAPTURING)) {
    hRes = IDirectSoundCaptureBuffer_Start (dsoundsrc->pDSBSecondary,
        DSCBSTART_LOOPING);
    GST_INFO_OBJECT (asrc, "capture started");
  }

  /* Loop till the source has produced bytes equal to or greater than @length.
   *
   * DirectSound has a notification-based API that uses Windows CreateEvent()
   * + WaitForSingleObject(), but it is completely useless for live streams.
   *
   *  1. You must schedule all events before starting capture
   *  2. The events are all fired exactly once
   *  3. You cannot schedule new events while a capture is running
   *  4. You cannot stop/schedule/start either
   *
   * This means you cannot use the API while doing live looped capture and we
   * must resort to this.
   *
   * However, this is almost as efficient as event-based capture since it's ok
   * to consistently overwait by a fixed amount; the extra bytes will just end
   * up being used in the next call, and the extra latency will be constant. */
  while (TRUE) {
    hRes =
        IDirectSoundCaptureBuffer_GetCurrentPosition (dsoundsrc->pDSBSecondary,
        &dwCurrentCaptureCursor, NULL);

    if (FAILED (hRes)) {
      GST_DSOUND_UNLOCK (dsoundsrc);
      return -1;
    }

    /* calculate the size of the buffer that's been captured while accounting
     * for wrap-arounds */
    if (dwCurrentCaptureCursor < dsoundsrc->current_circular_offset) {
      dwBufferSize = dsoundsrc->buffer_size -
          (dsoundsrc->current_circular_offset - dwCurrentCaptureCursor);
    } else {
      dwBufferSize =
          dwCurrentCaptureCursor - dsoundsrc->current_circular_offset;
    }

    if (dwBufferSize >= length) {
      /* Yay, we got all the data we need */
      break;
    } else {
      GST_DEBUG_OBJECT (asrc, "not enough data, got %lu (want at least %u)",
          dwBufferSize, length);
      /* If we didn't get enough data, sleep for a proportionate time */
      sleep_time_ms = gst_util_uint64_scale (dsoundsrc->latency_time,
          length - dwBufferSize, length * 1000);
      /* Make sure we don't run in a tight loop unnecessarily */
      sleep_time_ms = MAX (sleep_time_ms, 10);
      /* Sleep using gst_clock_id_wait() so that we can be interrupted */
      sleep_until = gst_clock_get_time (dsoundsrc->system_clock) +
          sleep_time_ms * GST_MSECOND;
      /* Setup the clock id wait */
      if (G_UNLIKELY (dsoundsrc->read_wait_clock_id == NULL ||
              gst_clock_single_shot_id_reinit (dsoundsrc->system_clock,
                  dsoundsrc->read_wait_clock_id, sleep_until) == FALSE)) {
        if (dsoundsrc->read_wait_clock_id != NULL)
          gst_clock_id_unref (dsoundsrc->read_wait_clock_id);
        dsoundsrc->read_wait_clock_id =
            gst_clock_new_single_shot_id (dsoundsrc->system_clock, sleep_until);
      }

      clock_id = dsoundsrc->read_wait_clock_id;
      dsoundsrc->reset_while_sleeping = FALSE;

      GST_DEBUG_OBJECT (asrc, "waiting %" G_GUINT64_FORMAT "ms for more data",
          sleep_time_ms);
      GST_DSOUND_UNLOCK (dsoundsrc);

      gst_clock_id_wait (clock_id, NULL);

      GST_DSOUND_LOCK (dsoundsrc);

      if (dsoundsrc->reset_while_sleeping == TRUE) {
        GST_DEBUG_OBJECT (asrc, "reset while sleeping, cancelled read");
        GST_DSOUND_UNLOCK (dsoundsrc);
        return -1;
      }
    }
  }

  GST_DEBUG_OBJECT (asrc, "Got enough data: %lu bytes (wanted at least %u)",
      dwBufferSize, length);

  /* Lock the buffer and read only the first @length bytes. Keep the rest in
   * the capture buffer for the next read. */
  hRes = IDirectSoundCaptureBuffer_Lock (dsoundsrc->pDSBSecondary,
      dsoundsrc->current_circular_offset,
      length,
      &pLockedBuffer1, &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L);

  /* NOTE: We now assume that dwSizeBuffer1 + dwSizeBuffer2 == length since the
   * API is supposed to guarantee that */

  /* Copy buffer data to another buffer */
  if (hRes == DS_OK) {
    memcpy (data, pLockedBuffer1, dwSizeBuffer1);
  }

  /* ...and if something is in another buffer */
  if (pLockedBuffer2 != NULL) {
    memcpy (((guchar *) data + dwSizeBuffer1), pLockedBuffer2, dwSizeBuffer2);
  }

  dsoundsrc->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2;
  dsoundsrc->current_circular_offset %= dsoundsrc->buffer_size;

  IDirectSoundCaptureBuffer_Unlock (dsoundsrc->pDSBSecondary,
      pLockedBuffer1, dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2);

  GST_DSOUND_UNLOCK (dsoundsrc);

  /* We always read exactly @length data */
  return length;
}
Exemplo n.º 15
0
static void
paused_mode_task (gpointer data)
{
  GstMimEnc *mimenc = GST_MIM_ENC (data);
  GstClockTime now;
  GstClockTimeDiff diff;
  GstFlowReturn ret;

  GST_OBJECT_LOCK (mimenc);

  if (!GST_ELEMENT_CLOCK (mimenc)) {
    GST_OBJECT_UNLOCK (mimenc);
    GST_ERROR_OBJECT (mimenc, "Element has no clock");
    gst_pad_pause_task (mimenc->srcpad);
    return;
  }

  if (mimenc->stop_paused_mode) {
    GST_OBJECT_UNLOCK (mimenc);
    goto stop_task;
  }

  now = gst_clock_get_time (GST_ELEMENT_CLOCK (mimenc));

  diff = now - GST_ELEMENT_CAST (mimenc)->base_time - mimenc->last_buffer;
  if (diff < 0)
    diff = 0;

  if (diff > 3.95 * GST_SECOND) {
    GstBuffer *buffer;
    GstMapInfo out_map;

    buffer = gst_buffer_new_and_alloc (TCP_HEADER_SIZE);
    gst_buffer_map (buffer, &out_map, GST_MAP_WRITE);
    GST_BUFFER_TIMESTAMP (buffer) = mimenc->last_buffer + PAUSED_MODE_INTERVAL;
    gst_mim_enc_create_tcp_header (mimenc, out_map.data, 0,
        GST_BUFFER_TIMESTAMP (buffer), FALSE, TRUE);
    gst_buffer_unmap (buffer, &out_map);

    mimenc->last_buffer += PAUSED_MODE_INTERVAL;

    GST_OBJECT_UNLOCK (mimenc);
    GST_LOG_OBJECT (mimenc, "Haven't had an incoming buffer in 4 seconds,"
        " sending out a pause frame");

    ret = gst_pad_push (mimenc->srcpad, buffer);
    if (ret < 0) {
      GST_WARNING_OBJECT (mimenc, "Error pushing paused header: %s",
          gst_flow_get_name (ret));
      goto stop_task;
    }
  } else {
    GstClockTime next_stop;
    GstClockID id;

    next_stop = now + (PAUSED_MODE_INTERVAL - MIN (diff, PAUSED_MODE_INTERVAL));

    id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (mimenc), next_stop);

    if (mimenc->stop_paused_mode) {
      GST_OBJECT_UNLOCK (mimenc);
      goto stop_task;
    }

    mimenc->clock_id = id;
    GST_OBJECT_UNLOCK (mimenc);

    gst_clock_id_wait (id, NULL);

    GST_OBJECT_LOCK (mimenc);
    mimenc->clock_id = NULL;
    GST_OBJECT_UNLOCK (mimenc);

    gst_clock_id_unref (id);
  }
  return;

stop_task:

  gst_pad_pause_task (mimenc->srcpad);
}
Exemplo n.º 16
0
/*
 * Method: wait
 *
 * Performs a blocking wait on the entry.
 *
 * Returns: a return code (see Gst::Clock::Return).
 */
static VALUE
rg_wait (VALUE self)
{
    return GENUM2RVAL (gst_clock_id_wait (RGST_CLOCK_ENTRY (self), NULL),
                       GST_TYPE_CLOCK_RETURN);
}
Exemplo n.º 17
0
static GstFlowReturn
gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
    guint length, GstBuffer ** buffer)
{
  GstRTPDTMFSrcEvent *event;
  GstRTPDTMFSrc *dtmfsrc;
  GstClock *clock;
  GstClockID *clockid;
  GstClockReturn clockret;
  GstMessage *message;
  GQueue messages = G_QUEUE_INIT;

  dtmfsrc = GST_RTP_DTMF_SRC (basesrc);

  do {

    if (dtmfsrc->payload == NULL) {
      GST_DEBUG_OBJECT (dtmfsrc, "popping");
      event = g_async_queue_pop (dtmfsrc->event_queue);

      GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);

      switch (event->event_type) {
        case RTP_DTMF_EVENT_TYPE_STOP:
          GST_WARNING_OBJECT (dtmfsrc,
              "Received a DTMF stop event when already stopped");
          gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
          break;

        case RTP_DTMF_EVENT_TYPE_START:
          dtmfsrc->first_packet = TRUE;
          dtmfsrc->last_packet = FALSE;
          /* Set the redundancy on the first packet */
          dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
          if (!gst_rtp_dtmf_prepare_timestamps (dtmfsrc))
            goto no_clock;

          g_queue_push_tail (&messages,
              gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
                  event));
          dtmfsrc->payload = event->payload;
          dtmfsrc->payload->duration =
              dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
          event->payload = NULL;
          break;

        case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
          /*
           * We're pushing it back because it has to stay in there until
           * the task is really paused (and the queue will then be flushed
           */
          GST_OBJECT_LOCK (dtmfsrc);
          if (dtmfsrc->paused) {
            g_async_queue_push (dtmfsrc->event_queue, event);
            goto paused_locked;
          }
          GST_OBJECT_UNLOCK (dtmfsrc);
          break;
      }

      gst_rtp_dtmf_src_event_free (event);
    } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet &&
        (dtmfsrc->timestamp - dtmfsrc->start_timestamp) / GST_MSECOND >=
        MIN_PULSE_DURATION) {
      GST_DEBUG_OBJECT (dtmfsrc, "try popping");
      event = g_async_queue_try_pop (dtmfsrc->event_queue);


      if (event != NULL) {
        GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type);

        switch (event->event_type) {
          case RTP_DTMF_EVENT_TYPE_START:
            GST_WARNING_OBJECT (dtmfsrc,
                "Received two consecutive DTMF start events");
            gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
            break;

          case RTP_DTMF_EVENT_TYPE_STOP:
            dtmfsrc->first_packet = FALSE;
            dtmfsrc->last_packet = TRUE;
            /* Set the redundancy on the last packet */
            dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
            g_queue_push_tail (&messages,
                gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
                    event));
            break;

          case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
            /*
             * We're pushing it back because it has to stay in there until
             * the task is really paused (and the queue will then be flushed)
             */
            GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
            GST_OBJECT_LOCK (dtmfsrc);
            if (dtmfsrc->paused) {
              g_async_queue_push (dtmfsrc->event_queue, event);
              goto paused_locked;
            }
            GST_OBJECT_UNLOCK (dtmfsrc);
            break;
        }
        gst_rtp_dtmf_src_event_free (event);
      }
    }
  } while (dtmfsrc->payload == NULL);


  GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");

  clock = gst_element_get_clock (GST_ELEMENT (basesrc));
  if (!clock)
    goto no_clock;
  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
      gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
  gst_object_unref (clock);

  GST_OBJECT_LOCK (dtmfsrc);
  if (!dtmfsrc->paused) {
    dtmfsrc->clockid = clockid;
    GST_OBJECT_UNLOCK (dtmfsrc);

    clockret = gst_clock_id_wait (clockid, NULL);

    GST_OBJECT_LOCK (dtmfsrc);
    if (dtmfsrc->paused)
      clockret = GST_CLOCK_UNSCHEDULED;
  } else {
    clockret = GST_CLOCK_UNSCHEDULED;
  }
  gst_clock_id_unref (clockid);
  dtmfsrc->clockid = NULL;
  GST_OBJECT_UNLOCK (dtmfsrc);

  while ((message = g_queue_pop_head (&messages)) != NULL)
    gst_element_post_message (GST_ELEMENT (dtmfsrc), message);

  if (clockret == GST_CLOCK_UNSCHEDULED) {
    goto paused;
  }

send_last:

  if (dtmfsrc->dirty)
    if (!gst_rtp_dtmf_src_negotiate (basesrc))
      return GST_FLOW_NOT_NEGOTIATED;

  /* create buffer to hold the payload */
  *buffer = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc);

  if (dtmfsrc->redundancy_count)
    dtmfsrc->redundancy_count--;

  /* Only the very first one has a marker */
  dtmfsrc->first_packet = FALSE;

  /* This is the end of the event */
  if (dtmfsrc->last_packet == TRUE && dtmfsrc->redundancy_count == 0) {

    g_slice_free (GstRTPDTMFPayload, dtmfsrc->payload);
    dtmfsrc->payload = NULL;

    dtmfsrc->last_packet = FALSE;
  }

  return GST_FLOW_OK;

paused_locked:

  GST_OBJECT_UNLOCK (dtmfsrc);

paused:

  if (dtmfsrc->payload) {
    dtmfsrc->first_packet = FALSE;
    dtmfsrc->last_packet = TRUE;
    /* Set the redundanc on the last packet */
    dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
    goto send_last;
  } else {
    return GST_FLOW_FLUSHING;
  }

no_clock:
  GST_ELEMENT_ERROR (dtmfsrc, STREAM, MUX, ("No available clock"),
      ("No available clock"));
  gst_pad_pause_task (GST_BASE_SRC_PAD (dtmfsrc));
  return GST_FLOW_ERROR;
}
Exemplo n.º 18
0
static GstFlowReturn
gst_dx9screencapsrc_create (GstPushSrc * push_src, GstBuffer ** buf)
{
  GstDX9ScreenCapSrc *src = GST_DX9SCREENCAPSRC (push_src);
  GstBuffer *new_buf;
  gint new_buf_size, i;
  gint width, height, stride;
  GstClock *clock;
  GstClockTime buf_time, buf_dur;
  D3DLOCKED_RECT locked_rect;
  LPBYTE p_dst, p_src;
  HRESULT hres;
  GstMapInfo map;
  guint64 frame_number;

  if (G_UNLIKELY (!src->d3d9_device)) {
    GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
        ("format wasn't negotiated before create function"));
    return GST_FLOW_NOT_NEGOTIATED;
  }

  clock = gst_element_get_clock (GST_ELEMENT (src));
  if (clock != NULL) {
    GstClockTime time, base_time;

    /* Calculate sync time. */

    time = gst_clock_get_time (clock);
    base_time = gst_element_get_base_time (GST_ELEMENT (src));
    buf_time = time - base_time;

    if (src->rate_numerator) {
      frame_number = gst_util_uint64_scale (buf_time,
          src->rate_numerator, GST_SECOND * src->rate_denominator);
    } else {
      frame_number = -1;
    }
  } else {
    buf_time = GST_CLOCK_TIME_NONE;
    frame_number = -1;
  }

  if (frame_number != -1 && frame_number == src->frame_number) {
    GstClockID id;
    GstClockReturn ret;

    /* Need to wait for the next frame */
    frame_number += 1;

    /* Figure out what the next frame time is */
    buf_time = gst_util_uint64_scale (frame_number,
        src->rate_denominator * GST_SECOND, src->rate_numerator);

    id = gst_clock_new_single_shot_id (clock,
        buf_time + gst_element_get_base_time (GST_ELEMENT (src)));
    GST_OBJECT_LOCK (src);
    src->clock_id = id;
    GST_OBJECT_UNLOCK (src);

    GST_DEBUG_OBJECT (src, "Waiting for next frame time %" G_GUINT64_FORMAT,
        buf_time);
    ret = gst_clock_id_wait (id, NULL);
    GST_OBJECT_LOCK (src);

    gst_clock_id_unref (id);
    src->clock_id = NULL;
    if (ret == GST_CLOCK_UNSCHEDULED) {
      /* Got woken up by the unlock function */
      GST_OBJECT_UNLOCK (src);
      return GST_FLOW_FLUSHING;
    }
    GST_OBJECT_UNLOCK (src);

    /* Duration is a complete 1/fps frame duration */
    buf_dur =
        gst_util_uint64_scale_int (GST_SECOND, src->rate_denominator,
        src->rate_numerator);
  } else if (frame_number != -1) {
    GstClockTime next_buf_time;

    GST_DEBUG_OBJECT (src, "No need to wait for next frame time %"
        G_GUINT64_FORMAT " next frame = %" G_GINT64_FORMAT " prev = %"
        G_GINT64_FORMAT, buf_time, frame_number, src->frame_number);
    next_buf_time = gst_util_uint64_scale (frame_number + 1,
        src->rate_denominator * GST_SECOND, src->rate_numerator);
    /* Frame duration is from now until the next expected capture time */
    buf_dur = next_buf_time - buf_time;
  } else {
    buf_dur = GST_CLOCK_TIME_NONE;
  }
  src->frame_number = frame_number;

  height = (src->src_rect.bottom - src->src_rect.top);
  width = (src->src_rect.right - src->src_rect.left);
  new_buf_size = width * 4 * height;

  GST_LOG_OBJECT (src,
      "creating buffer of %d bytes with %dx%d image",
      new_buf_size, width, height);

  /* Do screen capture and put it into buffer...
   * Aquire front buffer, and lock it
   */
  hres =
      IDirect3DDevice9_GetFrontBufferData (src->d3d9_device, 0, src->surface);
  if (FAILED (hres)) {
    GST_DEBUG_OBJECT (src, "DirectX::GetBackBuffer failed.");
    return GST_FLOW_ERROR;
  }

  if (src->show_cursor) {
    CURSORINFO ci;

    ci.cbSize = sizeof (CURSORINFO);
    GetCursorInfo (&ci);
    if (ci.flags & CURSOR_SHOWING) {
      ICONINFO ii;
      HDC memDC;

      GetIconInfo (ci.hCursor, &ii);

      if (SUCCEEDED (IDirect3DSurface9_GetDC (src->surface, &memDC))) {
        HCURSOR cursor = CopyImage (ci.hCursor, IMAGE_CURSOR, 0, 0,
            LR_MONOCHROME | LR_DEFAULTSIZE);

        DrawIcon (memDC,
            ci.ptScreenPos.x - ii.xHotspot - src->monitor_info.rcMonitor.left,
            ci.ptScreenPos.y - ii.yHotspot - src->monitor_info.rcMonitor.top,
            cursor);

        DestroyCursor (cursor);
        IDirect3DSurface9_ReleaseDC (src->surface, memDC);
      }

      DeleteObject (ii.hbmColor);
      DeleteObject (ii.hbmMask);
    }
  }

  hres =
      IDirect3DSurface9_LockRect (src->surface, &locked_rect, &(src->src_rect),
      D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY);
  if (FAILED (hres)) {
    GST_DEBUG_OBJECT (src, "DirectX::LockRect failed.");
    return GST_FLOW_ERROR;
  }

  new_buf = gst_buffer_new_and_alloc (new_buf_size);
  gst_buffer_map (new_buf, &map, GST_MAP_WRITE);
  p_dst = (LPBYTE) map.data;
  p_src = (LPBYTE) locked_rect.pBits;
  stride = width * 4;
  for (i = 0; i < height; ++i) {
    memcpy (p_dst, p_src, stride);
    p_dst += stride;
    p_src += locked_rect.Pitch;
  }
  gst_buffer_unmap (new_buf, &map);

  /* Unlock copy of front buffer */
  IDirect3DSurface9_UnlockRect (src->surface);

  GST_BUFFER_TIMESTAMP (new_buf) = buf_time;
  GST_BUFFER_DURATION (new_buf) = buf_dur;

  if (clock != NULL)
    gst_object_unref (clock);

  *buf = new_buf;
  return GST_FLOW_OK;
}
Exemplo n.º 19
0
static GstFlowReturn
gst_gdiscreencapsrc_create (GstPushSrc * push_src, GstBuffer ** buf)
{
  GstGDIScreenCapSrc *src = GST_GDISCREENCAPSRC (push_src);
  GstBuffer *new_buf;
  gint new_buf_size;
  GstClock *clock;
  GstClockTime buf_time, buf_dur;
  guint64 frame_number;

  if (G_UNLIKELY (!src->info.bmiHeader.biWidth ||
          !src->info.bmiHeader.biHeight)) {
    GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
        ("format wasn't negotiated before create function"));
    return GST_FLOW_NOT_NEGOTIATED;
  }

  new_buf_size = GST_ROUND_UP_4 (src->info.bmiHeader.biWidth * 3) *
      (-src->info.bmiHeader.biHeight);

  GST_LOG_OBJECT (src,
      "creating buffer of %d bytes with %dx%d image",
      new_buf_size, (gint) src->info.bmiHeader.biWidth,
      (gint) (-src->info.bmiHeader.biHeight));

  new_buf = gst_buffer_new_and_alloc (new_buf_size);

  clock = gst_element_get_clock (GST_ELEMENT (src));
  if (clock != NULL) {
    GstClockTime time, base_time;

    /* Calculate sync time. */

    time = gst_clock_get_time (clock);
    base_time = gst_element_get_base_time (GST_ELEMENT (src));
    buf_time = time - base_time;

    if (src->rate_numerator) {
      frame_number = gst_util_uint64_scale (buf_time,
          src->rate_numerator, GST_SECOND * src->rate_denominator);
    } else {
      frame_number = -1;
    }
  } else {
    buf_time = GST_CLOCK_TIME_NONE;
    frame_number = -1;
  }

  if (frame_number != -1 && frame_number == src->frame_number) {
    GstClockID id;
    GstClockReturn ret;

    /* Need to wait for the next frame */
    frame_number += 1;

    /* Figure out what the next frame time is */
    buf_time = gst_util_uint64_scale (frame_number,
        src->rate_denominator * GST_SECOND, src->rate_numerator);

    id = gst_clock_new_single_shot_id (clock,
        buf_time + gst_element_get_base_time (GST_ELEMENT (src)));
    GST_OBJECT_LOCK (src);
    src->clock_id = id;
    GST_OBJECT_UNLOCK (src);

    GST_DEBUG_OBJECT (src, "Waiting for next frame time %" G_GUINT64_FORMAT,
        buf_time);
    ret = gst_clock_id_wait (id, NULL);
    GST_OBJECT_LOCK (src);

    gst_clock_id_unref (id);
    src->clock_id = NULL;
    if (ret == GST_CLOCK_UNSCHEDULED) {
      /* Got woken up by the unlock function */
      GST_OBJECT_UNLOCK (src);
      return GST_FLOW_FLUSHING;
    }
    GST_OBJECT_UNLOCK (src);

    /* Duration is a complete 1/fps frame duration */
    buf_dur =
        gst_util_uint64_scale_int (GST_SECOND, src->rate_denominator,
        src->rate_numerator);
  } else if (frame_number != -1) {
    GstClockTime next_buf_time;

    GST_DEBUG_OBJECT (src, "No need to wait for next frame time %"
        G_GUINT64_FORMAT " next frame = %" G_GINT64_FORMAT " prev = %"
        G_GINT64_FORMAT, buf_time, frame_number, src->frame_number);
    next_buf_time = gst_util_uint64_scale (frame_number + 1,
        src->rate_denominator * GST_SECOND, src->rate_numerator);
    /* Frame duration is from now until the next expected capture time */
    buf_dur = next_buf_time - buf_time;
  } else {
    buf_dur = GST_CLOCK_TIME_NONE;
  }
  src->frame_number = frame_number;

  GST_BUFFER_TIMESTAMP (new_buf) = buf_time;
  GST_BUFFER_DURATION (new_buf) = buf_dur;

  /* Do screen capture and put it into buffer... */
  gst_gdiscreencapsrc_screen_capture (src, new_buf);

  gst_object_unref (clock);

  *buf = new_buf;
  return GST_FLOW_OK;
}
Exemplo n.º 20
0
static void
paused_mode_task (gpointer data)
{
  GstMimEnc *mimenc = GST_MIMENC (data);
  GstClockTime now;
  GstClockTimeDiff diff;
  GstFlowReturn ret;

  if (!GST_ELEMENT_CLOCK (mimenc)) {
    GST_ERROR_OBJECT (mimenc, "Element has no clock");
    gst_pad_pause_task (mimenc->srcpad);
    return;
  }

  GST_OBJECT_LOCK (mimenc);

  if (mimenc->stop_paused_mode) {
    GST_OBJECT_UNLOCK (mimenc);
    goto stop_task;
  }

  now = gst_clock_get_time (GST_ELEMENT_CLOCK (mimenc));

  diff = now - GST_ELEMENT_CAST (mimenc)->base_time - mimenc->last_buffer;
  if (diff < 0)
    diff = 0;

  if (diff > 3.95 * GST_SECOND) {
    GstBuffer *buffer = gst_mimenc_create_tcp_header (mimenc, 0,
        mimenc->last_buffer + 4 * GST_SECOND, FALSE, TRUE);
    GstEvent *event = NULL;

    mimenc->last_buffer += 4 * GST_SECOND;

    if (mimenc->need_newsegment) {
      event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0);
      mimenc->need_newsegment = FALSE;
    }

    GST_OBJECT_UNLOCK (mimenc);
    GST_LOG_OBJECT (mimenc, "Haven't had an incoming buffer in 4 seconds,"
        " sending out a pause frame");

    if (event) {
      if (!gst_pad_push_event (mimenc->srcpad, event))
        GST_WARNING_OBJECT (mimenc, "Failed to push NEWSEGMENT event");
    }
    ret = gst_pad_push (mimenc->srcpad, buffer);
    if (ret < 0) {
      GST_WARNING_OBJECT (mimenc, "Error pushing paused header: %s",
          gst_flow_get_name (ret));
      goto stop_task;
    }
  } else {
    GstClockTime next_stop;
    GstClockID id;

    next_stop = now + (4 * GST_SECOND - MIN (diff, 4 * GST_SECOND));

    id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (mimenc), next_stop);

    if (mimenc->stop_paused_mode) {
      GST_OBJECT_UNLOCK (mimenc);
      goto stop_task;
    }

    mimenc->clock_id = id;
    GST_OBJECT_UNLOCK (mimenc);

    gst_clock_id_wait (id, NULL);

    GST_OBJECT_LOCK (mimenc);
    mimenc->clock_id = NULL;
    GST_OBJECT_UNLOCK (mimenc);

    gst_clock_id_unref (id);
  }
  return;

stop_task:

  gst_pad_pause_task (mimenc->srcpad);
}