/** * gst_clock_set_master * @clock: a #GstClock * @master: a master #GstClock * * Set @master as the master clock for @clock. @clock will be automatically * calibrated so that gst_clock_get_time() reports the same time as the * master clock. * * A clock provider that slaves its clock to a master can get the current * calibration values with gst_clock_get_calibration(). * * @master can be %NULL in which case @clock will not be slaved anymore. It will * however keep reporting its time adjusted with the last configured rate * and time offsets. * * Returns: %TRUE if the clock is capable of being slaved to a master clock. * Trying to set a master on a clock without the * #GST_CLOCK_FLAG_CAN_SET_MASTER flag will make this function return %FALSE. * * MT safe. */ gboolean gst_clock_set_master (GstClock * clock, GstClock * master) { GstClock **master_p; g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); g_return_val_if_fail (master != clock, FALSE); GST_OBJECT_LOCK (clock); /* we always allow setting the master to NULL */ if (master && !GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER)) goto not_supported; GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "slaving %p to master clock %p", clock, master); master_p = &clock->master; gst_object_replace ((GstObject **) master_p, (GstObject *) master); GST_OBJECT_UNLOCK (clock); GST_CLOCK_SLAVE_LOCK (clock); if (clock->clockid) { gst_clock_id_unschedule (clock->clockid); gst_clock_id_unref (clock->clockid); clock->clockid = NULL; } if (master) { clock->filling = TRUE; clock->time_index = 0; /* use the master periodic id to schedule sampling and * clock calibration. */ clock->clockid = gst_clock_new_periodic_id (master, gst_clock_get_time (master), clock->timeout); gst_clock_id_wait_async (clock->clockid, (GstClockCallback) gst_clock_slave_callback, clock); } GST_CLOCK_SLAVE_UNLOCK (clock); return TRUE; /* ERRORS */ not_supported: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "cannot be slaved to a master clock"); GST_OBJECT_UNLOCK (clock); return FALSE; } }
static gboolean _stop_pad (GstAggregator * self, GstAggregatorPad * pad, gpointer unused_udata) { _aggpad_flush (pad, self); PAD_LOCK_EVENT (pad); /* remove the timeouts */ if (pad->priv->timeout_id) { gst_clock_id_unschedule (pad->priv->timeout_id); gst_clock_id_unref (pad->priv->timeout_id); pad->priv->timeout_id = NULL; } PAD_UNLOCK_EVENT (pad); return TRUE; }
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; }
static void gst_imx_v4l2src_apply_focus_settings(GstImxV4l2VideoSrc *v4l2src, gboolean activate) { int locks, range; /* even when activating, first ensure that it is not running */ /* ensure that continuous autofocus is not running */ v4l2_s_ctrl(v4l2src, V4L2_CID_FOCUS_AUTO, 0); /* ensure that single shot AF is not running */ v4l2_s_ctrl(v4l2src, V4L2_CID_AUTO_FOCUS_STOP, 0); if (v4l2src->af_clock_id) { gst_clock_id_unschedule(v4l2src->af_clock_id); gst_clock_id_unref(v4l2src->af_clock_id); v4l2src->af_clock_id = NULL; } /* ensure that focus is not locked */ if (v4l2_g_ctrl(v4l2src, V4L2_CID_3A_LOCK, &locks) == 0 && (locks & V4L2_LOCK_FOCUS)) v4l2_s_ctrl(v4l2src, V4L2_CID_3A_LOCK, locks & ~V4L2_LOCK_FOCUS); if (activate) { /* set focus range */ switch (v4l2src->focus_mode) { case GST_PHOTOGRAPHY_FOCUS_MODE_AUTO: range = V4L2_AUTO_FOCUS_RANGE_AUTO; break; case GST_PHOTOGRAPHY_FOCUS_MODE_MACRO: range = V4L2_AUTO_FOCUS_RANGE_MACRO; break; case GST_PHOTOGRAPHY_FOCUS_MODE_INFINITY: range = V4L2_AUTO_FOCUS_RANGE_INFINITY; break; default: range = V4L2_AUTO_FOCUS_RANGE_NORMAL; break; } v4l2_s_ctrl(v4l2src, V4L2_CID_AUTO_FOCUS_RANGE, range); /* enable continuous autofocus if requested */ if (v4l2src->focus_mode == GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_NORMAL) v4l2_s_ctrl(v4l2src, V4L2_CID_FOCUS_AUTO, 1); } }
static gboolean remove_clock_cache (GstClock * clock, GstClockTime time, GstClockID id, gpointer user_data) { ClockCache *cache = user_data; G_LOCK (clocks_lock); if (!cache->clocks) { gst_clock_id_unref (cache->remove_id); gst_object_unref (cache->clock); clocks = g_list_remove (clocks, cache); g_free (cache); } G_UNLOCK (clocks_lock); return TRUE; }
static gboolean gst_imx_v4l2src_af_status_cb(GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data) { GstImxV4l2VideoSrc *v4l2src = GST_IMX_V4L2SRC(user_data); g_mutex_lock(&v4l2src->af_mutex); if (v4l2src->af_clock_id == id) { gst_clock_id_unref(v4l2src->af_clock_id); v4l2src->af_clock_id = NULL; gst_imx_v4l2src_af_check_status(v4l2src); } g_mutex_unlock(&v4l2src->af_mutex); return TRUE; }
static void gst_directsound_src_finalize (GObject * object) { GstDirectSoundSrc *dsoundsrc = GST_DIRECTSOUND_SRC (object); g_mutex_clear (&dsoundsrc->dsound_lock); gst_object_unref (dsoundsrc->system_clock); if (dsoundsrc->read_wait_clock_id != NULL) gst_clock_id_unref (dsoundsrc->read_wait_clock_id); g_free (dsoundsrc->device_name); g_free (dsoundsrc->device_id); g_free (dsoundsrc->device_guid); G_OBJECT_CLASS (parent_class)->finalize (object); }
/** * 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 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; } }
/* 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", ×tamp) && 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", ×tamp)) { 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; }
static void gst_clock_finalize (GObject * object) { GstClock *clock = GST_CLOCK (object); GST_CLOCK_SLAVE_LOCK (clock); if (clock->priv->clockid) { gst_clock_id_unschedule (clock->priv->clockid); gst_clock_id_unref (clock->priv->clockid); clock->priv->clockid = NULL; } g_free (clock->priv->times); clock->priv->times = NULL; GST_CLOCK_SLAVE_UNLOCK (clock); g_mutex_clear (&clock->priv->slave_lock); G_OBJECT_CLASS (parent_class)->finalize (object); }
static GstStateChangeReturn gst_identity_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstIdentity *identity = GST_IDENTITY (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (identity); if (identity->clock_id) { GST_DEBUG_OBJECT (identity, "unlock clock wait"); gst_clock_id_unschedule (identity->clock_id); gst_clock_id_unref (identity->clock_id); identity->clock_id = NULL; } GST_OBJECT_UNLOCK (identity); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
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; }
void gst_imx_v4l2src_set_autofocus(GstPhotography *photo, gboolean on) { GstImxV4l2VideoSrc *v4l2src = GST_IMX_V4L2SRC(photo); int locks; g_mutex_lock(&v4l2src->af_mutex); if (v4l2src->af_clock_id) { gst_clock_id_unschedule(v4l2src->af_clock_id); gst_clock_id_unref(v4l2src->af_clock_id); v4l2src->af_clock_id = NULL; } if (v4l2src->focus_mode == GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_NORMAL) { if (v4l2_g_ctrl(v4l2src, V4L2_CID_3A_LOCK, &locks) == 0) { if (on && !(locks & V4L2_LOCK_FOCUS)) v4l2_s_ctrl(v4l2src, V4L2_CID_3A_LOCK, locks | V4L2_LOCK_FOCUS); else if (!on && (locks & V4L2_LOCK_FOCUS)) v4l2_s_ctrl(v4l2src, V4L2_CID_3A_LOCK, locks & ~V4L2_LOCK_FOCUS); } } else { if (on) { if (v4l2_s_ctrl(v4l2src, V4L2_CID_AUTO_FOCUS_START, 0) == 0) gst_imx_v4l2src_af_check_status(v4l2src); } else v4l2_s_ctrl(v4l2src, V4L2_CID_AUTO_FOCUS_STOP, 0); } g_mutex_unlock(&v4l2src->af_mutex); }
gboolean clear_sender (gpointer key, gpointer value, gpointer user_data) { FsRtpTfrc *self = FS_RTP_TFRC (user_data); struct TrackedSource *src = value; src->send_ts_base = 0; src->send_ts_cycles = 0; src->fb_last_ts = 0; src->fb_ts_cycles = 0; if (src->sender_id) { gst_clock_id_unschedule (src->sender_id); gst_clock_id_unref (src->sender_id); src->sender_id = 0; } if (src->sender) tfrc_sender_free (src->sender); src->sender = NULL; if (src->idl) { tfrc_is_data_limited_free (src->idl); src->idl = NULL; } if (self->last_src == src) self->last_src = NULL; if (src->receiver) return FALSE; else return TRUE; }
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; }
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); }
// 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", ×tamp) && 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", ×tamp)) { 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; }
/** * 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; } }
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; }
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; } }
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; }
static gboolean gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event) { GstIdentity *identity; gboolean ret = TRUE; identity = GST_IDENTITY (trans); if (!identity->silent) { const GstStructure *s; const gchar *tstr; gchar *sstr; GST_OBJECT_LOCK (identity); g_free (identity->last_message); tstr = gst_event_type_get_name (GST_EVENT_TYPE (event)); if ((s = gst_event_get_structure (event))) sstr = gst_structure_to_string (s); else sstr = g_strdup (""); identity->last_message = g_strdup_printf ("event ******* (%s:%s) E (type: %s (%d), %s) %p", GST_DEBUG_PAD_NAME (trans->sinkpad), tstr, GST_EVENT_TYPE (event), sstr, event); g_free (sstr); GST_OBJECT_UNLOCK (identity); gst_identity_notify_last_message (identity); } if (identity->single_segment && (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT)) { if (trans->have_segment == FALSE) { GstEvent *news; GstSegment segment; gst_event_copy_segment (event, &segment); gst_event_copy_segment (event, &trans->segment); trans->have_segment = TRUE; /* This is the first segment, send out a (0, -1) segment */ gst_segment_init (&segment, segment.format); news = gst_event_new_segment (&segment); gst_pad_event_default (trans->sinkpad, GST_OBJECT_CAST (trans), news); } } /* Reset previous timestamp, duration and offsets on NEWSEGMENT * to prevent false warnings when checking for perfect streams */ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { identity->prev_timestamp = identity->prev_duration = GST_CLOCK_TIME_NONE; identity->prev_offset = identity->prev_offset_end = GST_BUFFER_OFFSET_NONE; } if (identity->single_segment && GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { /* eat up segments */ gst_event_unref (event); ret = TRUE; } else { if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) { GST_OBJECT_LOCK (identity); if (identity->clock_id) { GST_DEBUG_OBJECT (identity, "unlock clock wait"); gst_clock_id_unschedule (identity->clock_id); gst_clock_id_unref (identity->clock_id); identity->clock_id = NULL; } GST_OBJECT_UNLOCK (identity); } ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event); } return ret; }
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; }
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; } }
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; }
/* 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_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; }
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; }
static GstStateChangeReturn gst_identity_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstIdentity *identity = GST_IDENTITY (element); gboolean no_preroll = FALSE; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: GST_OBJECT_LOCK (identity); identity->blocked = TRUE; GST_OBJECT_UNLOCK (identity); if (identity->sync) no_preroll = TRUE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: GST_OBJECT_LOCK (identity); identity->blocked = FALSE; g_cond_broadcast (&identity->blocked_cond); GST_OBJECT_UNLOCK (identity); break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (identity); if (identity->clock_id) { GST_DEBUG_OBJECT (identity, "unlock clock wait"); gst_clock_id_unschedule (identity->clock_id); gst_clock_id_unref (identity->clock_id); identity->clock_id = NULL; } identity->blocked = FALSE; g_cond_broadcast (&identity->blocked_cond); GST_OBJECT_UNLOCK (identity); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: GST_OBJECT_LOCK (identity); identity->upstream_latency = 0; identity->blocked = TRUE; GST_OBJECT_UNLOCK (identity); if (identity->sync) no_preroll = TRUE; break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } if (no_preroll && ret == GST_STATE_CHANGE_SUCCESS) ret = GST_STATE_CHANGE_NO_PREROLL; return ret; }