Exemple #1
0
///////////////////////////////////////////////////////////////////////////////////////////////////
/// gst_element_get_first_sink_pad()
///
/// Get an element's first sink pad by using gst_element_iterate_sink_pads. The pad's ref count is
/// NOT incremented.
///////////////////////////////////////////////////////////////////////////////////////////////////
GstPad* gst_element_get_first_sink_pad(GstElement* element)
{
	GstIterator *iter = gst_element_iterate_sink_pads(element);
	GValue vPad = G_VALUE_INIT;
	GstPad* ret = NULL;
	if (gst_iterator_next(iter, &vPad) == GST_ITERATOR_OK)
	{
		ret = GST_PAD(g_value_get_object(&vPad));
	}
	gst_iterator_free(iter);
	return ret;
} // END gst_element_get_first_sink_pad()
Exemple #2
0
///////////////////////////////////////////////////////////////////////////////////////////////////
/// gst_element_count_sink_pads()
///
/// Count the element's sink pads by using gst_element_iterate_sink_pads.
///////////////////////////////////////////////////////////////////////////////////////////////////
gsize gst_element_count_sink_pads(GstElement* element)
{
	GstIterator *iter = gst_element_iterate_sink_pads(element);
	GValue vPad = G_VALUE_INIT;
	gsize ret = 0;
	while (gst_iterator_next(iter, &vPad) == GST_ITERATOR_OK)
	{
		ret++;
	}
	gst_iterator_free(iter);
	return ret;
} // END gst_element_count_sink_pads()
Exemple #3
0
gboolean
kms_element_for_each_sink_pad (GstElement * element,
    KmsPadCallback action, gpointer data)
{
  GstIterator *it = gst_element_iterate_sink_pads (element);
  gboolean ret;

  ret = kms_element_iterate_pads (it, action, data);
  gst_iterator_free (it);

  return ret;
}
static GstCaps *
gst_rtp_mux_getcaps (GstPad * pad, GstRTPMux * mux, GstCaps * filter)
{
  GstCaps *caps = NULL;
  GstIterator *iter = NULL;
  GValue v = { 0 };
  GstIteratorResult res;
  GstCaps *peercaps;
  GstCaps *othercaps;
  GstCaps *tcaps;

  peercaps = gst_pad_peer_query_caps (mux->srcpad, filter);

  if (peercaps) {
    tcaps = gst_pad_get_pad_template_caps (pad);
    othercaps = gst_caps_intersect_full (peercaps, tcaps,
        GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (peercaps);
  } else {
    tcaps = gst_pad_get_pad_template_caps (mux->srcpad);
    if (filter)
      othercaps = gst_caps_intersect_full (filter, tcaps,
          GST_CAPS_INTERSECT_FIRST);
    else
      othercaps = gst_caps_copy (tcaps);
  }
  gst_caps_unref (tcaps);

  clear_caps (othercaps, FALSE);

  g_value_init (&v, GST_TYPE_CAPS);

  iter = gst_element_iterate_sink_pads (GST_ELEMENT (mux));
  do {
    gst_value_set_caps (&v, othercaps);
    res = gst_iterator_fold (iter, same_clock_rate_fold, &v, pad);
    gst_iterator_resync (iter);
  } while (res == GST_ITERATOR_RESYNC);
  gst_iterator_free (iter);

  caps = (GstCaps *) gst_value_get_caps (&v);

  if (res == GST_ITERATOR_ERROR) {
    gst_caps_unref (caps);
    caps = gst_caps_new_empty ();
  }

  gst_caps_unref (othercaps);

  return caps;
}
static void
release_sink_pads (GstElement * audiomixer)
{
  GValue val = G_VALUE_INIT;
  GstIterator *it;
  gboolean done = FALSE;

  it = gst_element_iterate_sink_pads (audiomixer);
  do {
    switch (gst_iterator_next (it, &val)) {
      case GST_ITERATOR_OK:
      {
        GstPad *sinkpad, *srcpad;
        GstElement *agnosticbin;

        sinkpad = g_value_get_object (&val);
        srcpad = gst_pad_get_peer (sinkpad);
        agnosticbin = gst_pad_get_parent_element (srcpad);

        GST_DEBUG ("Unlink %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT,
            agnosticbin, audiomixer);

        if (!gst_pad_unlink (srcpad, sinkpad)) {
          GST_ERROR ("Can not unlink %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT,
              srcpad, sinkpad);
        }

        gst_element_release_request_pad (audiomixer, sinkpad);
        gst_element_release_request_pad (agnosticbin, srcpad);

        gst_object_unref (srcpad);
        gst_object_unref (agnosticbin);
        g_value_reset (&val);
        break;
      }
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (it);
        break;
      case GST_ITERATOR_ERROR:
        GST_ERROR ("Error iterating over %s's src pads",
            GST_ELEMENT_NAME (audiomixer));
      case GST_ITERATOR_DONE:
        g_value_unset (&val);
        done = TRUE;
        break;
    }
  } while (!done);

  gst_iterator_free (it);
}
/* forwards the event to all sinkpads, takes ownership of the
 * event
 *
 * Returns: TRUE if the event could be forwarded on all
 * sinkpads.
 */
static gboolean
forward_event (GstAdder * adder, GstEvent * event, gboolean flush)
{
  gboolean ret;
  GstIterator *it;
  GstIteratorResult ires;
  GValue vret = { 0 };
  EventData data;

  GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
      GST_EVENT_TYPE_NAME (event));

  data.event = event;
  data.flush = flush;

  g_value_init (&vret, G_TYPE_BOOLEAN);
  g_value_set_boolean (&vret, FALSE);
  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
  while (TRUE) {
    ires =
        gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
        &vret, &data);
    switch (ires) {
      case GST_ITERATOR_RESYNC:
        GST_WARNING ("resync");
        gst_iterator_resync (it);
        g_value_set_boolean (&vret, TRUE);
        break;
      case GST_ITERATOR_OK:
      case GST_ITERATOR_DONE:
        ret = g_value_get_boolean (&vret);
        goto done;
      default:
        ret = FALSE;
        goto done;
    }
  }
done:
  gst_iterator_free (it);
  GST_LOG_OBJECT (adder, "Forwarded event %p (%s), ret=%d", event,
      GST_EVENT_TYPE_NAME (event), ret);
  gst_event_unref (event);

  return ret;
}
static gboolean
forward_event (GstInterleave * self, GstEvent * event)
{
  GstIterator *it;
  GValue vret = { 0 };

  GST_LOG_OBJECT (self, "Forwarding event %p (%s)", event,
      GST_EVENT_TYPE_NAME (event));

  g_value_init (&vret, G_TYPE_BOOLEAN);
  g_value_set_boolean (&vret, TRUE);
  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
  gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
      event);
  gst_iterator_free (it);
  gst_event_unref (event);

  return g_value_get_boolean (&vret);
}
Exemple #8
0
///////////////////////////////////////////////////////////////////////////////////////////////////
/// gst_element_find_sink_pad_by_name()
///
/// Find an element's sink pad by name by using gst_element_iterate_sink_pads and comparing the
/// element's name with that provided.
///////////////////////////////////////////////////////////////////////////////////////////////////
GstPad* gst_element_find_sink_pad_by_name(GstElement* element, const gchar* name)
{
	GstIterator *iter = gst_element_iterate_sink_pads(element);
	GValue vPad = G_VALUE_INIT;
	GstPad* ret = NULL;
	while (gst_iterator_next(iter, &vPad) == GST_ITERATOR_OK)
	{
		GstPad* pad = GST_PAD(g_value_get_object(&vPad));
		const gchar* pad_name = gst_pad_get_name(pad);
		if (g_strcmp0(pad_name, name) == 0)
		{
			ret = pad;
		}
		g_free(const_cast<gchar*>(pad_name));
		if (ret != NULL)
		{
			break;
		}
	}
	gst_iterator_free(iter);
	return ret;
} // END gst_element_find_sink_pad_by_name()
Exemple #9
0
static gboolean
fs_funnel_src_event (GstPad * pad, GstEvent * event)
{
  GstElement *funnel;
  GstIterator *iter;
  GstPad *sinkpad;
  gboolean result = FALSE;
  gboolean done = FALSE;

  funnel = gst_pad_get_parent_element (pad);
  g_return_val_if_fail (funnel != NULL, FALSE);

  iter = gst_element_iterate_sink_pads (funnel);

  while (!done) {
    switch (gst_iterator_next (iter, (gpointer) &sinkpad)) {
      case GST_ITERATOR_OK:
        gst_event_ref (event);
        result |= gst_pad_push_event (sinkpad, event);
        gst_object_unref (sinkpad);
        break;
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (iter);
        result = FALSE;
        break;
      case GST_ITERATOR_ERROR:
        GST_WARNING_OBJECT (funnel, "Error iterating sinkpads");
      case GST_ITERATOR_DONE:
        done = TRUE;
        break;
    }
  }
  gst_iterator_free (iter);
  gst_object_unref (funnel);
  gst_event_unref (event);

  return result;
}
static gboolean
_gst_context_run_query (GstElement * element, GstQuery * query,
    GstPadDirection direction)
{
  GstIteratorFoldFunction const func = context_pad_query;
  GstIterator *it;
  GValue res = { 0 };

  g_value_init (&res, G_TYPE_BOOLEAN);
  g_value_set_boolean (&res, FALSE);

  /* Ask neighbour */
  if (direction == GST_PAD_SRC)
    it = gst_element_iterate_src_pads (element);
  else
    it = gst_element_iterate_sink_pads (element);

  while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
    gst_iterator_resync (it);
  gst_iterator_free (it);

  return g_value_get_boolean (&res);
}
Exemple #11
0
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 void
suboverlay_child_added_cb (GstElement * suboverlay, GstElement * child,
    InsanityTest * test)
{
  GstIterator *it = NULL;
  GstPad *render_sub_sink, *tmppad;
  GstElementFactory *fact;
  const gchar *klass, *name;
  gulong probe_id;
  GValue value = { 0, };

  gboolean is_renderer = FALSE;


  /* cc-ed from -base/gstsubtitleoveraly.c */
  fact = gst_element_get_factory (child);
  klass = gst_element_factory_get_metadata (fact, GST_ELEMENT_METADATA_KLASS);

  if (GST_IS_BIN (child))
    return;

  name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST (fact));

  if (g_strrstr (klass, "Overlay/Subtitle") != NULL ||
      g_strrstr (klass, "Overlay/SubPicture") != NULL)
    is_renderer = TRUE;

  else if (g_strcmp0 (name, "textoverlay") == 0)
    is_renderer = TRUE;

  if (is_renderer == FALSE)
    goto done;

  LOG (test, "Renderer found: %s", name);

  /* Now adding the probe to the renderer "subtitle" sink pad */
  it = gst_element_iterate_sink_pads (child);
  if (gst_iterator_find_custom (it,
          (GCompareFunc) find_renderer_subtitle_sinkpad, &value, NULL)) {
    render_sub_sink = g_value_get_object (&value);
  } else {
    goto done;
  }

  if (insanity_gst_test_add_data_probe (INSANITY_GST_TEST (test),
          GST_BIN (glob_pipeline), GST_OBJECT_NAME (child),
          GST_ELEMENT_NAME (render_sub_sink), &tmppad, &probe_id,
          &renderer_probe_cb, NULL, NULL) == TRUE) {

    glob_renderer_sink_probe = g_slice_new0 (ProbeContext);
    glob_renderer_sink_probe->probe_id = probe_id;
    glob_renderer_sink_probe->pad = render_sub_sink;
    glob_renderer_sink_probe->element = child;
    glob_renderer_sink_probe->test = test;
    glob_renderer_sink_probe->waiting_first_segment = TRUE;

    insanity_test_validate_checklist_item (test, "install-probes", TRUE, NULL);
  } else {
    insanity_test_validate_checklist_item (test, "install-probes", FALSE,
        "Failed to attach probe to fakesink");
    insanity_test_done (test);

    goto done;
  }

done:
  if (it)
    gst_iterator_free (it);

}
Exemple #13
0
/* FIXME, the duration query should reflect how long you will produce
 * data, that is the amount of stream time until you will emit EOS.
 *
 * For synchronized mixing this is always the max of all the durations
 * of upstream since we emit EOS when all of them finished.
 *
 * We don't do synchronized mixing so this really depends on where the
 * streams where punched in and what their relative offsets are against
 * eachother which we can get from the first timestamps we see.
 *
 * When we add a new stream (or remove a stream) the duration might
 * also become invalid again and we need to post a new DURATION
 * message to notify this fact to the parent.
 * For now we take the max of all the upstream elements so the simple
 * cases work at least somewhat.
 */
static gboolean
gst_adder_query_duration (GstAdder * adder, GstQuery * query)
{
  gint64 max;
  gboolean res;
  GstFormat format;
  GstIterator *it;
  gboolean done;

  /* parse format */
  gst_query_parse_duration (query, &format, NULL);

  max = -1;
  res = TRUE;
  done = FALSE;

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

        gint64 duration;

        /* ask sink peer for duration */
        res &= gst_pad_query_peer_duration (pad, &format, &duration);
        /* take max from all valid return values */
        if (res) {
          /* valid unknown length, stop searching */
          if (duration == -1) {
            max = duration;
            done = TRUE;
          }
          /* else see if bigger than current max */
          else if (duration > max)
            max = duration;
        }
        gst_object_unref (pad);
        break;
      }
      case GST_ITERATOR_RESYNC:
        max = -1;
        res = TRUE;
        gst_iterator_resync (it);
        break;
      default:
        res = FALSE;
        done = TRUE;
        break;
    }
  }
  gst_iterator_free (it);

  if (res) {
    /* and store the max */
    GST_DEBUG_OBJECT (adder, "Total duration in format %s: %"
        GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
    gst_query_set_duration (query, format, max);
  }

  return res;
}
/**
 * gst_aggregator_iterate_sinkpads:
 * @self: The #GstAggregator
 * @func: The function to call.
 * @user_data: The data to pass to @func.
 *
 * Iterate the sinkpads of aggregator to call a function on them.
 *
 * This method guarantees that @func will be called only once for each
 * sink pad.
 */
gboolean
gst_aggregator_iterate_sinkpads (GstAggregator * self,
    GstAggregatorPadForeachFunc func, gpointer user_data)
{
  gboolean result = FALSE;
  GstIterator *iter;
  gboolean done = FALSE;
  GValue item = { 0, };
  GList *seen_pads = NULL;

  iter = gst_element_iterate_sink_pads (GST_ELEMENT (self));

  if (!iter)
    goto no_iter;

  while (!done) {
    switch (gst_iterator_next (iter, &item)) {
      case GST_ITERATOR_OK:
      {
        GstPad *pad;

        pad = g_value_get_object (&item);

        /* if already pushed, skip. FIXME, find something faster to tag pads */
        if (pad == NULL || g_list_find (seen_pads, pad)) {
          g_value_reset (&item);
          break;
        }

        GST_LOG_OBJECT (self, "calling function on pad %s:%s",
            GST_DEBUG_PAD_NAME (pad));
        result = func (self, pad, user_data);

        done = !result;

        seen_pads = g_list_prepend (seen_pads, pad);

        g_value_reset (&item);
        break;
      }
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (iter);
        break;
      case GST_ITERATOR_ERROR:
        GST_ERROR_OBJECT (self,
            "Could not iterate over internally linked pads");
        done = TRUE;
        break;
      case GST_ITERATOR_DONE:
        done = TRUE;
        break;
    }
  }
  g_value_unset (&item);
  gst_iterator_free (iter);

  if (seen_pads == NULL) {
    GST_DEBUG_OBJECT (self, "No pad seen");
    return FALSE;
  }

  g_list_free (seen_pads);

no_iter:
  return result;
}
Exemple #15
0
static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_TYPE *amt, GstCaps *capsin, GstCaps *capsout)
{
    GstIterator *it;
    BOOL done = FALSE, found = FALSE;
    int ret;

    TRACE("%p %p %p %p\n", This, amt, capsin, capsout);

    mark_wine_thread();

    This->filter = gst_element_factory_make(This->gstreamer_name, NULL);
    if (!This->filter) {
        FIXME("Could not make %s filter\n", This->gstreamer_name);
        return E_FAIL;
    }
    This->my_src = gst_pad_new("yuvsrc", GST_PAD_SRC);
    gst_pad_set_element_private (This->my_src, This);
    gst_pad_set_active(This->my_src, 1);

    This->my_sink = gst_pad_new("yuvsink", GST_PAD_SINK);
    gst_pad_set_chain_function(This->my_sink, got_data_wrapper);
    gst_pad_set_element_private (This->my_sink, This);
    gst_pad_set_active(This->my_sink, 1);

    it = gst_element_iterate_sink_pads(This->filter);
    while (!done) {
        GValue item = {0};

        switch (gst_iterator_next(it, &item)) {
        case GST_ITERATOR_RESYNC:
            gst_iterator_resync (it);
            break;
        case GST_ITERATOR_OK:
            This->their_sink = g_value_get_object(&item);
            gst_object_ref(This->their_sink);
            g_value_reset(&item);
        case GST_ITERATOR_ERROR:
        case GST_ITERATOR_DONE:
            done = TRUE;
            break;
        }
    }
    gst_iterator_free(it);
    if (!This->their_sink) {
        ERR("Could not find sink on filter %s\n", This->gstreamer_name);
        return E_FAIL;
    }

    it = gst_element_iterate_src_pads(This->filter);
    gst_iterator_resync(it);
    done = FALSE;
    while (!done) {
        GValue item = {0};

        switch (gst_iterator_next(it, &item)) {
        case GST_ITERATOR_RESYNC:
            gst_iterator_resync (it);
            break;
        case GST_ITERATOR_OK:
            This->their_src = g_value_get_object(&item);
            gst_object_ref(This->their_src);
            g_value_reset(&item);
        case GST_ITERATOR_ERROR:
        case GST_ITERATOR_DONE:
            done = TRUE;
            break;
        }
    }
    gst_iterator_free(it);
    found = !!This->their_src;
    if (!found)
        g_signal_connect(This->filter, "pad-added", G_CALLBACK(Gstreamer_transform_pad_added_wrapper), This);
    ret = gst_pad_link(This->my_src, This->their_sink);
    if (ret < 0) {
        WARN("Failed to link with %i\n", ret);
        return E_FAIL;
    }

    ret = gst_pad_set_caps(This->my_src, capsin);
    if (ret < 0) {
        WARN("Failed to set caps on own source with %i\n", ret);
        return E_FAIL;
    }

    if (found)
        Gstreamer_transform_pad_added(This->filter, This->their_src, This);

    if (!gst_pad_is_linked(This->my_sink))
        return E_FAIL;

    ret = gst_pad_set_caps(This->my_sink, capsout);
    if (ret < 0) {
        WARN("Failed to set caps on own sink with %i\n", ret);
        return E_FAIL;
    }

    TRACE("Connected\n");
    return S_OK;
}
static gboolean
validate_codec_profile (FsCodec *codec,const gchar *bin_description,
    gboolean is_send)
{
  GError *error = NULL;
  GstElement *bin = NULL;
  guint src_pad_count = 0, sink_pad_count = 0;
  GstCaps *caps;
  gpointer matching_pad = NULL;
  GstIterator *iter;

  bin = parse_bin_from_description_all_linked (bin_description,
      &src_pad_count, &sink_pad_count, &error);

  /* if could not build bin, fail */
  if (!bin)
  {
    GST_WARNING ("Could not build profile (%s): %s", bin_description,
        error->message);
    g_clear_error (&error);
    return FALSE;
  }
  g_clear_error (&error);

  caps = fs_codec_to_gst_caps (codec);

  if (is_send)
    iter = gst_element_iterate_src_pads (bin);
  else
    iter = gst_element_iterate_sink_pads (bin);

  matching_pad = gst_iterator_find_custom (iter, find_matching_pad, caps);
  gst_iterator_free (iter);

  if (!matching_pad)
  {
    GST_WARNING ("Invalid profile (%s), has no %s pad that matches the codec"
        " details", is_send ? "src" : "sink", bin_description);
    gst_caps_unref (caps);
    gst_object_unref (bin);
    return FALSE;
  }

  gst_caps_unref (caps);
  gst_object_unref (bin);

  if (is_send)
  {
    if (src_pad_count == 0)
    {
      GST_WARNING ("Invalid profile (%s), has 0 src pad", bin_description);
      return FALSE;
    }
  }
  else
  {
    if (src_pad_count != 1)
    {
      GST_WARNING ("Invalid profile (%s), has %u src pads, should have one",
          bin_description, src_pad_count);
      return FALSE;
    }
  }

  if (sink_pad_count != 1)
  {
    GST_WARNING ("Invalid profile (%s), has %u sink pads, should have one",
        bin_description, sink_pad_count);
    return FALSE;
  }

  return TRUE;
}
Exemple #17
0
static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_TYPE *amt, GstCaps *capsin, GstCaps *capsout) {
    GstIterator *it;
    int done = 0, found = 0, ret;

    This->filter = gst_element_factory_make(This->gstreamer_name, NULL);
    if (!This->filter) {
        FIXME("Could not make %s filter\n", This->gstreamer_name);
        return E_FAIL;
    }
    This->my_src = gst_pad_new(NULL, GST_PAD_SRC);
    gst_pad_set_element_private (This->my_src, This);

    This->my_sink = gst_pad_new(NULL, GST_PAD_SINK);
    gst_pad_set_chain_function(This->my_sink, got_data);
    gst_pad_set_bufferalloc_function(This->my_sink, request_buffer);
    gst_pad_set_element_private (This->my_sink, This);

    ret = gst_pad_set_caps(This->my_src, capsin);
    if (ret < 0) {
        WARN("Failed to set caps on own source with %i\n", ret);
        return E_FAIL;
    }

    ret = gst_pad_set_caps(This->my_sink, capsout);
    if (ret < 0) {
        WARN("Failed to set caps on own sink with %i\n", ret);
        return E_FAIL;
    }

    it = gst_element_iterate_sink_pads(This->filter);
    while (!done) {
        gpointer item;

        switch (gst_iterator_next(it, &item)) {
        case GST_ITERATOR_RESYNC:
            gst_iterator_resync (it);
            break;
        case GST_ITERATOR_OK:
            This->their_sink = item;
        case GST_ITERATOR_ERROR:
        case GST_ITERATOR_DONE:
            done = 1;
            break;
        }
    }
    gst_iterator_free(it);
    if (!This->their_sink) {
        ERR("Could not find sink on filter %s\n", This->gstreamer_name);
        return E_FAIL;
    }

    it = gst_element_iterate_src_pads(This->filter);
    gst_iterator_resync(it);
    done = 0;
    while (!done) {
        gpointer item;

        switch (gst_iterator_next(it, &item)) {
        case GST_ITERATOR_RESYNC:
            gst_iterator_resync (it);
            break;
        case GST_ITERATOR_OK:
            This->their_src = item;
        case GST_ITERATOR_ERROR:
        case GST_ITERATOR_DONE:
            done = 1;
            break;
        }
    }
    gst_iterator_free(it);
    found = !!This->their_src;
    if (!found)
        g_signal_connect(This->filter, "pad-added", G_CALLBACK(Gstreamer_transform_pad_added), This);
    ret = gst_pad_link(This->my_src, This->their_sink);
    if (ret < 0) {
        WARN("Failed to link with %i\n", ret);
        return E_FAIL;
    }

    if (found)
        Gstreamer_transform_pad_added(This->filter, This->their_src, This);

    if (!gst_pad_is_linked(This->my_sink))
        return E_FAIL;

    TRACE("Connected\n");
    return S_OK;
}
static gboolean
gst_live_adder_query_pos_dur (GstLiveAdder * adder, GstFormat informat,
                              gboolean position, gint64 * outvalue)
{
    gint64 max = G_MININT64;
    gboolean res = TRUE;
    GstIterator *it;
    gboolean done = FALSE;


    it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
    while (!done) {
        GstIteratorResult ires;
        gpointer item;
        GstFormat format = informat;

        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);
            gint64 value;
            gboolean curres;

            /* ask sink peer for duration */
            if (position)
                curres = gst_pad_query_peer_position (pad, &format, &value);
            else
                curres = gst_pad_query_peer_duration (pad, &format, &value);

            /* take max from all valid return values */
            /* Only if the format is the one we requested, otherwise ignore it ?
             */

            if (curres && format == informat) {
                res &= curres;

                /* valid unknown length, stop searching */
                if (value == -1) {
                    max = value;
                    done = TRUE;
                } else if (value > max) {
                    max = value;
                }
            }
            break;
        }
        case GST_ITERATOR_RESYNC:
            max = -1;
            res = TRUE;
            break;
        default:
            res = FALSE;
            done = TRUE;
            break;
        }
    }
    gst_iterator_free (it);

    if (res)
        *outvalue = max;

    return res;
}
static gboolean
gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
{
  gint64 max;
  gboolean res;
  GstFormat format;
  GstIterator *it;
  gboolean done;

  /* parse format */
  gst_query_parse_duration (query, &format, NULL);

  max = -1;
  res = TRUE;
  done = FALSE;

  /* Take maximum of all durations */
  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
  while (!done) {
    GstIteratorResult ires;

    GValue item = { 0, };

    ires = gst_iterator_next (it, &item);
    switch (ires) {
      case GST_ITERATOR_DONE:
        done = TRUE;
        break;
      case GST_ITERATOR_OK:
      {
        GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item));

        gint64 duration;

        /* ask sink peer for duration */
        res &= gst_pad_peer_query_duration (pad, format, &duration);
        /* take max from all valid return values */
        if (res) {
          /* valid unknown length, stop searching */
          if (duration == -1) {
            max = duration;
            done = TRUE;
          }
          /* else see if bigger than current max */
          else if (duration > max)
            max = duration;
        }
        gst_object_unref (pad);
        g_value_unset (&item);
        break;
      }
      case GST_ITERATOR_RESYNC:
        max = -1;
        res = TRUE;
        gst_iterator_resync (it);
        break;
      default:
        res = FALSE;
        done = TRUE;
        break;
    }
  }
  gst_iterator_free (it);

  if (res) {
    /* If in bytes format we have to multiply with the number of channels
     * to get the correct results. All other formats should be fine */
    if (format == GST_FORMAT_BYTES && max != -1)
      max *= self->channels;

    /* and store the max */
    GST_DEBUG_OBJECT (self, "Total duration in format %s: %"
        GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
    gst_query_set_duration (query, format, max);
  }

  return res;
}
/*
 * debug_dump_element:
 * @bin: the bin that should be analyzed
 * @out: file to write to
 * @indent: level of graph indentation
 *
 * Helper for gst_debug_bin_to_dot_file() to recursively dump a pipeline.
 */
static void
debug_dump_element (GstBin * bin, GstDebugGraphDetails details,
    GString * str, const gint indent)
{
  GstIterator *element_iter, *pad_iter;
  gboolean elements_done, pads_done;
  GValue item = { 0, };
  GValue item2 = { 0, };
  GstElement *element;
  GstPad *pad = NULL;
  guint src_pads, sink_pads;
  gchar *element_name;
  gchar *state_name = NULL;
  gchar *param_name = NULL;
  const gchar *spc = &spaces[MAX (sizeof (spaces) - (1 + indent * 2), 0)];

  element_iter = gst_bin_iterate_elements (bin);
  elements_done = FALSE;
  while (!elements_done) {
    switch (gst_iterator_next (element_iter, &item)) {
      case GST_ITERATOR_OK:
        element = g_value_get_object (&item);
        element_name = debug_dump_make_object_name (GST_OBJECT (element));

        if (details & GST_DEBUG_GRAPH_SHOW_STATES) {
          state_name = debug_dump_get_element_state (GST_ELEMENT (element));
        }
        if (details & GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS) {
          param_name = debug_dump_get_element_params (GST_ELEMENT (element),
              details);
        }
        /* elements */
        g_string_append_printf (str, "%ssubgraph cluster_%s {\n", spc,
            element_name);
        g_string_append_printf (str, "%s  fontname=\"Bitstream Vera Sans\";\n",
            spc);
        g_string_append_printf (str, "%s  fontsize=\"8\";\n", spc);
        g_string_append_printf (str, "%s  style=filled;\n", spc);
        g_string_append_printf (str, "%s  color=black;\n\n", spc);
        g_string_append_printf (str, "%s  label=\"%s\\n%s%s%s\";\n", spc,
            G_OBJECT_TYPE_NAME (element), GST_OBJECT_NAME (element),
            (state_name ? state_name : ""), (param_name ? param_name : "")
            );
        if (state_name) {
          g_free (state_name);
          state_name = NULL;
        }
        if (param_name) {
          g_free (param_name);
          param_name = NULL;
        }
        g_free (element_name);

        src_pads = sink_pads = 0;
        if ((pad_iter = gst_element_iterate_sink_pads (element))) {
          debug_dump_element_pads (pad_iter, pad, element, details, str,
              indent, &src_pads, &sink_pads);
          gst_iterator_free (pad_iter);
        }
        if ((pad_iter = gst_element_iterate_src_pads (element))) {
          debug_dump_element_pads (pad_iter, pad, element, details, str,
              indent, &src_pads, &sink_pads);
          gst_iterator_free (pad_iter);
        }
        if (GST_IS_BIN (element)) {
          g_string_append_printf (str, "%s  fillcolor=\"#ffffff\";\n", spc);
          /* recurse */
          debug_dump_element (GST_BIN (element), details, str, indent + 1);
        } else {
          if (src_pads && !sink_pads)
            g_string_append_printf (str, "%s  fillcolor=\"#ffaaaa\";\n", spc);
          else if (!src_pads && sink_pads)
            g_string_append_printf (str, "%s  fillcolor=\"#aaaaff\";\n", spc);
          else if (src_pads && sink_pads)
            g_string_append_printf (str, "%s  fillcolor=\"#aaffaa\";\n", spc);
          else
            g_string_append_printf (str, "%s  fillcolor=\"#ffffff\";\n", spc);
        }
        g_string_append_printf (str, "%s}\n\n", spc);
        if ((pad_iter = gst_element_iterate_pads (element))) {
          pads_done = FALSE;
          while (!pads_done) {
            switch (gst_iterator_next (pad_iter, &item2)) {
              case GST_ITERATOR_OK:
                pad = g_value_get_object (&item2);
                if (gst_pad_is_linked (pad)) {
                  if (gst_pad_get_direction (pad) == GST_PAD_SRC) {
                    debug_dump_element_pad_link (pad, element, details, str,
                        indent);
                  } else {
                    GstPad *peer_pad = gst_pad_get_peer (pad);

                    if (peer_pad) {
                      if (!GST_IS_GHOST_PAD (peer_pad)
                          && GST_IS_PROXY_PAD (peer_pad)) {
                        debug_dump_element_pad_link (peer_pad, NULL, details,
                            str, indent);
                      }
                      gst_object_unref (peer_pad);
                    }
                  }
                }
                g_value_reset (&item2);
                break;
              case GST_ITERATOR_RESYNC:
                gst_iterator_resync (pad_iter);
                break;
              case GST_ITERATOR_ERROR:
              case GST_ITERATOR_DONE:
                pads_done = TRUE;
                break;
            }
          }
          g_value_unset (&item2);
          gst_iterator_free (pad_iter);
        }
        g_value_reset (&item);
        break;
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (element_iter);
        break;
      case GST_ITERATOR_ERROR:
      case GST_ITERATOR_DONE:
        elements_done = TRUE;
        break;
    }
  }

  g_value_unset (&item);
  gst_iterator_free (element_iter);
}
static gboolean
gst_frei0r_mixer_src_query_duration (GstFrei0rMixer * self, GstQuery * query)
{
  gint64 min;
  gboolean res;
  GstFormat format;
  GstIterator *it;
  gboolean done;

  /* parse format */
  gst_query_parse_duration (query, &format, NULL);

  min = -1;
  res = TRUE;
  done = FALSE;

  /* Take minimum of all durations */
  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
  while (!done) {
    GstIteratorResult ires;
    GValue item = { 0 };

    ires = gst_iterator_next (it, &item);
    switch (ires) {
      case GST_ITERATOR_DONE:
        done = TRUE;
        break;
      case GST_ITERATOR_OK:
      {
        GstPad *pad = g_value_get_object (&item);
        gint64 duration;

        /* ask sink peer for duration */
        res &= gst_pad_peer_query_duration (pad, format, &duration);
        /* take min from all valid return values */
        if (res) {
          /* valid unknown length, stop searching */
          if (duration == -1) {
            min = duration;
            done = TRUE;
          }
          /* else see if smaller than current min */
          else if (duration < min)
            min = duration;
        }
        g_value_reset (&item);
        break;
      }
      case GST_ITERATOR_RESYNC:
        min = -1;
        res = TRUE;
        gst_iterator_resync (it);
        break;
      default:
        res = FALSE;
        done = TRUE;
        break;
    }

    g_value_unset (&item);
  }
  gst_iterator_free (it);

  if (res) {
    /* and store the min */
    GST_DEBUG_OBJECT (self, "Total duration in format %s: %"
        GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (min));
    gst_query_set_duration (query, format, min);
  }

  return res;
}
/* Fetches a compatible pad on the target element which isn't already
 * linked */
static GstPad *
get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
{
  GstPad *res = NULL;
  GstIterator *pads;
  gboolean done = FALSE;
  GstCaps *srccaps;

  if (G_UNLIKELY (pad == NULL))
    goto no_pad;

  GST_DEBUG ("element : %s, pad %s:%s",
      GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));

  if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
    pads = gst_element_iterate_sink_pads (element);
  else
    pads = gst_element_iterate_src_pads (element);
  srccaps = gst_pad_get_caps_reffed (pad);

  GST_DEBUG ("srccaps %" GST_PTR_FORMAT, srccaps);

  while (!done) {
    gpointer padptr;

    switch (gst_iterator_next (pads, &padptr)) {
      case GST_ITERATOR_OK:
      {
        GstPad *testpad = (GstPad *) padptr;

        if (gst_pad_is_linked (testpad)) {
          gst_object_unref (testpad);
        } else {
          GstCaps *sinkcaps = gst_pad_get_caps_reffed (testpad);

          GST_DEBUG ("sinkccaps %" GST_PTR_FORMAT, sinkcaps);

          if (gst_caps_can_intersect (srccaps, sinkcaps)) {
            res = testpad;
            done = TRUE;
          } else
            gst_object_unref (testpad);
          gst_caps_unref (sinkcaps);
        }
      }
        break;
      case GST_ITERATOR_DONE:
      case GST_ITERATOR_ERROR:
        done = TRUE;
        break;
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (pads);
        break;
    }
  }
  gst_iterator_free (pads);
  gst_caps_unref (srccaps);

  return res;

no_pad:
  {
    GST_ERROR ("No pad to check against");
    return NULL;
  }
}
Exemple #23
0
static gboolean
mpegtsmux_src_event (GstPad * pad, GstEvent * event)
{
  MpegTsMux *mux = GST_MPEG_TSMUX (gst_pad_get_parent (pad));
  gboolean res = TRUE;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CUSTOM_UPSTREAM:
    {
      GstIterator *iter;
      GstIteratorResult iter_ret;
      GstPad *sinkpad;
      GstClockTime running_time;
      gboolean all_headers, done;
      guint count;

      if (!gst_video_event_is_force_key_unit (event))
        break;

      gst_video_event_parse_upstream_force_key_unit (event,
          &running_time, &all_headers, &count);

      GST_INFO_OBJECT (mux, "received upstream force-key-unit event, "
          "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
          gst_event_get_seqnum (event), GST_TIME_ARGS (running_time),
          all_headers, count);

      if (!all_headers)
        break;

      mux->pending_key_unit_ts = running_time;
      gst_event_replace (&mux->force_key_unit_event, event);

      iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux));
      done = FALSE;
      while (!done) {
        gboolean res = FALSE, tmp;
        iter_ret = gst_iterator_next (iter, (gpointer *) & sinkpad);

        switch (iter_ret) {
          case GST_ITERATOR_DONE:
            done = TRUE;
            break;
          case GST_ITERATOR_OK:
            GST_INFO_OBJECT (mux, "forwarding to %s",
                gst_pad_get_name (sinkpad));
            tmp = gst_pad_push_event (sinkpad, gst_event_ref (event));
            GST_INFO_OBJECT (mux, "result %d", tmp);
            /* succeed if at least one pad succeeds */
            res |= tmp;
            gst_object_unref (sinkpad);
            break;
          case GST_ITERATOR_ERROR:
            done = TRUE;
            break;
          case GST_ITERATOR_RESYNC:
            break;
        }
      }

      gst_event_unref (event);
      break;
    }
    default:
      res = gst_pad_event_default (pad, event);
      break;
  }

  gst_object_unref (mux);
  return res;
}
Exemple #24
0
static HRESULT WINAPI Gstreamer_YUV_SetMediaType(TransformFilter *tf, PIN_DIRECTION dir,  const AM_MEDIA_TYPE *amt) {
    GstTfImpl *This = (GstTfImpl*)tf;
    GstCaps *capsin, *capsout;
    AM_MEDIA_TYPE *outpmt = &This->tf.pmt;
    HRESULT hr;
    int avgtime;
    LONG width, height;

    if (dir != PINDIR_INPUT)
        return S_OK;

    if (Gstreamer_YUV_QueryConnect(&This->tf, amt) == S_FALSE || !amt->pbFormat)
        return E_FAIL;

    FreeMediaType(outpmt);
    CopyMediaType(outpmt, amt);

    if (IsEqualGUID(&amt->formattype, &FORMAT_VideoInfo)) {
        VIDEOINFOHEADER *vih = (VIDEOINFOHEADER*)outpmt->pbFormat;
        avgtime = vih->AvgTimePerFrame;
        width = vih->bmiHeader.biWidth;
        height = vih->bmiHeader.biHeight;
        if (vih->bmiHeader.biHeight > 0)
            vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight;
        vih->bmiHeader.biBitCount = 24;
        vih->bmiHeader.biCompression = BI_RGB;
        vih->bmiHeader.biSizeImage = width * abs(height) * 3;
    } else {
        VIDEOINFOHEADER2 *vih = (VIDEOINFOHEADER2*)outpmt->pbFormat;
        avgtime = vih->AvgTimePerFrame;
        width = vih->bmiHeader.biWidth;
        height = vih->bmiHeader.biHeight;
        if (vih->bmiHeader.biHeight > 0)
            vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight;
        vih->bmiHeader.biBitCount = 24;
        vih->bmiHeader.biCompression = BI_RGB;
        vih->bmiHeader.biSizeImage = width * abs(height) * 3;
    }
    if (!avgtime)
        avgtime = 10000000 / 30;

    outpmt->subtype = MEDIASUBTYPE_RGB24;

    capsin = gst_caps_new_simple("video/x-raw-yuv",
                                 "format", GST_TYPE_FOURCC, amt->subtype.Data1,
                                 "width", G_TYPE_INT, width,
                                 "height", G_TYPE_INT, height,
                                 "framerate", GST_TYPE_FRACTION, 10000000, (int)avgtime,
                                 NULL);
    capsout = gst_caps_new_simple("video/x-raw-rgb",
                                  "bpp", G_TYPE_INT, 24,
                                  "depth", G_TYPE_INT, 24,
                                  "endianness", G_TYPE_INT, 4321,
                                  "red_mask", G_TYPE_INT, 0xff,
                                  "green_mask", G_TYPE_INT, 0xff00,
                                  "blue_mask", G_TYPE_INT, 0xff0000,
                                  "width", G_TYPE_INT, width,
                                  "height", G_TYPE_INT, height,
                                  "framerate", GST_TYPE_FRACTION, 10000000, (int)avgtime,
                                   NULL);

    This->filter2 = gst_element_factory_make("videoflip", NULL);
    if (This->filter2) {
        GstIterator *it;
        int done = 0;

        g_object_set(This->filter2, "method", 5, NULL);

        it = gst_element_iterate_sink_pads(This->filter2);
        while (!done) {
            gpointer item;

            switch (gst_iterator_next(it, &item)) {
            case GST_ITERATOR_RESYNC:
                gst_iterator_resync (it);
                break;
            case GST_ITERATOR_OK:
                This->their_sink2 = item;
            case GST_ITERATOR_ERROR:
            case GST_ITERATOR_DONE:
                done = 1;
                break;
            }
        }
        gst_iterator_free(it);

        done = 0;
        it = gst_element_iterate_src_pads(This->filter2);
        while (!done) {
            gpointer item;

            switch (gst_iterator_next(it, &item)) {
            case GST_ITERATOR_RESYNC:
                gst_iterator_resync (it);
                break;
            case GST_ITERATOR_OK:
                This->their_src2 = item;
            case GST_ITERATOR_ERROR:
            case GST_ITERATOR_DONE:
                done = 1;
                break;
            }
        }
        gst_iterator_free(it);

        if (!This->their_src2 || !This->their_sink2) {
            if (This->their_src2)
                gst_object_unref(This->their_src2);
            if (This->their_sink2)
                gst_object_unref(This->their_sink2);
            gst_object_unref(This->filter2);
            This->filter2 = 0;
        }
    }

    hr = Gstreamer_transform_ConnectInput(This, amt, capsin, capsout);
    gst_caps_unref(capsin);
    gst_caps_unref(capsout);

    This->cbBuffer = width * height * 4;
    return hr;
}
Exemple #25
0
/**
 * gst_composite_adjust_pip:
 *  @param composite The GstComposite instance
 *  @param x the X position of the PIP
 *  @param y the Y position of the PIP
 *  @param w the width of the PIP
 *  @param h the height of the PIP
 *  @return PIP has been changed succefully 
 *
 *  Change the PIP position and size.
 */
gboolean
gst_composite_adjust_pip (GstComposite * composite, gint x, gint y,
    gint w, gint h)
{
  gboolean result = FALSE;
  GstIterator *iter = NULL;
  GValue value = { 0 };
  GstElement *element = NULL;
  gboolean done = FALSE;

  g_return_val_if_fail (GST_IS_COMPOSITE (composite), FALSE);

  GST_COMPOSITE_LOCK (composite);
  if (composite->adjusting) {
    WARN ("last PIP adjustment request is progressing");
    goto end;
  }

  composite->b_x = x;
  composite->b_y = y;

  if (composite->b_width != w || composite->b_height != h) {
    composite->b_width = w;
    composite->b_height = h;
    composite->adjusting = TRUE;
    gst_worker_stop (GST_WORKER (composite));
    result = TRUE;
    goto end;
  }

  element = gst_worker_get_element (GST_WORKER (composite), "mix");
  iter = gst_element_iterate_sink_pads (element);
  while (iter && !done) {
    switch (gst_iterator_next (iter, &value)) {
      case GST_ITERATOR_OK:
      {
        GstPad *pad = g_value_get_object (&value);
        if (g_strcmp0 (gst_pad_get_name (pad), "sink_1") == 0) {
          g_object_set (pad, "xpos", composite->b_x,
              "ypos", composite->b_y, NULL);
          done = TRUE;
          result = TRUE;
        }
        g_value_reset (&value);
      }
        break;
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (iter);
        break;
      case GST_ITERATOR_DONE:
        done = TRUE;
        break;
      default:
        /* iterator returned _ERROR or premature end with _OK,
         * mark an error and exit */
        done = TRUE;
        result = FALSE;
        break;
    }
  }

  if (G_IS_VALUE (&value))
    g_value_unset (&value);
  if (iter)
    gst_iterator_free (iter);

  composite->adjusting = FALSE;

  /*
     if (!result) {
     WARN ("failed to adjust PIP: %d, %d, %d, %d", x, y, w, h);
     }
   */

end:
  GST_COMPOSITE_UNLOCK (composite);
  return result;
}
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;
}