Пример #1
0
static GstPad *
_get_peer_pad (GstPad * pad)
{
  GstPad *peer = gst_pad_get_peer (pad);

  if (!peer)
    return NULL;

  while (GST_IS_PROXY_PAD (peer)) {
    GstPad *next_pad;

    if (GST_IS_GHOST_PAD (peer)) {
      next_pad = gst_pad_get_peer (peer);

      if (next_pad == pad)
        next_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (peer));
    } else {
      next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (peer)));
    }

    if (!next_pad)
      return NULL;

    gst_object_unref (peer);
    peer = next_pad;
  }

  return peer;
}
Пример #2
0
/**
 * gst_ghost_pad_set_target:
 * @gpad: the #GstGhostPad
 * @newtarget: (transfer none) (allow-none): the new pad target
 *
 * Set the new target of the ghostpad @gpad. Any existing target
 * is unlinked and links to the new target are established. if @newtarget is
 * %NULL the target will be cleared.
 *
 * Returns: (transfer full): %TRUE if the new target could be set. This function
 *     can return %FALSE when the internal pads could not be linked.
 */
gboolean
gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
{
    GstPad *internal;
    GstPad *oldtarget;
    GstPadLinkReturn lret;

    g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
    g_return_val_if_fail (GST_PAD_CAST (gpad) != newtarget, FALSE);
    g_return_val_if_fail (newtarget != GST_PROXY_PAD_INTERNAL (gpad), FALSE);

    GST_OBJECT_LOCK (gpad);
    internal = GST_PROXY_PAD_INTERNAL (gpad);

    if (newtarget)
        GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
    else
        GST_DEBUG_OBJECT (gpad, "clearing target");

    /* clear old target */
    if ((oldtarget = gst_pad_get_peer (internal))) {
        GST_OBJECT_UNLOCK (gpad);

        /* unlink internal pad */
        if (GST_PAD_IS_SRC (internal))
            gst_pad_unlink (internal, oldtarget);
        else
            gst_pad_unlink (oldtarget, internal);

        gst_object_unref (oldtarget);
    } else {
        GST_OBJECT_UNLOCK (gpad);
    }

    if (newtarget) {
        /* and link to internal pad without any checks */
        GST_DEBUG_OBJECT (gpad, "connecting internal pad to target %"
                          GST_PTR_FORMAT, newtarget);

        if (GST_PAD_IS_SRC (internal))
            lret =
                gst_pad_link_full (internal, newtarget, GST_PAD_LINK_CHECK_NOTHING);
        else
            lret =
                gst_pad_link_full (newtarget, internal, GST_PAD_LINK_CHECK_NOTHING);

        if (lret != GST_PAD_LINK_OK)
            goto link_failed;
    }

    return TRUE;

    /* ERRORS */
link_failed:
    {
        GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%s",
                            gst_pad_link_get_name (lret));
        return FALSE;
    }
}
static void
debug_dump_element_pad (GstPad * pad, GstElement * element,
    GstDebugGraphDetails details, FILE * out, const gint indent)
{
  GstElement *target_element;
  GstPad *target_pad, *tmp_pad;
  GstPadDirection dir;
  gchar *element_name;
  gchar *target_element_name;
  const gchar *color_name;

  dir = gst_pad_get_direction (pad);
  element_name = debug_dump_make_object_name (GST_OBJECT (element));
  if (GST_IS_GHOST_PAD (pad)) {
    color_name =
        (dir == GST_PAD_SRC) ? "#ffdddd" : ((dir ==
            GST_PAD_SINK) ? "#ddddff" : "#ffffff");
    /* output target-pad so that it belongs to this element */
    if ((tmp_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)))) {
      if ((target_pad = gst_pad_get_peer (tmp_pad))) {
        gchar *pad_name, *target_pad_name;
        const gchar *spc = &spaces[MAX (sizeof (spaces) - (1 + indent * 2), 0)];

        if ((target_element = gst_pad_get_parent_element (target_pad))) {
          target_element_name =
              debug_dump_make_object_name (GST_OBJECT (target_element));
        } else {
          target_element_name = g_strdup ("");
        }
        debug_dump_pad (target_pad, color_name, target_element_name, details,
            out, indent);
        /* src ghostpad relationship */
        pad_name = debug_dump_make_object_name (GST_OBJECT (pad));
        target_pad_name = debug_dump_make_object_name (GST_OBJECT (target_pad));
        if (dir == GST_PAD_SRC) {
          fprintf (out, "%s%s_%s -> %s_%s [style=dashed, minlen=0]\n", spc,
              target_element_name, target_pad_name, element_name, pad_name);
        } else {
          fprintf (out, "%s%s_%s -> %s_%s [style=dashed, minlen=0]\n", spc,
              element_name, pad_name, target_element_name, target_pad_name);
        }
        g_free (target_pad_name);
        g_free (target_element_name);
        if (target_element)
          gst_object_unref (target_element);
        gst_object_unref (target_pad);
        g_free (pad_name);
      }
      gst_object_unref (tmp_pad);
    }
  } else {
    color_name =
        (dir == GST_PAD_SRC) ? "#ffaaaa" : ((dir ==
            GST_PAD_SINK) ? "#aaaaff" : "#cccccc");
  }
  /* pads */
  debug_dump_pad (pad, color_name, element_name, details, out, indent);
  g_free (element_name);
}
Пример #4
0
static void
log_new_pad_stats (GstPadStats * stats, GstPad * pad)
{
  gst_tracer_record_log (tr_new_pad, (guint64) (guintptr) g_thread_self (),
      stats->index, stats->parent_ix, GST_OBJECT_NAME (pad),
      G_OBJECT_TYPE_NAME (pad), GST_IS_GHOST_PAD (pad),
      GST_PAD_DIRECTION (pad));
}
Пример #5
0
EXPORT_C
#endif

gboolean
gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
{
  GstPad *internal;
  GstPad *oldtarget;
  gboolean result;
  GstPadLinkReturn lret;

  g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);

  GST_PROXY_LOCK (gpad);
  internal = GST_PROXY_PAD_INTERNAL (gpad);

  GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));

  /* clear old target */
  if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
    /* if we have an internal pad, unlink */
    if (internal) {
      if (GST_PAD_IS_SRC (internal))
        gst_pad_unlink (internal, oldtarget);
      else
        gst_pad_unlink (oldtarget, internal);
    }
  }

  result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);

  if (result && newtarget) {
    /* and link to internal pad */
    GST_DEBUG_OBJECT (gpad, "connecting internal pad to target");

    if (GST_PAD_IS_SRC (internal))
      lret = gst_pad_link (internal, newtarget);
    else
      lret = gst_pad_link (newtarget, internal);

    if (lret != GST_PAD_LINK_OK)
      goto link_failed;
  }
  GST_PROXY_UNLOCK (gpad);

  return result;

  /* ERRORS */
link_failed:
  {
    GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d",
        lret);
    /* and unset target again */
    gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL);
    GST_PROXY_UNLOCK (gpad);
    return FALSE;
  }
}
Пример #6
0
/**
 * gst_ghost_pad_get_target:
 * @gpad: the #GstGhostPad
 *
 * Get the target pad of @gpad. Unref target pad after usage.
 *
 * Returns: (transfer full): the target #GstPad, can be NULL if the ghostpad
 * has no target set. Unref target pad after usage.
 */
GstPad *
gst_ghost_pad_get_target (GstGhostPad * gpad)
{
  GstPad *ret;

  g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);

  ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));

  GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));

  return ret;
}
Пример #7
0
static void
log_new_pad_stats (GstPadStats * stats, GstPad * pad)
{
  gst_tracer_log_trace (gst_structure_new ("new-pad",
          "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
          "ix", G_TYPE_UINT, stats->index,
          "parent-ix", G_TYPE_UINT, stats->parent_ix,
          "name", G_TYPE_STRING, GST_OBJECT_NAME (pad),
          "type", G_TYPE_STRING, G_OBJECT_TYPE_NAME (pad),
          "is-ghostpad", G_TYPE_BOOLEAN, GST_IS_GHOST_PAD (pad),
          "pad-direction", GST_TYPE_PAD_DIRECTION, GST_PAD_DIRECTION (pad),
          NULL));
}
Пример #8
0
/* TODO(ensonic): gst_pad_get_parent_element() would not work here, should we
 * add this as new api, e.g. gst_pad_find_parent_element();
 */
static GstElement *
get_real_pad_parent (GstPad * pad)
{
  GstObject *parent;

  if (!pad)
    return NULL;

  parent = GST_OBJECT_PARENT (pad);

  /* if parent of pad is a ghost-pad, then pad is a proxy_pad */
  if (parent && GST_IS_GHOST_PAD (parent)) {
    pad = GST_PAD_CAST (parent);
    parent = GST_OBJECT_PARENT (pad);
  }
  return GST_ELEMENT_CAST (parent);
}
Пример #9
0
static gboolean
gst_ghost_pad_activate_push_default (GstPad * pad, GstObject * parent,
    gboolean active)
{
  gboolean ret;
  GstPad *other;

  g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE);

  GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
      (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));

  /* just activate the internal pad */
  other = GST_PROXY_PAD_INTERNAL (pad);
  ret = gst_pad_activate_mode (other, GST_PAD_MODE_PUSH, active);

  return ret;
}
Пример #10
0
/**
 * gst_ghost_pad_activate_mode_default:
 * @pad: the #GstPad to activate or deactivate.
 * @parent: the parent of @pad or NULL
 * @mode: the requested activation mode
 * @active: whether the pad should be active or not.
 *
 * Invoke the default activate mode function of a ghost pad.
 *
 * Returns: %TRUE if the operation was successful.
 */
gboolean
gst_ghost_pad_activate_mode_default (GstPad * pad, GstObject * parent,
    GstPadMode mode, gboolean active)
{
  gboolean res;

  g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE);

  switch (mode) {
    case GST_PAD_MODE_PULL:
      res = gst_ghost_pad_activate_pull_default (pad, parent, active);
      break;
    case GST_PAD_MODE_PUSH:
      res = gst_ghost_pad_activate_push_default (pad, parent, active);
      break;
    default:
      GST_LOG_OBJECT (pad, "unknown activation mode %d", mode);
      res = FALSE;
      break;
  }
  return res;
}
Пример #11
0
void test_parse_bin_from_description()
{
  struct
  {
    const gchar *bin_desc;
    const gchar *pad_names;
  } bin_tests[] = {
    {
    "identity", "identity0/sink,identity0/src"}, {
    "identity ! identity ! identity", "identity1/sink,identity3/src"}, {
    "identity ! fakesink", "identity4/sink"}, {
    "fakesrc ! identity", "identity5/src"}, {
    "fakesrc ! fakesink", ""}
  };
  gint i;
  
  xmlfile = "gstutils_test_parse_bin_from_description";
  std_log(LOG_FILENAME_LINE, "Test Started gstutils_test_parse_bin_from_description");

  for (i = 0; i < G_N_ELEMENTS (bin_tests); ++i) {
    GstElement *bin, *parent;
    GString *s;
    GstPad *ghost_pad, *target_pad;
    GError *err = NULL;

    bin = gst_parse_bin_from_description (bin_tests[i].bin_desc, TRUE, &err);
    if (err) {
      g_error ("ERROR in gst_parse_bin_from_description (%s): %s",
          bin_tests[i].bin_desc, err->message);
    }
    g_assert (bin != NULL);

    s = g_string_new ("");
    if ((ghost_pad = gst_element_get_pad (bin, "sink"))) {
      g_assert (GST_IS_GHOST_PAD (ghost_pad));

      target_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost_pad));
      g_assert (target_pad != NULL);
      g_assert (GST_IS_PAD (target_pad));

      parent = gst_pad_get_parent_element (target_pad);
      g_assert (parent != NULL);

      g_string_append_printf (s, "%s/sink", GST_ELEMENT_NAME (parent));

      gst_object_unref (parent);
      gst_object_unref (target_pad);
      gst_object_unref (ghost_pad);
    }

    if ((ghost_pad = gst_element_get_pad (bin, "src"))) {
      g_assert (GST_IS_GHOST_PAD (ghost_pad));

      target_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost_pad));
      g_assert (target_pad != NULL);
      g_assert (GST_IS_PAD (target_pad));

      parent = gst_pad_get_parent_element (target_pad);
      g_assert (parent != NULL);

      if (s->len > 0) {
        g_string_append (s, ",");
      }

      g_string_append_printf (s, "%s/src", GST_ELEMENT_NAME (parent));

      gst_object_unref (parent);
      gst_object_unref (target_pad);
      gst_object_unref (ghost_pad);
    }

    if (strcmp (s->str, bin_tests[i].pad_names) != 0) {
      g_error ("FAILED: expted '%s', got '%s' for bin '%s'",
          bin_tests[i].pad_names, s->str, bin_tests[i].bin_desc);
    }
    g_string_free (s, TRUE);

    gst_object_unref (bin);
  }
  std_log(LOG_FILENAME_LINE, "Test Successful");
  create_xml(0);
}
Пример #12
0
static void
do_element_stats (GstStatsTracer * self, GstPad * pad, GstClockTime elapsed1,
    GstClockTime elapsed2)
{
  GstClockTimeDiff elapsed = GST_CLOCK_DIFF (elapsed1, elapsed2);
  GstObject *parent = GST_OBJECT_PARENT (pad);
  GstElement *this =
      GST_ELEMENT_CAST (GST_IS_PAD (parent) ? GST_OBJECT_PARENT (parent) :
      parent);
  GstElementStats *this_stats = get_element_stats (self, this);
  GstPad *peer_pad = GST_PAD_PEER (pad);
  GstElementStats *peer_stats;

  if (!peer_pad)
    return;

  /* walk the ghost pad chain downstream to get the real pad */
  /* if parent of peer_pad is a ghost-pad, then peer_pad is a proxy_pad */
  parent = GST_OBJECT_PARENT (peer_pad);
  if (parent && GST_IS_GHOST_PAD (parent)) {
    peer_pad = GST_PAD_CAST (parent);
    /* if this is now the ghost pad, get the peer of this */
    get_pad_stats (self, peer_pad);
    if ((parent = GST_OBJECT_PARENT (peer_pad))) {
      get_element_stats (self, GST_ELEMENT_CAST (parent));
    }
    peer_pad = GST_PAD_PEER (GST_GHOST_PAD_CAST (peer_pad));
    parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
  }
  /* walk the ghost pad chain upstream to get the real pad */
  /* if peer_pad is a ghost-pad, then parent is a bin and it is the parent of
   * a proxy_pad */
  while (peer_pad && GST_IS_GHOST_PAD (peer_pad)) {
    get_pad_stats (self, peer_pad);
    get_element_stats (self, GST_ELEMENT_CAST (parent));
    peer_pad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (peer_pad));
    parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
  }

  if (!parent) {
    printf ("%" GST_TIME_FORMAT
        " transmission on unparented target pad %s_%s -> %s_%s\n",
        GST_TIME_ARGS (elapsed), GST_DEBUG_PAD_NAME (pad),
        GST_DEBUG_PAD_NAME (peer_pad));
    return;
  }
  peer_stats = get_element_stats (self, GST_ELEMENT_CAST (parent));

  /* we'd like to gather time spend in each element, but this does not make too
   * much sense yet
   * pure push/pull-based:
   *   - the time spend in the push/pull_range is accounted for the peer and
   *     removed from the current element
   *   - this works for chains
   *   - drawback is sink elements that block to sync have a high time usage
   *     - we could rerun the ests with sync=false
   * both:
   *   - a.g. demuxers both push and pull. thus we subtract time for the pull
   *     and the push operations, but never add anything.
   *   - can we start a counter after push/pull in such elements and add then
   *     time to the element upon next pad activity?
   */
#if 1
  /* this does not make sense for demuxers */
  this_stats->treal -= elapsed;
  peer_stats->treal += elapsed;
#else
  /* this creates several >100% figures */
  this_stats->treal += GST_CLOCK_DIFF (this_stats->last_ts, elapsed2) - elapsed;
  peer_stats->treal += elapsed;
  this_stats->last_ts = elapsed2;
  peer_stats->last_ts = elapsed2;
#endif
}
/*
 * 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);
}
Пример #14
0
/**
 * gst_ghost_pad_construct:
 * @gpad: the newly allocated ghost pad
 *
 * Finish initialization of a newly allocated ghost pad.
 *
 * This function is most useful in language bindings and when subclassing
 * #GstGhostPad; plugin and application developers normally will not call this
 * function. Call this function directly after a call to g_object_new
 * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
 *
 * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
 */
gboolean
gst_ghost_pad_construct (GstGhostPad * gpad)
{
  GstPadDirection dir, otherdir;
  GstPadTemplate *templ;
  GstPad *pad, *internal;

  g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
  g_return_val_if_fail (GST_GHOST_PAD_PRIVATE (gpad)->constructed == FALSE,
      FALSE);

  g_object_get (gpad, "direction", &dir, "template", &templ, NULL);

  g_return_val_if_fail (dir != GST_PAD_UNKNOWN, FALSE);

  pad = GST_PAD (gpad);

  /* Set directional padfunctions for ghostpad */
  if (dir == GST_PAD_SINK) {
    gst_pad_set_chain_function (pad, gst_proxy_pad_chain_default);
    gst_pad_set_chain_list_function (pad, gst_proxy_pad_chain_list_default);
  } else {
    gst_pad_set_getrange_function (pad, gst_proxy_pad_getrange_default);
  }

  /* INTERNAL PAD, it always exists and is child of the ghostpad */
  otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
  if (templ) {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, "template", templ, NULL);
    /* release ref obtained via g_object_get */
    gst_object_unref (templ);
  } else {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, NULL);
  }
  GST_PAD_UNSET_FLUSHING (internal);

  /* Set directional padfunctions for internal pad */
  if (dir == GST_PAD_SRC) {
    gst_pad_set_chain_function (internal, gst_proxy_pad_chain_default);
    gst_pad_set_chain_list_function (internal,
        gst_proxy_pad_chain_list_default);
  } else {
    gst_pad_set_getrange_function (internal, gst_proxy_pad_getrange_default);
  }

  GST_OBJECT_LOCK (pad);

  /* now make the ghostpad a parent of the internal pad */
  if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
          GST_OBJECT_CAST (pad)))
    goto parent_failed;

  /* The ghostpad is the parent of the internal pad and is the only object that
   * can have a refcount on the internal pad.
   * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
   * a refcount of 1.
   * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
   * its refcount on the internal pad in the dispose method by un-parenting it.
   * This is why we don't take extra refcounts in the assignments below
   */
  GST_PROXY_PAD_INTERNAL (pad) = internal;
  GST_PROXY_PAD_INTERNAL (internal) = pad;

  /* special activation functions for the internal pad */
  gst_pad_set_activatemode_function (internal,
      gst_ghost_pad_internal_activate_mode_default);

  GST_OBJECT_UNLOCK (pad);

  GST_GHOST_PAD_PRIVATE (gpad)->constructed = TRUE;
  return TRUE;

  /* ERRORS */
parent_failed:
  {
    GST_WARNING_OBJECT (gpad, "Could not set internal pad %s:%s",
        GST_DEBUG_PAD_NAME (internal));
    g_critical ("Could not set internal pad %s:%s",
        GST_DEBUG_PAD_NAME (internal));
    GST_OBJECT_UNLOCK (pad);
    gst_object_unref (internal);
    return FALSE;
  }
}
Пример #15
0
/*
 * 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, FILE * out,
    const gint indent)
{
  GstIterator *element_iter, *pad_iter;
  gboolean elements_done, pads_done;
  GstElement *element, *peer_element, *target_element;
  GstPad *pad, *peer_pad, *target_pad;
  GstPadDirection dir;
  GstCaps *caps;
  GstStructure *structure;
  gboolean free_caps, free_media;
  guint src_pads, sink_pads;
  gchar *media = NULL;
  gchar *pad_name, *element_name;
  gchar *peer_pad_name, *peer_element_name;
  gchar *target_pad_name, *target_element_name;
  gchar *color_name;
  gchar *state_name = NULL;
  gchar *param_name = NULL;
  gchar *spc = NULL;

  spc = g_malloc (1 + indent * 2);
  memset (spc, 32, indent * 2);
  spc[indent * 2] = '\0';

  element_iter = gst_bin_iterate_elements (bin);
  elements_done = FALSE;
  while (!elements_done) {
    switch (gst_iterator_next (element_iter, (gpointer) & element)) {
      case GST_ITERATOR_OK:
        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));
        }
        /* elements */
        fprintf (out, "%ssubgraph cluster_%s {\n", spc, element_name);
        fprintf (out, "%s  fontname=\"Bitstream Vera Sans\";\n", spc);
        fprintf (out, "%s  fontsize=\"8\";\n", spc);
        fprintf (out, "%s  style=filled;\n", spc);
        fprintf (out, "%s  color=black;\n\n", spc);
        fprintf (out, "%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_pads (element))) {
          pads_done = FALSE;
          while (!pads_done) {
            switch (gst_iterator_next (pad_iter, (gpointer) & pad)) {
              case GST_ITERATOR_OK:
                dir = gst_pad_get_direction (pad);
                pad_name = debug_dump_make_object_name (GST_OBJECT (pad));
                element_name =
                    debug_dump_make_object_name (GST_OBJECT (element));
                if (GST_IS_GHOST_PAD (pad)) {
                  color_name =
                      (dir == GST_PAD_SRC) ? "#ffdddd" : ((dir ==
                          GST_PAD_SINK) ? "#ddddff" : "#ffffff");
                } else {
                  color_name =
                      (dir == GST_PAD_SRC) ? "#ffaaaa" : ((dir ==
                          GST_PAD_SINK) ? "#aaaaff" : "#cccccc");
                }
                /* pads */
                fprintf (out,
                    "%s  %s_%s [color=black, fillcolor=\"%s\", label=\"%s\"];\n",
                    spc, element_name, pad_name, color_name,
                    GST_OBJECT_NAME (pad));

                if (dir == GST_PAD_SRC)
                  src_pads++;
                else if (dir == GST_PAD_SINK)
                  sink_pads++;
                g_free (pad_name);
                g_free (element_name);
                gst_object_unref (pad);
                break;
              case GST_ITERATOR_RESYNC:
                gst_iterator_resync (pad_iter);
                break;
              case GST_ITERATOR_ERROR:
              case GST_ITERATOR_DONE:
                pads_done = TRUE;
                break;
            }
          }
          gst_iterator_free (pad_iter);
        }
        if (GST_IS_BIN (element)) {
          fprintf (out, "%s  fillcolor=\"#ffffff\";\n", spc);
          /* recurse */
          debug_dump_element (GST_BIN (element), details, out, indent + 1);
        } else {
          if (src_pads && !sink_pads)
            fprintf (out, "%s  fillcolor=\"#ffaaaa\";\n", spc);
          else if (!src_pads && sink_pads)
            fprintf (out, "%s  fillcolor=\"#aaaaff\";\n", spc);
          else if (src_pads && sink_pads)
            fprintf (out, "%s  fillcolor=\"#aaffaa\";\n", spc);
          else
            fprintf (out, "%s  fillcolor=\"#ffffff\";\n", spc);
        }
        fprintf (out, "%s}\n\n", spc);
        if ((pad_iter = gst_element_iterate_pads (element))) {
          pads_done = FALSE;
          while (!pads_done) {
            switch (gst_iterator_next (pad_iter, (gpointer) & pad)) {
              case GST_ITERATOR_OK:
                if (gst_pad_is_linked (pad)
                    && gst_pad_get_direction (pad) == GST_PAD_SRC) {
                  if ((peer_pad = gst_pad_get_peer (pad))) {
                    free_media = FALSE;
                    if ((details & GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE) ||
                        (details & GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS)
                        ) {
                      if ((caps = gst_pad_get_negotiated_caps (pad))) {
                        free_caps = TRUE;
                      } else {
                        free_caps = FALSE;
                        if (!(caps = (GstCaps *)
                                gst_pad_get_pad_template_caps (pad))) {
                          /* this should not happen */
                          media = "?";
                        }
                      }
                      if (caps) {
                        if (details & GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS) {
                          gchar *tmp =
                              g_strdelimit (gst_caps_to_string (caps), ",",
                              '\n');

                          media = g_strescape (tmp, NULL);
                          free_media = TRUE;
                          g_free (tmp);
                        } else {
                          if (GST_CAPS_IS_SIMPLE (caps)) {
                            structure = gst_caps_get_structure (caps, 0);
                            media =
                                (gchar *) gst_structure_get_name (structure);
                          } else
                            media = "*";
                        }
                        if (free_caps) {
                          gst_caps_unref (caps);
                        }
                      }
                    }

                    pad_name = debug_dump_make_object_name (GST_OBJECT (pad));
                    element_name =
                        debug_dump_make_object_name (GST_OBJECT (element));
                    peer_pad_name =
                        debug_dump_make_object_name (GST_OBJECT (peer_pad));
                    if ((peer_element = gst_pad_get_parent_element (peer_pad))) {
                      peer_element_name =
                          debug_dump_make_object_name (GST_OBJECT
                          (peer_element));
                    } else {
                      peer_element_name = "";
                    }
                    /* pad link */
                    if (media) {
                      fprintf (out, "%s%s_%s -> %s_%s [label=\"%s\"]\n", spc,
                          element_name, pad_name, peer_element_name,
                          peer_pad_name, media);
                      if (free_media) {
                        g_free (media);
                      }
                    } else {
                      fprintf (out, "%s%s_%s -> %s_%s\n", spc,
                          element_name, pad_name, peer_element_name,
                          peer_pad_name);
                    }

                    if (GST_IS_GHOST_PAD (pad)) {
                      if ((target_pad =
                              gst_ghost_pad_get_target (GST_GHOST_PAD (pad)))) {
                        target_pad_name =
                            debug_dump_make_object_name (GST_OBJECT
                            (target_pad));
                        if ((target_element =
                                gst_pad_get_parent_element (target_pad))) {
                          target_element_name =
                              debug_dump_make_object_name (GST_OBJECT
                              (target_element));
                        } else {
                          target_element_name = "";
                        }
                        /* src ghostpad relationship */
                        fprintf (out, "%s%s_%s -> %s_%s [style=dashed]\n", spc,
                            target_element_name, target_pad_name, element_name,
                            pad_name);

                        g_free (target_pad_name);
                        if (target_element) {
                          g_free (target_element_name);
                          gst_object_unref (target_element);
                        }
                        gst_object_unref (target_pad);
                      }
                    }
                    if (GST_IS_GHOST_PAD (peer_pad)) {
                      if ((target_pad =
                              gst_ghost_pad_get_target (GST_GHOST_PAD
                                  (peer_pad)))) {
                        target_pad_name =
                            debug_dump_make_object_name (GST_OBJECT
                            (target_pad));
                        if ((target_element =
                                gst_pad_get_parent_element (target_pad))) {
                          target_element_name =
                              debug_dump_make_object_name (GST_OBJECT
                              (target_element));
                        } else {
                          target_element_name = "";
                        }
                        /* sink ghostpad relationship */
                        fprintf (out, "%s%s_%s -> %s_%s [style=dashed]\n", spc,
                            peer_element_name, peer_pad_name,
                            target_element_name, target_pad_name);

                        g_free (target_pad_name);
                        if (target_element) {
                          g_free (target_element_name);
                          gst_object_unref (target_element);
                        }
                        gst_object_unref (target_pad);
                      }
                    }

                    g_free (pad_name);
                    g_free (element_name);
                    g_free (peer_pad_name);
                    if (peer_element) {
                      g_free (peer_element_name);
                      gst_object_unref (peer_element);
                    }
                    gst_object_unref (peer_pad);
                  }
                }
                gst_object_unref (pad);
                break;
              case GST_ITERATOR_RESYNC:
                gst_iterator_resync (pad_iter);
                break;
              case GST_ITERATOR_ERROR:
              case GST_ITERATOR_DONE:
                pads_done = TRUE;
                break;
            }
          }
          gst_iterator_free (pad_iter);
        }
        gst_object_unref (element);
        break;
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (element_iter);
        break;
      case GST_ITERATOR_ERROR:
      case GST_ITERATOR_DONE:
        elements_done = TRUE;
        break;
    }
  }
  gst_iterator_free (element_iter);
  g_free (spc);
}
Пример #16
0
/**
 * gst_ghost_pad_construct:
 * @gpad: the newly allocated ghost pad
 *
 * Finish initialization of a newly allocated ghost pad.
 *
 * This function is most useful in language bindings and when subclassing
 * #GstGhostPad; plugin and application developers normally will not call this
 * function. Call this function directly after a call to g_object_new
 * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
 *
 * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
 *
 * Since: 0.10.22
 */
gboolean
gst_ghost_pad_construct (GstGhostPad * gpad)
{
  GstPadDirection dir, otherdir;
  GstPadTemplate *templ;
  GstPad *pad, *internal;

  g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
  g_return_val_if_fail (GST_GHOST_PAD_PRIVATE (gpad)->constructed == FALSE,
      FALSE);

  g_object_get (gpad, "direction", &dir, "template", &templ, NULL);

  g_return_val_if_fail (dir != GST_PAD_UNKNOWN, FALSE);

  pad = GST_PAD (gpad);

  /* Set directional padfunctions for ghostpad */
  if (dir == GST_PAD_SINK) {
    gst_pad_set_bufferalloc_function (pad,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
    gst_pad_set_chain_function (pad,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
  } else {
    gst_pad_set_getrange_function (pad,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
    gst_pad_set_checkgetrange_function (pad,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
  }

  /* link/unlink functions */
  gst_pad_set_link_function (pad, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
  gst_pad_set_unlink_function (pad,
      GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));


  /* INTERNAL PAD, it always exists and is child of the ghostpad */
  otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
  if (templ) {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, "template", templ, NULL);
    /* release ref obtained via g_object_get */
    gst_object_unref (templ);
  } else {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, NULL);
  }
  GST_PAD_UNSET_FLUSHING (internal);

  /* Set directional padfunctions for internal pad */
  if (dir == GST_PAD_SRC) {
    gst_pad_set_bufferalloc_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
    gst_pad_set_chain_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
  } else {
    gst_pad_set_getrange_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
    gst_pad_set_checkgetrange_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
  }

  GST_PROXY_LOCK (pad);

  /* now make the ghostpad a parent of the internal pad */
  if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
          GST_OBJECT_CAST (pad)))
    goto parent_failed;

  /* The ghostpad is the parent of the internal pad and is the only object that
   * can have a refcount on the internal pad.
   * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
   * a refcount of 1.
   * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
   * it's refcount on the internal pad in the dispose method by un-parenting it.
   * This is why we don't take extra refcounts in the assignments below
   */
  GST_PROXY_PAD_INTERNAL (pad) = internal;
  GST_PROXY_PAD_INTERNAL (internal) = pad;

  /* could be more general here, iterating over all writable properties...
   * taking the short road for now tho */
  GST_GHOST_PAD_PRIVATE (pad)->notify_id =
      g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
      pad);

  /* call function to init values of the pad caps */
  on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (pad));

  /* special activation functions for the internal pad */
  gst_pad_set_activatepull_function (internal,
      GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
  gst_pad_set_activatepush_function (internal,
      GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));

  GST_PROXY_UNLOCK (pad);

  GST_GHOST_PAD_PRIVATE (gpad)->constructed = TRUE;
  return TRUE;

  /* ERRORS */
parent_failed:
  {
    GST_WARNING_OBJECT (gpad, "Could not set internal pad %s:%s",
        GST_DEBUG_PAD_NAME (internal));
    g_critical ("Could not set internal pad %s:%s",
        GST_DEBUG_PAD_NAME (internal));
    GST_PROXY_UNLOCK (pad);
    gst_object_unref (internal);
    return FALSE;
  }
}