static gboolean _latency_query (GstAggregator * self, GstPad * pad, gpointer user_data) { LatencyData *data = user_data; GstClockTime min, max; GstQuery *query; gboolean live, res; query = gst_query_new_latency (); res = gst_pad_peer_query (pad, query); if (res) { gst_query_parse_latency (query, &live, &min, &max); GST_LOG_OBJECT (self, "got latency live:%s min:%" G_GINT64_FORMAT " max:%" G_GINT64_FORMAT, live ? "true" : "false", min, max); if (min > data->min) data->min = min; if (max != GST_CLOCK_TIME_NONE && ((data->max != GST_CLOCK_TIME_NONE && max < data->max) || (data->max == GST_CLOCK_TIME_NONE))) data->max = max; data->live |= live; } gst_query_unref (query); return TRUE; }
static gboolean audioresample_query (GstPad * pad, GstQuery * query) { GstAudioresample *audioresample = GST_AUDIORESAMPLE (gst_pad_get_parent (pad)); GstBaseTransform *trans = GST_BASE_TRANSFORM (audioresample); gboolean res = TRUE; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; guint64 latency; GstPad *peer; gint rate = audioresample->i_rate; gint resampler_latency = audioresample->filter_length / 2; if (gst_base_transform_is_passthrough (trans)) resampler_latency = 0; if ((peer = gst_pad_get_peer (trans->sinkpad))) { if ((res = gst_pad_query (peer, query))) { gst_query_parse_latency (query, &live, &min, &max); GST_DEBUG ("Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); /* add our own latency */ if (rate != 0 && resampler_latency != 0) latency = gst_util_uint64_scale (resampler_latency, GST_SECOND, rate); else latency = 0; GST_DEBUG ("Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); min += latency; if (max != GST_CLOCK_TIME_NONE) max += latency; GST_DEBUG ("Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } gst_object_unref (peer); } break; } default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (audioresample); return res; }
static gboolean gst_goom_src_query (GstPad * pad, GstQuery * query) { gboolean res = FALSE; GstGoom *goom; goom = GST_GOOM (gst_pad_get_parent (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { /* We need to send the query upstream and add the returned latency to our * own */ GstClockTime min_latency, max_latency; gboolean us_live; GstClockTime our_latency; guint max_samples; if (goom->rate == 0) break; if ((res = gst_pad_peer_query (goom->sinkpad, query))) { gst_query_parse_latency (query, &us_live, &min_latency, &max_latency); GST_DEBUG_OBJECT (goom, "Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); /* the max samples we must buffer buffer */ max_samples = MAX (GOOM_SAMPLES, goom->spf); our_latency = gst_util_uint64_scale_int (max_samples, GST_SECOND, goom->rate); GST_DEBUG_OBJECT (goom, "Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (our_latency)); /* we add some latency but only if we need to buffer more than what * upstream gives us */ min_latency += our_latency; if (max_latency != -1) max_latency += our_latency; GST_DEBUG_OBJECT (goom, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); gst_query_set_latency (query, TRUE, min_latency, max_latency); } break; } default: res = gst_pad_peer_query (goom->sinkpad, query); break; } gst_object_unref (goom); return res; }
static gboolean gst_audio_fx_base_fir_filter_query (GstPad * pad, GstQuery * query) { GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (gst_pad_get_parent (pad)); gboolean res = TRUE; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; guint64 latency; GstPad *peer; gint rate = GST_AUDIO_FILTER (self)->format.rate; if (rate == 0) { res = FALSE; } else if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM (self)->sinkpad))) { if ((res = gst_pad_query (peer, query))) { gst_query_parse_latency (query, &live, &min, &max); GST_DEBUG_OBJECT (self, "Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); if (self->fft && !self->low_latency) latency = self->block_length - self->kernel_length + 1; else latency = self->latency; /* add our own latency */ latency = gst_util_uint64_scale_round (latency, GST_SECOND, rate); GST_DEBUG_OBJECT (self, "Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); min += latency; if (max != GST_CLOCK_TIME_NONE) max += latency; GST_DEBUG_OBJECT (self, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } gst_object_unref (peer); } break; } default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (self); return res; }
static gboolean gst_base_video_encoder_src_query (GstPad * pad, GstQuery * query) { GstBaseVideoEncoder *enc; gboolean res; GstPad *peerpad; enc = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); peerpad = gst_pad_get_peer (GST_BASE_VIDEO_CODEC_SINK_PAD (enc)); switch GST_QUERY_TYPE (query) { case GST_QUERY_CONVERT: { GstFormat src_fmt, dest_fmt; gint64 src_val, dest_val; gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); res = gst_base_video_encoded_video_convert (&GST_BASE_VIDEO_CODEC (enc)->state, src_fmt, src_val, &dest_fmt, &dest_val); if (!res) goto error; gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); break; } case GST_QUERY_LATENCY: { gboolean live; GstClockTime min_latency, max_latency; res = gst_pad_query (peerpad, query); if (res) { gst_query_parse_latency (query, &live, &min_latency, &max_latency); min_latency += enc->min_latency; if (max_latency != GST_CLOCK_TIME_NONE) { max_latency += enc->max_latency; } gst_query_set_latency (query, live, min_latency, max_latency); } } break; default: res = gst_pad_query_default (pad, query); } gst_object_unref (peerpad); gst_object_unref (enc); return res; error: GST_DEBUG_OBJECT (enc, "query failed"); gst_object_unref (peerpad); gst_object_unref (enc); return res; }
static gboolean gst_rtp_jitter_buffer_query (GstPad * pad, GstQuery * query) { GstRtpJitterBuffer *jitterbuffer; GstRtpJitterBufferPrivate *priv; gboolean res = FALSE; jitterbuffer = GST_RTP_JITTER_BUFFER (gst_pad_get_parent (pad)); priv = jitterbuffer->priv; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { /* We need to send the query upstream and add the returned latency to our * own */ GstClockTime min_latency, max_latency; gboolean us_live; GstClockTime our_latency; if ((res = gst_pad_peer_query (priv->sinkpad, query))) { gst_query_parse_latency (query, &us_live, &min_latency, &max_latency); GST_DEBUG_OBJECT (jitterbuffer, "Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); /* store this so that we can safely sync on the peer buffers. */ JBUF_LOCK (priv); priv->peer_latency = min_latency; our_latency = ((guint64) priv->latency_ms) * GST_MSECOND; JBUF_UNLOCK (priv); GST_DEBUG_OBJECT (jitterbuffer, "Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (our_latency)); /* we add some latency but can buffer an infinite amount of time */ min_latency += our_latency; max_latency = -1; GST_DEBUG_OBJECT (jitterbuffer, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); gst_query_set_latency (query, TRUE, min_latency, max_latency); } break; } default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (jitterbuffer); return res; }
uint64_t ofGstUtils::getMaxLatencyNanos(){ GstClockTime minlat=0, maxlat=0; GstQuery * q = gst_query_new_latency(); if (gst_element_query (gstPipeline, q)) { gboolean live; gst_query_parse_latency (q, &live, &minlat, &maxlat); } gst_query_unref (q); return maxlat; }
static VALUE latency_parse(VALUE self) { GstClockTime min_latency; GstClockTime max_latency; gboolean live; gst_query_parse_latency(RVAL2GST_QUERY(self), &live, &min_latency, &max_latency); return rb_ary_new3(3, CBOOL2RVAL(live), ULL2NUM(min_latency), ULL2NUM(max_latency)); }
static void query_upstream_latency (MpegTSBase * base) { GstQuery *query; query = gst_query_new_latency (); if (gst_pad_peer_query (base->sinkpad, query)) { gst_query_parse_latency (query, &base->upstream_live, NULL, NULL); GST_DEBUG_OBJECT (base, "Upstream is %s", base->upstream_live ? "LIVE" : "NOT LIVE"); } else GST_WARNING_OBJECT (base, "Failed to query upstream latency"); gst_query_unref (query); base->queried_latency = TRUE; }
static gboolean kms_agnostic_bin2_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) { gboolean ret; ret = gst_pad_query_default (pad, parent, query); if (ret && GST_QUERY_TYPE (query) == GST_QUERY_LATENCY) { GstClockTime min_latency; GstClockTime max_latency; gst_query_parse_latency (query, NULL, &min_latency, &max_latency); gst_query_set_latency (query, TRUE, min_latency, max_latency); } return ret; }
static gboolean gst_identity_query (GstBaseTransform * base, GstPadDirection direction, GstQuery * query) { GstIdentity *identity; gboolean ret; identity = GST_IDENTITY (base); ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (base, direction, query); if (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY) { gboolean live = FALSE; GstClockTime min = 0, max = 0; if (ret) { gst_query_parse_latency (query, &live, &min, &max); if (identity->sync && max < min) { GST_ELEMENT_WARNING (base, CORE, CLOCK, (NULL), ("Impossible to configure latency before identity sync=true:" " max %" GST_TIME_FORMAT " < min %" GST_TIME_FORMAT ". Add queues or other buffering elements.", GST_TIME_ARGS (max), GST_TIME_ARGS (min))); } } /* Ignore the upstream latency if it is not live */ GST_OBJECT_LOCK (identity); if (live) identity->upstream_latency = min; else identity->upstream_latency = 0; GST_OBJECT_UNLOCK (identity); gst_query_set_latency (query, live || identity->sync, min, max); ret = TRUE; } return ret; }
static gboolean gst_rtp_ssrc_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstRtpSsrcDemux *demux; gboolean res = FALSE; demux = GST_RTP_SSRC_DEMUX (parent); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { if ((res = gst_pad_peer_query (demux->rtp_sink, query))) { gboolean live; GstClockTime min_latency, max_latency; GstRtpSsrcDemuxPad *demuxpad; demuxpad = gst_pad_get_element_private (pad); gst_query_parse_latency (query, &live, &min_latency, &max_latency); GST_DEBUG_OBJECT (demux, "peer min latency %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency)); GST_DEBUG_OBJECT (demux, "latency for SSRC %08x", demuxpad->ssrc); gst_query_set_latency (query, live, min_latency, max_latency); } break; } default: res = gst_pad_query_default (pad, parent, query); break; } return res; }
static gboolean gst_webrtc_echo_probe_src_event (GstBaseTransform * btrans, GstEvent * event) { GstBaseTransformClass *klass; GstWebrtcEchoProbe *self = GST_WEBRTC_ECHO_PROBE (btrans); GstClockTime latency; GstClockTime upstream_latency = 0; GstQuery *query; klass = GST_BASE_TRANSFORM_CLASS (gst_webrtc_echo_probe_parent_class); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_LATENCY: gst_event_parse_latency (event, &latency); query = gst_query_new_latency (); if (gst_pad_query (btrans->srcpad, query)) { gst_query_parse_latency (query, NULL, &upstream_latency, NULL); if (!GST_CLOCK_TIME_IS_VALID (upstream_latency)) upstream_latency = 0; } GST_WEBRTC_ECHO_PROBE_LOCK (self); self->latency = latency; self->delay = upstream_latency / GST_MSECOND; GST_WEBRTC_ECHO_PROBE_UNLOCK (self); GST_DEBUG_OBJECT (self, "We have a latency of %" GST_TIME_FORMAT " and delay of %ims", GST_TIME_ARGS (latency), (gint) (upstream_latency / GST_MSECOND)); break; default: break; } return klass->src_event (btrans, event); }
bool LatencyQuery::hasLive() const { gboolean l; gst_query_parse_latency(object<GstQuery>(), &l, NULL, NULL); return l; }
static gboolean gst_video_rate_query (GstBaseTransform * trans, GstPadDirection direction, GstQuery * query) { GstVideoRate *videorate = GST_VIDEO_RATE (trans); gboolean res = FALSE; GstPad *otherpad; otherpad = (direction == GST_PAD_SRC) ? GST_BASE_TRANSFORM_SINK_PAD (trans) : GST_BASE_TRANSFORM_SRC_PAD (trans); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; guint64 latency; guint64 avg_period; GstPad *peer; GST_OBJECT_LOCK (videorate); avg_period = videorate->average_period_set; GST_OBJECT_UNLOCK (videorate); if (avg_period == 0 && (peer = gst_pad_get_peer (otherpad))) { if ((res = gst_pad_query (peer, query))) { gst_query_parse_latency (query, &live, &min, &max); GST_DEBUG_OBJECT (videorate, "Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); if (videorate->from_rate_numerator != 0) { /* add latency. We don't really know since we hold on to the frames * until we get a next frame, which can be anything. We assume * however that this will take from_rate time. */ latency = gst_util_uint64_scale (GST_SECOND, videorate->from_rate_denominator, videorate->from_rate_numerator); } else { /* no input framerate, we don't know */ latency = 0; } GST_DEBUG_OBJECT (videorate, "Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); min += latency; if (max != -1) max += latency; GST_DEBUG_OBJECT (videorate, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } gst_object_unref (peer); break; } /* Simple fallthrough if we don't have a latency or not a peer that we * can't ask about its latency yet.. */ } default: res = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction, query); break; } return res; }
static gboolean gst_pipeline_do_latency (GstBin * bin) { GstPipeline *pipeline = GST_PIPELINE (bin); GstQuery *query; GstClockTime latency; GstClockTime min_latency, max_latency; gboolean res; GST_OBJECT_LOCK (pipeline); latency = pipeline->priv->latency; GST_OBJECT_UNLOCK (pipeline); if (latency == GST_CLOCK_TIME_NONE) return GST_BIN_CLASS (parent_class)->do_latency (bin); GST_DEBUG_OBJECT (pipeline, "querying latency"); query = gst_query_new_latency (); if ((res = gst_element_query (GST_ELEMENT_CAST (pipeline), query))) { gboolean live; gst_query_parse_latency (query, &live, &min_latency, &max_latency); GST_DEBUG_OBJECT (pipeline, "got min latency %" GST_TIME_FORMAT ", max latency %" GST_TIME_FORMAT ", live %d", GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency), live); if (max_latency < min_latency) { /* this is an impossible situation, some parts of the pipeline might not * work correctly. We post a warning for now. */ GST_ELEMENT_WARNING (pipeline, CORE, CLOCK, (NULL), ("Impossible to configure latency: max %" GST_TIME_FORMAT " < min %" GST_TIME_FORMAT ". Add queues or other buffering elements.", GST_TIME_ARGS (max_latency), GST_TIME_ARGS (min_latency))); } if (latency < min_latency) { /* This is a problematic situation as we will most likely drop lots of * data if we configure a too low latency */ GST_ELEMENT_WARNING (pipeline, CORE, CLOCK, (NULL), ("Configured latency is lower than detected minimum latency: configured %" GST_TIME_FORMAT " < min %" GST_TIME_FORMAT, GST_TIME_ARGS (latency), GST_TIME_ARGS (min_latency))); } } else { /* this is not a real problem, we just don't configure any latency. */ GST_WARNING_OBJECT (pipeline, "failed to query latency"); } gst_query_unref (query); /* configure latency on elements */ res = gst_element_send_event (GST_ELEMENT_CAST (pipeline), gst_event_new_latency (latency)); if (res) { GST_INFO_OBJECT (pipeline, "configured latency of %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); } else { GST_WARNING_OBJECT (pipeline, "did not really configure latency of %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); } return res; }
static gboolean gst_live_adder_query (GstPad * pad, GstQuery * query) { GstLiveAdder *adder; gboolean res = FALSE; adder = GST_LIVE_ADDER (gst_pad_get_parent (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { /* We need to send the query upstream and add the returned latency to our * own */ GstClockTime min_latency = 0, max_latency = G_MAXUINT64; gpointer item; GstIterator *iter = NULL; gboolean done = FALSE; iter = gst_element_iterate_sink_pads (GST_ELEMENT (adder)); while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: { GstPad *sinkpad = item; GstClockTime pad_min_latency, pad_max_latency; gboolean pad_us_live; if (gst_pad_peer_query (sinkpad, query)) { gst_query_parse_latency (query, &pad_us_live, &pad_min_latency, &pad_max_latency); res = TRUE; GST_DEBUG_OBJECT (adder, "Peer latency for pad %s: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_PAD_NAME (sinkpad), GST_TIME_ARGS (pad_min_latency), GST_TIME_ARGS (pad_max_latency)); min_latency = MAX (pad_min_latency, min_latency); max_latency = MIN (pad_max_latency, max_latency); } gst_object_unref (item); } break; case GST_ITERATOR_RESYNC: min_latency = 0; max_latency = G_MAXUINT64; gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: GST_ERROR_OBJECT (adder, "Error looping sink pads"); done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (iter); if (res) { GstClockTime my_latency = adder->latency_ms * GST_MSECOND; GST_OBJECT_LOCK (adder); adder->peer_latency = min_latency; min_latency += my_latency; GST_OBJECT_UNLOCK (adder); /* Make sure we don't risk an overflow */ if (max_latency < G_MAXUINT64 - my_latency) max_latency += my_latency; else max_latency = G_MAXUINT64; gst_query_set_latency (query, TRUE, min_latency, max_latency); GST_DEBUG_OBJECT (adder, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); } break; } case GST_QUERY_DURATION: res = gst_live_adder_query_duration (adder, query); break; case GST_QUERY_POSITION: res = gst_live_adder_query_position (adder, query); break; default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (adder); return res; }
static gboolean gst_speex_enc_src_query (GstPad * pad, GstQuery * query) { gboolean res = TRUE; GstSpeexEnc *enc; enc = GST_SPEEX_ENC (gst_pad_get_parent (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: { GstFormat fmt, req_fmt; gint64 pos, val; gst_query_parse_position (query, &req_fmt, NULL); if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) { gst_query_set_position (query, req_fmt, val); break; } fmt = GST_FORMAT_TIME; if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos))) break; if ((res = gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt, &val))) gst_query_set_position (query, req_fmt, val); break; } case GST_QUERY_DURATION: { GstFormat fmt, req_fmt; gint64 dur, val; gst_query_parse_duration (query, &req_fmt, NULL); if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) { gst_query_set_duration (query, req_fmt, val); break; } fmt = GST_FORMAT_TIME; if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur))) break; if ((res = gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt, &val))) { gst_query_set_duration (query, req_fmt, val); } break; } case GST_QUERY_CONVERT: { GstFormat src_fmt, dest_fmt; gint64 src_val, dest_val; gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt, &dest_val))) goto error; gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); break; } case GST_QUERY_LATENCY: { gboolean live; GstClockTime min_latency, max_latency; gint64 latency; if ((res = gst_pad_peer_query (enc->sinkpad, query))) { gst_query_parse_latency (query, &live, &min_latency, &max_latency); GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query); latency = gst_speex_enc_get_latency (enc); /* add our latency */ min_latency += latency; if (max_latency != -1) max_latency += latency; gst_query_set_latency (query, live, min_latency, max_latency); GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query); } break; } default: res = gst_pad_peer_query (enc->sinkpad, query); break; } error: gst_object_unref (enc); return res; }
ClockTime LatencyQuery::maximumLatency() const { GstClockTime c; gst_query_parse_latency(object<GstQuery>(), NULL, NULL, &c); return c; }
static gboolean gst_adder_query_latency (GstAdder * adder, GstQuery * query) { GstClockTime min, max; gboolean live; gboolean res; GstIterator *it; gboolean done; res = TRUE; done = FALSE; live = FALSE; min = 0; max = GST_CLOCK_TIME_NONE; /* Take maximum of all latency values */ it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder)); while (!done) { GstIteratorResult ires; gpointer item; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = GST_PAD_CAST (item); GstQuery *peerquery; GstClockTime min_cur, max_cur; gboolean live_cur; peerquery = gst_query_new_latency (); /* Ask peer for latency */ res &= gst_pad_peer_query (pad, peerquery); /* take max from all valid return values */ if (res) { gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur); if (min_cur > min) min = min_cur; if (max_cur != GST_CLOCK_TIME_NONE && ((max != GST_CLOCK_TIME_NONE && max_cur > max) || (max == GST_CLOCK_TIME_NONE))) max = max_cur; live = live || live_cur; } gst_query_unref (peerquery); gst_object_unref (pad); break; } case GST_ITERATOR_RESYNC: live = FALSE; min = 0; max = GST_CLOCK_TIME_NONE; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } } gst_iterator_free (it); if (res) { /* store the results */ GST_DEBUG_OBJECT (adder, "Calculated total latency: live %s, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } return res; }
static gboolean gst_visual_gl_src_query (GstPad * pad, GstQuery * query) { gboolean res; GstVisualGL *visual; visual = GST_VISUAL_GL (gst_pad_get_parent (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { /* We need to send the query upstream and add the returned latency to our * own */ GstClockTime min_latency, max_latency; gboolean us_live; GstClockTime our_latency; guint max_samples; if ((res = gst_pad_peer_query (visual->sinkpad, query))) { gst_query_parse_latency (query, &us_live, &min_latency, &max_latency); GST_DEBUG_OBJECT (visual, "Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); /* the max samples we must buffer buffer */ max_samples = MAX (VISUAL_SAMPLES, visual->spf); our_latency = gst_util_uint64_scale_int (max_samples, GST_SECOND, visual->rate); GST_DEBUG_OBJECT (visual, "Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (our_latency)); /* we add some latency but only if we need to buffer more than what * upstream gives us */ min_latency += our_latency; if (max_latency != -1) max_latency += our_latency; GST_DEBUG_OBJECT (visual, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); gst_query_set_latency (query, TRUE, min_latency, max_latency); } break; } case GST_QUERY_CUSTOM: { GstStructure *structure = gst_query_get_structure (query); gchar *name = gst_element_get_name (visual); res = g_strcmp0 (name, gst_structure_get_name (structure)) == 0; g_free (name); if (!res) res = gst_pad_query_default (pad, query); break; } default: res = gst_pad_peer_query (visual->sinkpad, query); break; } gst_object_unref (visual); return res; }
static gboolean gst_deinterlace2_src_query (GstPad * pad, GstQuery * query) { GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad)); gboolean res = FALSE; GST_LOG_OBJECT (self, "%s query", GST_QUERY_TYPE_NAME (query)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; GstPad *peer; if ((peer = gst_pad_get_peer (self->sinkpad))) { if ((res = gst_pad_query (peer, query))) { GstClockTime latency; gint fields_required = 0; gint method_latency = 0; if (self->method) { fields_required = gst_deinterlace_method_get_fields_required (self->method); method_latency = gst_deinterlace_method_get_latency (self->method); } gst_query_parse_latency (query, &live, &min, &max); GST_DEBUG ("Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); /* add our own latency */ latency = (fields_required + method_latency) * self->field_duration; GST_DEBUG ("Our latency: min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, GST_TIME_ARGS (latency), GST_TIME_ARGS (latency)); min += latency; if (max != GST_CLOCK_TIME_NONE) max += latency; else max = latency; GST_DEBUG ("Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } gst_object_unref (peer); } break; } default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (self); return res; }
static gboolean hls_test_bus_message (InsanityGstPipelineTest * ptest, GstMessage * msg) { switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_BUFFERING: { gint per; gst_message_parse_buffering (msg, &per); /* First buffering happend properly, this is requiered to be able to * start seeking */ if (G_UNLIKELY (glob_buffered == FALSE)) { if (per == 100) { insanity_test_validate_checklist_item (INSANITY_TEST (ptest), "done-buffering", TRUE, NULL); glob_buffered = TRUE; if (glob_buffering_timeout != 0) { g_source_remove (glob_buffering_timeout); glob_buffering_timeout = 0; } } else { glob_buffering_timeout = g_timeout_add (250, (GSourceFunc) buffering_timeout, INSANITY_TEST (ptest)); } } break; } case GST_MESSAGE_STATE_CHANGED: if (GST_MESSAGE_SRC (msg) == GST_OBJECT (glob_pipeline)) { const char *validate_checklist_item = glob_validate_on_playing; GstState oldstate, newstate, pending; gst_message_parse_state_changed (msg, &oldstate, &newstate, &pending); if (newstate == GST_STATE_PAUSED && oldstate == GST_STATE_READY) { GstIterator *it; GValue v = { 0, }; gboolean queried; InsanityTest *test = INSANITY_TEST (ptest); GstQuery *query = gst_query_new_latency (); const gchar *step_message = "Could not query seeking\n"; if ((queried = gst_element_query (glob_pipeline, query))) { gst_query_parse_latency (query, &glob_is_live, NULL, NULL); step_message = NULL; } else insanity_test_printf (test, "Could not query\n"); insanity_gst_pipeline_test_set_live (ptest, glob_is_live); insanity_test_validate_checklist_item (test, "queried-live", queried, step_message); gst_query_unref (query); step_message = "Could not query seekable\n"; query = gst_query_new_seeking (GST_FORMAT_TIME); if ((queried = gst_element_query (glob_pipeline, query))) { gst_query_parse_seeking (query, NULL, &glob_is_seekable, NULL, NULL); step_message = NULL; } else insanity_test_printf (test, "Could not query\n"); insanity_test_validate_checklist_item (test, "queried-seekable", queried, step_message); gst_query_unref (query); /* Iterate over the bins to find a hlsdemux */ it = gst_bin_iterate_recurse (GST_BIN (glob_pipeline)); if (gst_iterator_find_custom (it, (GCompareFunc) find_hlsdemux, &v, NULL)) { glob_hlsdemux = g_value_dup_object (&v); } g_value_unset (&v); gst_iterator_free (it); if (glob_hlsdemux != NULL) { insanity_test_validate_checklist_item (test, "protocol-is-hls", TRUE, "HLS protocol in use"); gst_object_unref (glob_hlsdemux); } else { insanity_test_validate_checklist_item (test, "protocol-is-hls", FALSE, "HLS protocol in use"); insanity_test_done (test); } /* Watch pipeline only if seekable */ if (glob_is_seekable) watch_pipeline (ptest); } else if (newstate == GST_STATE_PLAYING && pending == GST_STATE_VOID_PENDING && validate_checklist_item) { glob_validate_on_playing = NULL; insanity_test_validate_checklist_item (INSANITY_TEST (ptest), validate_checklist_item, TRUE, NULL); /* let it run a couple seconds */ glob_wait_time = hls_test_get_wait_time (INSANITY_TEST (ptest)); glob_timer_id = g_timeout_add (250, (GSourceFunc) & wait_and_end_step, INSANITY_TEST (ptest)); } } break; case GST_MESSAGE_EOS: return FALSE; default: break; } return TRUE; }
static gboolean gst_video_rate_query (GstPad * pad, GstQuery * query) { GstVideoRate *videorate; gboolean res = FALSE; videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; guint64 latency; GstPad *peer; if ((peer = gst_pad_get_peer (videorate->sinkpad))) { if ((res = gst_pad_query (peer, query))) { gst_query_parse_latency (query, &live, &min, &max); GST_DEBUG_OBJECT (videorate, "Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); if (videorate->from_rate_numerator != 0) { /* add latency. We don't really know since we hold on to the frames * until we get a next frame, which can be anything. We assume * however that this will take from_rate time. */ latency = gst_util_uint64_scale (GST_SECOND, videorate->from_rate_denominator, videorate->from_rate_numerator); } else { /* no input framerate, we don't know */ latency = 0; } GST_DEBUG_OBJECT (videorate, "Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); min += latency; if (max != -1) max += latency; GST_DEBUG_OBJECT (videorate, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } gst_object_unref (peer); } break; } default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (videorate); return res; }