Esempio 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);
}
Esempio 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);
}
static void
gst_dtls_connection_check_timeout_locked (GstDtlsConnection * self)
{
  GstDtlsConnectionPrivate *priv;
  struct timeval timeout;
  gint64 end_time, wait_time;

  g_return_if_fail (GST_IS_DTLS_CONNECTION (self));

  priv = self->priv;

  if (DTLSv1_get_timeout (priv->ssl, &timeout)) {
    wait_time = timeout.tv_sec * G_USEC_PER_SEC + timeout.tv_usec;

    GST_DEBUG_OBJECT (self, "waiting for %" G_GINT64_FORMAT " usec", wait_time);
    if (wait_time) {
      GstClock *system_clock = gst_system_clock_obtain ();
      GstClockID clock_id;
#ifndef G_DISABLE_ASSERT
      GstClockReturn clock_return;
#endif

      end_time = gst_clock_get_time (system_clock) + wait_time * GST_USECOND;

      clock_id = gst_clock_new_single_shot_id (system_clock, end_time);
#ifndef G_DISABLE_ASSERT
      clock_return =
#else
      (void)
#endif
          gst_clock_id_wait_async (clock_id, schedule_timeout_handling,
          g_object_ref (self), (GDestroyNotify) g_object_unref);
      g_assert (clock_return == GST_CLOCK_OK);
      gst_clock_id_unref (clock_id);
      gst_object_unref (system_clock);
    } else {
      if (self->priv->is_alive && !self->priv->timeout_pending) {
        self->priv->timeout_pending = TRUE;
        GST_TRACE_OBJECT (self, "Schedule timeout now");

        g_thread_pool_push (self->priv->thread_pool, GINT_TO_POINTER (0xc0ffee),
            NULL);
      }
    }
  } else {
    GST_DEBUG_OBJECT (self, "no timeout set");
  }
}
Esempio n. 4
0
static gboolean gstreamill_monitor (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data)
{
        GstClockID nextid;
        GstClockReturn ret;
        GstClockTime now;
        Gstreamill *gstreamill;
        GSList *list;

        gstreamill = (Gstreamill *)user_data;

        g_mutex_lock (&(gstreamill->job_list_mutex));

        /* remove stoped job from job list */
        clean_job_list (gstreamill);

        /* stop? */
        if (gstreamill->stop && g_slist_length (gstreamill->job_list) == 0) {
                GST_ERROR ("streamill stopped");
                exit (0);
        }

        /* check job stat */
        if (!gstreamill->stop) {
                list = gstreamill->job_list;
                g_slist_foreach (list, job_check_func, gstreamill);
        }

        /* log rotate. */
        if (gstreamill->daemon) {
                log_rotate (gstreamill);
                dvr_clean (gstreamill);
        }

        g_mutex_unlock (&(gstreamill->job_list_mutex));

        /* register streamill monitor */
        now = gst_clock_get_time (gstreamill->system_clock);
        nextid = gst_clock_new_single_shot_id (gstreamill->system_clock, now + 2000 * GST_MSECOND);
        ret = gst_clock_id_wait_async (nextid, gstreamill_monitor, gstreamill, NULL);
        gst_clock_id_unref (nextid);
        if (ret != GST_CLOCK_OK) {
                GST_WARNING ("Register gstreamill monitor failure");
                return FALSE;
        }

        return TRUE;
}
Esempio n. 5
0
/**
 * gstreamill_start:
 * @gstreamill: (in): gstreamill to be starting
 *
 * start gstreamill
 *
 * Returns: 0 on success.
 */
gint gstreamill_start (Gstreamill *gstreamill)
{
        GstClockID id;
        GstClockTime t;
        GstClockReturn ret;

        /* regist gstreamill monitor */
        t = gst_clock_get_time (gstreamill->system_clock)  + 5000 * GST_MSECOND;
        id = gst_clock_new_single_shot_id (gstreamill->system_clock, t); 
        ret = gst_clock_id_wait_async (id, gstreamill_monitor, gstreamill, NULL);
        gst_clock_id_unref (id);
        if (ret != GST_CLOCK_OK) {
                GST_WARNING ("Regist gstreamill monitor failure");
                return 1;
        }

        return 0;
}
static void
gst_net_client_clock_finalize (GObject * object)
{
  GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
  GList *l;

  if (self->priv->synced_id)
    g_signal_handler_disconnect (self->priv->internal_clock,
        self->priv->synced_id);
  self->priv->synced_id = 0;

  G_LOCK (clocks_lock);
  for (l = clocks; l; l = l->next) {
    ClockCache *cache = l->data;

    if (cache->clock == self->priv->internal_clock) {
      cache->clocks = g_list_remove (cache->clocks, self);

      if (cache->clocks) {
        update_clock_cache (cache);
      } else {
        GstClock *sysclock = gst_system_clock_obtain ();
        GstClockTime time = gst_clock_get_time (sysclock) + 60 * GST_SECOND;

        cache->remove_id = gst_clock_new_single_shot_id (sysclock, time);
        gst_clock_id_wait_async (cache->remove_id, remove_clock_cache, cache,
            NULL);
        gst_object_unref (sysclock);
      }
      break;
    }
  }
  G_UNLOCK (clocks_lock);

  g_free (self->priv->address);
  self->priv->address = NULL;

  if (self->priv->bus != NULL) {
    gst_object_unref (self->priv->bus);
    self->priv->bus = NULL;
  }

  G_OBJECT_CLASS (gst_net_client_clock_parent_class)->finalize (object);
}
Esempio n. 7
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;
  }
}
Esempio n. 8
0
/* receive spectral data from element message */
static gboolean
message_handler (GstBus * bus, GstMessage * message, gpointer data)
{
  if (message->type == GST_MESSAGE_ELEMENT) {
    const GstStructure *s = gst_message_get_structure (message);
    const gchar *name = gst_structure_get_name (s);

    if (strcmp (name, "spectrum") == 0) {
      GstElement *spectrum = GST_ELEMENT (GST_MESSAGE_SRC (message));
      GstClockTime timestamp, duration;
      GstClockTime waittime = GST_CLOCK_TIME_NONE;

      if (gst_structure_get_clock_time (s, "running-time", &timestamp) &&
          gst_structure_get_clock_time (s, "duration", &duration)) {
        /* wait for middle of buffer */
        waittime = timestamp + duration / 2;
      } else if (gst_structure_get_clock_time (s, "endtime", &timestamp)) {
        waittime = timestamp;
      }
      if (GST_CLOCK_TIME_IS_VALID (waittime)) {
        GstClockID clock_id;
        GstClockTime basetime = gst_element_get_base_time (spectrum);
        gfloat *spect = g_new (gfloat, spect_bands);
        const GValue *list;
        const GValue *value;
        guint i;

        list = gst_structure_get_value (s, "magnitude");
        for (i = 0; i < spect_bands; ++i) {
          value = gst_value_list_get_value (list, i);
          spect[i] = height_scale * g_value_get_float (value);
        }

        clock_id =
            gst_clock_new_single_shot_id (sync_clock, waittime + basetime);
        gst_clock_id_wait_async (clock_id, delayed_spectrum_update,
            (gpointer) spect);
        gst_clock_id_unref (clock_id);
      }
    }
  }
  return TRUE;
}
Esempio n. 9
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;
}
Esempio n. 10
0
/*
 * Class method: new(clock, time, interval=nil)
 * clock: a Gst::Clock.
 * time: a time period, in nanoseconds.
 * interval: an interval period, in nanoseconds.
 *
 * Creates a new Gst::ClockEntry object based on the given Gst::Clock.
 *
 * Two types of Gst::ClockEntry objects can be created:
 *
 * * One-shot: if the interval is ommited or nil, the entry will trigger a single shot notification, at the requested time (in nanoseconds);
 * * Periodic: if the interval is not nil, the timer entry will trigger a periodic notification, starting at time (in nanoseconds), and be fired with the given interval (also in nanoseconds).
 * 
 * The timer will be issued after Gst::ClockEntry#wait or
 * Gst::ClockEntry#wait_async.
 *
 * Returns: a new Gst::ClockEntry object.
 */
static VALUE
rg_initialize (int argc, VALUE * argv, VALUE self)
{
    VALUE clock, time, interval;
    GstClockID id;

    rb_scan_args (argc, argv, "21", &clock, &time, &interval);

    /*
     * Single-shot 
     */
    if (NIL_P (interval))
        id = gst_clock_new_single_shot_id (RVAL2GST_CLOCK (clock), NUM2ULL (time));
    /*
     * Periodic 
     */
    else
        id = gst_clock_new_periodic_id (RVAL2GST_CLOCK (clock),
                                        NUM2ULL (time), NUM2ULL (interval));

    G_INITIALIZE (self, GST_CLOCK_ENTRY (id));
    return Qnil;
}
Esempio n. 11
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;
}
Esempio n. 12
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;
    }
}
Esempio n. 13
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;
}
Esempio n. 14
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;
}
Esempio n. 15
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;

}
Esempio n. 16
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);
}
Esempio n. 17
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;
  }
}
Esempio n. 18
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;
  }
}
Esempio n. 19
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;
}
Esempio n. 20
0
static GstFlowReturn
_chain (GstPad * pad, GstObject * object, GstBuffer * buffer)
{
  GstBuffer *actual_buf = buffer;
  GstAggregator *self = GST_AGGREGATOR (object);
  GstAggregatorPrivate *priv = self->priv;
  GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad);
  GstAggregatorClass *aggclass = GST_AGGREGATOR_GET_CLASS (object);
  GstClockTime timeout = gst_aggregator_get_timeout (self);
  GstClockTime now;

  GST_DEBUG_OBJECT (aggpad, "Start chaining a buffer %" GST_PTR_FORMAT, buffer);
  if (aggpad->priv->timeout_id) {
    gst_clock_id_unschedule (aggpad->priv->timeout_id);
    gst_clock_id_unref (aggpad->priv->timeout_id);
    aggpad->priv->timeout_id = NULL;
  }
  g_atomic_int_set (&aggpad->unresponsive, FALSE);

  PAD_STREAM_LOCK (aggpad);

  if (g_atomic_int_get (&aggpad->priv->flushing) == TRUE)
    goto flushing;

  if (g_atomic_int_get (&aggpad->priv->pending_eos) == TRUE)
    goto eos;

  PAD_LOCK_EVENT (aggpad);

  if (aggpad->buffer) {
    GST_DEBUG_OBJECT (aggpad, "Waiting for buffer to be consumed");
    PAD_WAIT_EVENT (aggpad);
  }
  PAD_UNLOCK_EVENT (aggpad);

  if (g_atomic_int_get (&aggpad->priv->flushing) == TRUE)
    goto flushing;

  if (aggclass->clip) {
    aggclass->clip (self, aggpad, buffer, &actual_buf);
  }

  PAD_LOCK_EVENT (aggpad);
  if (aggpad->buffer)
    gst_buffer_unref (aggpad->buffer);
  aggpad->buffer = actual_buf;
  PAD_UNLOCK_EVENT (aggpad);
  PAD_STREAM_UNLOCK (aggpad);

  QUEUE_PUSH (self);

  if (GST_CLOCK_TIME_IS_VALID (timeout)) {
    now = gst_clock_get_time (self->clock);
    aggpad->priv->timeout_id =
        gst_clock_new_single_shot_id (self->clock, now + timeout);
    gst_clock_id_wait_async (aggpad->priv->timeout_id, _unresponsive_timeout,
        gst_object_ref (aggpad), gst_object_unref);
  }

  GST_DEBUG_OBJECT (aggpad, "Done chaining");

  return priv->flow_return;

flushing:
  PAD_STREAM_UNLOCK (aggpad);

  gst_buffer_unref (buffer);
  GST_DEBUG_OBJECT (aggpad, "We are flushing");

  return GST_FLOW_FLUSHING;

eos:
  PAD_STREAM_UNLOCK (aggpad);

  gst_buffer_unref (buffer);
  GST_DEBUG_OBJECT (pad, "We are EOS already...");

  return GST_FLOW_EOS;
}
// get spectrum messages and delay them
static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data)
{
	base *base_object = data;
	GstElement *spectrum = GST_ELEMENT(base_object->spectrum_element->obj);
	gst_object_ref(spectrum);

	GstElement *message_element = GST_ELEMENT(GST_MESSAGE_SRC(message));
	gst_object_ref(message_element);

	if (message_element == spectrum)
	{
		GstClockTime waittime = GST_CLOCK_TIME_NONE;
		const GstStructure *message_structure = gst_message_get_structure(message);

		// determine waittime
		GstClockTime timestamp, duration;

		if (
			   gst_structure_get_clock_time(message_structure, "running-time", &timestamp)
			&& gst_structure_get_clock_time(message_structure, "duration", &duration)
		)
		{
			/* wait for middle of buffer */
			waittime = timestamp + duration/2;
		}
		else if (gst_structure_get_clock_time(message_structure, "endtime", &timestamp))
		{
			waittime = timestamp;
		}

		// delay message
		if (GST_CLOCK_TIME_IS_VALID(waittime))
		{
			GstClockTime basetime = gst_element_get_base_time(spectrum);
			GstClockID clock_id = gst_clock_new_single_shot_id(base_object->sync_clock, basetime+waittime);
			spectrum_message *mess = g_malloc(sizeof(spectrum_message));

			// set bands and threshold
			g_object_get(message_element, "bands", &(mess->bands), "threshold", &(mess->threshold), NULL);

			// set start and duration
			GstClockTime streamtime, duration;
			gst_structure_get_clock_time(message_structure, "stream-time", &streamtime);
			gst_structure_get_clock_time(message_structure, "duration", &duration);

			mess->start = (gfloat)streamtime / GST_SECOND;
			mess->duration = (gfloat)duration / GST_SECOND;

			// set rate
			GstPad *sink = gst_element_get_static_pad(GST_ELEMENT(base_object->spectrum_element->obj), "sink");
			GstCaps *caps = gst_pad_get_negotiated_caps(sink);
			gst_object_unref(sink);

			GstStructure *caps_structure = gst_caps_get_structure(caps, 0);
			gst_structure_get_int(caps_structure, "rate", &(mess->rate));
			gst_caps_unref(caps);

			// set magnitudes
			const GValue *list = gst_structure_get_value(message_structure, "magnitude");

			PyGILState_STATE gstate = PyGILState_Ensure();

			int i;
			mess->magnitudes = PyList_New(mess->bands);
			for (i=0; i < (mess->bands); i++)
			{
				const GValue *value = gst_value_list_get_value(list, i);
				gfloat f = g_value_get_float(value);
				PyList_SetItem(mess->magnitudes, i, Py_BuildValue("f", f));
			}

			PyGILState_Release(gstate);

			// set gobj
			GObject *gobj = (base_object->gobj).obj;
			g_assert(gobj != NULL);
			g_object_ref(gobj);
			mess->gobj = gobj;

			// delay message
			gst_clock_id_wait_async(clock_id, delayed_spectrum_update, mess);

			gst_clock_id_unref(clock_id);
		}
	}

	gst_object_unref(spectrum);
	gst_object_unref(message_element);

	return TRUE;
}
Esempio n. 22
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);
}
Esempio n. 23
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;
  }
}
Esempio n. 24
0
static void gst_imx_v4l2src_af_check_status(GstImxV4l2VideoSrc *v4l2src)
{
	int status;
	gboolean send_message;
	GstPhotographyFocusStatus message_status;
	gboolean schedule_recheck;

	if (v4l2_g_ctrl(v4l2src, V4L2_CID_AUTO_FOCUS_STATUS, &status) < 0)
		goto none;

	switch (status)
	{
		case V4L2_AUTO_FOCUS_STATUS_IDLE:
		default:
		none:
			send_message = TRUE;
			message_status = GST_PHOTOGRAPHY_FOCUS_STATUS_NONE;
			schedule_recheck = FALSE;
			break;
		case V4L2_AUTO_FOCUS_STATUS_BUSY:
			send_message = FALSE;
			schedule_recheck = TRUE;
			break;
		case V4L2_AUTO_FOCUS_STATUS_REACHED:
			send_message = TRUE;
			message_status = GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS;
			schedule_recheck = FALSE;
			break;
		case V4L2_AUTO_FOCUS_STATUS_FAILED:
			send_message = TRUE;
			message_status = GST_PHOTOGRAPHY_FOCUS_STATUS_FAIL;
			schedule_recheck = FALSE;
			break;
	}

	if (send_message)
	{
		GstStructure *s;
		GstMessage *m;

		s = gst_structure_new(GST_PHOTOGRAPHY_AUTOFOCUS_DONE,
				"status", G_TYPE_INT, message_status,
				NULL);
		m = gst_message_new_custom(GST_MESSAGE_ELEMENT,
				GST_OBJECT(v4l2src), s);

		if (!gst_element_post_message(GST_ELEMENT(v4l2src), m))
			GST_ERROR_OBJECT(v4l2src, "failed to post message");
	}

	if (schedule_recheck)
	{
		GstClock *c;
		GstClockTime t;

		c = gst_system_clock_obtain();
		t = gst_clock_get_time(c) + 50 * GST_MSECOND;
		v4l2src->af_clock_id = gst_clock_new_single_shot_id(c, t);
		gst_object_unref(c);

		if (gst_clock_id_wait_async(v4l2src->af_clock_id,
					gst_imx_v4l2src_af_status_cb,
					v4l2src, NULL) != GST_CLOCK_OK)
			GST_ERROR_OBJECT(v4l2src, "failed to schedule recheck");
	}
}
Esempio n. 25
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;
}
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;
}
Esempio n. 27
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);
}