2000-12-28 22:12:02 +00:00
|
|
|
/* GStreamer
|
|
|
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
|
|
* 2000 Wim Taymans <wtay@chello.be>
|
2006-02-02 09:51:18 +00:00
|
|
|
* 2002 Thomas Vander Stichele <thomas@apestaart.org>
|
2000-12-28 22:12:02 +00:00
|
|
|
*
|
2008-08-20 07:22:11 +00:00
|
|
|
* gstutils.c: Utility functions
|
2000-01-30 09:03:00 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
2005-10-15 16:01:57 +00:00
|
|
|
|
2005-08-31 14:08:45 +00:00
|
|
|
/**
|
|
|
|
* SECTION:gstutils
|
|
|
|
* @short_description: Various utility functions
|
|
|
|
*
|
|
|
|
*/
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2006-05-04 15:20:14 +00:00
|
|
|
#include "gst_private.h"
|
2001-03-03 18:19:38 +00:00
|
|
|
#include <stdio.h>
|
2001-04-22 16:04:19 +00:00
|
|
|
#include <string.h>
|
2001-03-03 18:19:38 +00:00
|
|
|
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
#include "gstghostpad.h"
|
2000-12-15 01:57:34 +00:00
|
|
|
#include "gstutils.h"
|
2007-05-09 16:32:07 +00:00
|
|
|
#include "gsterror.h"
|
2003-06-29 14:05:49 +00:00
|
|
|
#include "gstinfo.h"
|
2006-02-02 09:51:18 +00:00
|
|
|
#include "gstparse.h"
|
2009-03-24 18:33:56 +00:00
|
|
|
#include "gstvalue.h"
|
2005-03-07 18:27:42 +00:00
|
|
|
#include "gst-i18n-lib.h"
|
2011-06-04 07:30:15 +00:00
|
|
|
#include "glib-compat-private.h"
|
2009-11-16 08:29:10 +00:00
|
|
|
#include <math.h>
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2000-10-25 19:09:53 +00:00
|
|
|
/**
|
|
|
|
* gst_util_dump_mem:
|
|
|
|
* @mem: a pointer to the memory to dump
|
|
|
|
* @size: the size of the memory block to dump
|
|
|
|
*
|
2001-01-06 22:05:15 +00:00
|
|
|
* Dumps the memory block into a hex representation. Useful for debugging.
|
2000-10-25 19:09:53 +00:00
|
|
|
*/
|
2001-10-21 18:00:31 +00:00
|
|
|
void
|
2004-03-22 22:23:50 +00:00
|
|
|
gst_util_dump_mem (const guchar * mem, guint size)
|
2001-03-21 21:43:56 +00:00
|
|
|
{
|
2000-07-15 13:26:28 +00:00
|
|
|
guint i, j;
|
2003-02-21 19:58:24 +00:00
|
|
|
GString *string = g_string_sized_new (50);
|
|
|
|
GString *chars = g_string_sized_new (18);
|
2000-07-15 13:26:28 +00:00
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
i = j = 0;
|
|
|
|
while (i < size) {
|
2003-02-21 19:58:24 +00:00
|
|
|
if (g_ascii_isprint (mem[i]))
|
2007-12-28 14:15:53 +00:00
|
|
|
g_string_append_c (chars, mem[i]);
|
2004-03-13 15:27:01 +00:00
|
|
|
else
|
2007-12-28 14:15:53 +00:00
|
|
|
g_string_append_c (chars, '.');
|
2002-05-29 15:01:50 +00:00
|
|
|
|
2003-01-26 23:38:30 +00:00
|
|
|
g_string_append_printf (string, "%02x ", mem[i]);
|
2003-02-21 19:58:24 +00:00
|
|
|
|
|
|
|
j++;
|
2000-07-15 13:26:28 +00:00
|
|
|
i++;
|
2003-02-21 19:58:24 +00:00
|
|
|
|
|
|
|
if (j == 16 || i == size) {
|
2004-03-13 15:27:01 +00:00
|
|
|
g_print ("%08x (%p): %-48.48s %-16.16s\n", i - j, mem + i - j,
|
2004-03-15 19:27:17 +00:00
|
|
|
string->str, chars->str);
|
2003-02-21 19:58:24 +00:00
|
|
|
g_string_set_size (string, 0);
|
|
|
|
g_string_set_size (chars, 0);
|
|
|
|
j = 0;
|
|
|
|
}
|
2000-07-15 13:26:28 +00:00
|
|
|
}
|
2003-01-26 23:38:30 +00:00
|
|
|
g_string_free (string, TRUE);
|
2003-02-21 19:58:24 +00:00
|
|
|
g_string_free (chars, TRUE);
|
2000-07-15 13:26:28 +00:00
|
|
|
}
|
2001-03-03 18:19:38 +00:00
|
|
|
|
2002-03-03 18:41:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_set_value_from_string:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @value: (out caller-allocates): the value to set
|
2002-03-03 18:41:25 +00:00
|
|
|
* @value_str: the string to get the value from
|
|
|
|
*
|
|
|
|
* Converts the string to the type of the value and
|
|
|
|
* sets the value with it.
|
2009-03-24 18:33:56 +00:00
|
|
|
*
|
|
|
|
* Note that this function is dangerous as it does not return any indication
|
|
|
|
* if the conversion worked or not.
|
2002-03-03 18:41:25 +00:00
|
|
|
*/
|
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_util_set_value_from_string (GValue * value, const gchar * value_str)
|
2002-03-03 18:41:25 +00:00
|
|
|
{
|
2009-03-24 18:33:56 +00:00
|
|
|
gboolean res;
|
2002-03-03 18:41:25 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
g_return_if_fail (value != NULL);
|
|
|
|
g_return_if_fail (value_str != NULL);
|
|
|
|
|
|
|
|
GST_CAT_DEBUG (GST_CAT_PARAMS, "parsing '%s' to type %s", value_str,
|
|
|
|
g_type_name (G_VALUE_TYPE (value)));
|
|
|
|
|
2009-03-24 18:33:56 +00:00
|
|
|
res = gst_value_deserialize (value, value_str);
|
|
|
|
if (!res && G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) {
|
|
|
|
/* backwards compat, all booleans that fail to parse are false */
|
|
|
|
g_value_set_boolean (value, FALSE);
|
|
|
|
res = TRUE;
|
2004-03-13 15:27:01 +00:00
|
|
|
}
|
2009-03-24 18:33:56 +00:00
|
|
|
g_return_if_fail (res);
|
2002-03-03 18:41:25 +00:00
|
|
|
}
|
|
|
|
|
2001-03-21 21:43:56 +00:00
|
|
|
/**
|
|
|
|
* gst_util_set_object_arg:
|
|
|
|
* @object: the object to set the argument of
|
|
|
|
* @name: the name of the argument to set
|
|
|
|
* @value: the string value to set
|
|
|
|
*
|
|
|
|
* Convertes the string value to the type of the objects argument and
|
|
|
|
* sets the argument with it.
|
2009-03-24 18:33:56 +00:00
|
|
|
*
|
|
|
|
* Note that this function silently returns if @object has no property named
|
|
|
|
* @name or when @value cannot be converted to the type of the property.
|
2001-03-21 21:43:56 +00:00
|
|
|
*/
|
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_util_set_object_arg (GObject * object, const gchar * name,
|
|
|
|
const gchar * value)
|
2001-03-03 18:19:38 +00:00
|
|
|
{
|
2009-03-24 18:33:56 +00:00
|
|
|
GParamSpec *pspec;
|
|
|
|
GType value_type;
|
|
|
|
GValue v = { 0, };
|
2001-06-25 01:20:11 +00:00
|
|
|
|
2009-03-24 18:33:56 +00:00
|
|
|
g_return_if_fail (G_IS_OBJECT (object));
|
|
|
|
g_return_if_fail (name != NULL);
|
|
|
|
g_return_if_fail (value != NULL);
|
2004-03-15 19:27:17 +00:00
|
|
|
|
2009-03-24 18:33:56 +00:00
|
|
|
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
|
|
|
|
if (!pspec)
|
|
|
|
return;
|
2004-03-15 19:27:17 +00:00
|
|
|
|
2009-12-28 16:25:20 +00:00
|
|
|
value_type = pspec->value_type;
|
2004-03-15 19:27:17 +00:00
|
|
|
|
2009-06-16 07:43:53 +00:00
|
|
|
GST_DEBUG ("pspec->flags is %d, pspec->value_type is %s",
|
|
|
|
pspec->flags, g_type_name (value_type));
|
2004-03-15 19:27:17 +00:00
|
|
|
|
2009-03-24 18:33:56 +00:00
|
|
|
if (!(pspec->flags & G_PARAM_WRITABLE))
|
|
|
|
return;
|
2004-03-15 19:27:17 +00:00
|
|
|
|
2009-03-24 18:33:56 +00:00
|
|
|
g_value_init (&v, value_type);
|
2009-06-16 07:43:53 +00:00
|
|
|
|
|
|
|
/* special case for element <-> xml (de)serialisation */
|
|
|
|
if (GST_VALUE_HOLDS_STRUCTURE (&v) && strcmp (value, "NULL") == 0) {
|
|
|
|
g_value_set_boxed (&v, NULL);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2009-03-24 18:33:56 +00:00
|
|
|
if (!gst_value_deserialize (&v, value))
|
|
|
|
return;
|
2004-03-15 19:27:17 +00:00
|
|
|
|
2009-06-16 07:43:53 +00:00
|
|
|
done:
|
|
|
|
|
2009-03-24 18:33:56 +00:00
|
|
|
g_object_set_property (object, pspec->name, &v);
|
|
|
|
g_value_unset (&v);
|
2001-03-03 18:19:38 +00:00
|
|
|
}
|
2001-09-17 23:44:07 +00:00
|
|
|
|
2005-10-10 16:38:59 +00:00
|
|
|
/* work around error C2520: conversion from unsigned __int64 to double
|
2005-12-05 13:06:37 +00:00
|
|
|
* not implemented, use signed __int64
|
2005-10-20 20:25:55 +00:00
|
|
|
*
|
2005-12-05 13:06:37 +00:00
|
|
|
* These are implemented as functions because on some platforms a 64bit int to
|
|
|
|
* double conversion is not defined/implemented.
|
2005-10-20 20:25:55 +00:00
|
|
|
*/
|
2005-12-05 13:06:37 +00:00
|
|
|
|
2005-10-10 18:16:37 +00:00
|
|
|
gdouble
|
2005-12-04 09:57:11 +00:00
|
|
|
gst_util_guint64_to_gdouble (guint64 value)
|
2005-10-10 16:38:59 +00:00
|
|
|
{
|
2005-12-04 09:57:11 +00:00
|
|
|
if (value & G_GINT64_CONSTANT (0x8000000000000000))
|
2005-10-10 16:38:59 +00:00
|
|
|
return (gdouble) ((gint64) value) + (gdouble) 18446744073709551616.;
|
|
|
|
else
|
|
|
|
return (gdouble) ((gint64) value);
|
|
|
|
}
|
2005-10-10 17:05:04 +00:00
|
|
|
|
2005-10-10 18:16:37 +00:00
|
|
|
guint64
|
2005-12-04 09:57:11 +00:00
|
|
|
gst_util_gdouble_to_guint64 (gdouble value)
|
2005-10-10 17:05:04 +00:00
|
|
|
{
|
|
|
|
if (value < (gdouble) 9223372036854775808.) /* 1 << 63 */
|
|
|
|
return ((guint64) ((gint64) value));
|
|
|
|
|
2005-10-10 18:16:37 +00:00
|
|
|
value -= (gdouble) 18446744073709551616.;
|
|
|
|
return ((guint64) ((gint64) value));
|
2005-10-10 17:05:04 +00:00
|
|
|
}
|
2005-11-24 17:44:57 +00:00
|
|
|
|
2009-09-09 12:53:16 +00:00
|
|
|
#ifndef HAVE_UINT128_T
|
2005-12-04 09:57:11 +00:00
|
|
|
/* convenience struct for getting high and low uint32 parts of
|
2005-11-24 17:44:57 +00:00
|
|
|
* a guint64 */
|
|
|
|
typedef union
|
|
|
|
{
|
|
|
|
guint64 ll;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
|
|
|
guint32 high, low;
|
|
|
|
#else
|
|
|
|
guint32 low, high;
|
|
|
|
#endif
|
|
|
|
} l;
|
|
|
|
} GstUInt64;
|
|
|
|
|
2009-08-28 10:43:43 +00:00
|
|
|
#if defined (__x86_64__) && defined (__GNUC__)
|
2009-08-28 11:45:38 +00:00
|
|
|
static inline void
|
2009-08-28 10:43:43 +00:00
|
|
|
gst_util_uint64_mul_uint64 (GstUInt64 * c1, GstUInt64 * c0, guint64 arg1,
|
|
|
|
guint64 arg2)
|
|
|
|
{
|
2010-03-10 07:15:15 +00:00
|
|
|
__asm__ __volatile__ ("mulq %3":"=a" (c0->ll), "=d" (c1->ll)
|
2009-08-28 10:43:43 +00:00
|
|
|
:"a" (arg1), "g" (arg2)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
#else /* defined (__x86_64__) */
|
2009-08-11 07:10:47 +00:00
|
|
|
/* multiply two 64-bit unsigned ints into a 128-bit unsigned int. the high
|
|
|
|
* and low 64 bits of the product are placed in c1 and c0 respectively.
|
|
|
|
* this operation cannot overflow. */
|
2009-08-28 11:45:38 +00:00
|
|
|
static inline void
|
2009-08-11 07:10:47 +00:00
|
|
|
gst_util_uint64_mul_uint64 (GstUInt64 * c1, GstUInt64 * c0, guint64 arg1,
|
|
|
|
guint64 arg2)
|
2005-11-28 16:05:35 +00:00
|
|
|
{
|
2009-08-11 07:10:47 +00:00
|
|
|
GstUInt64 a1, b0;
|
2005-12-02 11:36:50 +00:00
|
|
|
GstUInt64 v, n;
|
2005-11-25 00:02:05 +00:00
|
|
|
|
|
|
|
/* prepare input */
|
2009-08-11 07:10:47 +00:00
|
|
|
v.ll = arg1;
|
|
|
|
n.ll = arg2;
|
2005-11-25 00:02:05 +00:00
|
|
|
|
2005-12-04 09:57:11 +00:00
|
|
|
/* do 128 bits multiply
|
2005-11-25 00:02:05 +00:00
|
|
|
* nh nl
|
|
|
|
* * vh vl
|
|
|
|
* ----------
|
|
|
|
* a0 = vl * nl
|
|
|
|
* a1 = vl * nh
|
|
|
|
* b0 = vh * nl
|
|
|
|
* b1 = + vh * nh
|
|
|
|
* -------------------
|
2009-08-11 07:10:47 +00:00
|
|
|
* c1h c1l c0h c0l
|
|
|
|
*
|
|
|
|
* "a0" is optimized away, result is stored directly in c0. "b1" is
|
|
|
|
* optimized away, result is stored directly in c1.
|
2005-11-25 00:02:05 +00:00
|
|
|
*/
|
2009-08-11 07:10:47 +00:00
|
|
|
c0->ll = (guint64) v.l.low * n.l.low;
|
2005-11-25 00:02:05 +00:00
|
|
|
a1.ll = (guint64) v.l.low * n.l.high;
|
|
|
|
b0.ll = (guint64) v.l.high * n.l.low;
|
2009-08-11 07:10:47 +00:00
|
|
|
|
|
|
|
/* add the high word of a0 to the low words of a1 and b0 using c1 as
|
|
|
|
* scrach space to capture the carry. the low word of the result becomes
|
|
|
|
* the final high word of c0 */
|
|
|
|
c1->ll = (guint64) c0->l.high + a1.l.low + b0.l.low;
|
|
|
|
c0->l.high = c1->l.low;
|
|
|
|
|
|
|
|
/* add the carry from the result above (found in the high word of c1) and
|
|
|
|
* the high words of a1 and b0 to b1, the result is c1. */
|
|
|
|
c1->ll = (guint64) v.l.high * n.l.high + c1->l.high + a1.l.high + b0.l.high;
|
|
|
|
}
|
2009-08-28 10:43:43 +00:00
|
|
|
#endif /* defined (__x86_64__) */
|
2009-08-11 07:10:47 +00:00
|
|
|
|
2009-08-28 10:43:43 +00:00
|
|
|
#if defined (__x86_64__) && defined (__GNUC__)
|
2009-08-31 09:45:17 +00:00
|
|
|
static inline guint64
|
|
|
|
gst_util_div128_64 (GstUInt64 c1, GstUInt64 c0, guint64 denom)
|
2009-08-28 10:43:43 +00:00
|
|
|
{
|
2009-08-31 09:45:17 +00:00
|
|
|
guint64 res;
|
2009-08-28 10:43:43 +00:00
|
|
|
|
2009-08-31 09:45:17 +00:00
|
|
|
__asm__ __volatile__ ("divq %3":"=a" (res)
|
|
|
|
:"d" (c1.ll), "a" (c0.ll), "g" (denom)
|
2009-08-28 10:43:43 +00:00
|
|
|
);
|
2009-08-31 09:45:17 +00:00
|
|
|
|
|
|
|
return res;
|
2009-08-28 10:43:43 +00:00
|
|
|
}
|
2009-08-31 09:45:17 +00:00
|
|
|
#else
|
|
|
|
/* count leading zeros */
|
2009-08-28 11:45:38 +00:00
|
|
|
static inline guint
|
2009-08-28 10:33:37 +00:00
|
|
|
gst_util_clz (guint32 val)
|
2009-08-11 07:10:47 +00:00
|
|
|
{
|
2009-08-12 09:10:05 +00:00
|
|
|
guint s;
|
|
|
|
|
2009-08-28 10:33:37 +00:00
|
|
|
s = val | (val >> 1);
|
2009-08-12 09:10:05 +00:00
|
|
|
s |= (s >> 2);
|
|
|
|
s |= (s >> 4);
|
|
|
|
s |= (s >> 8);
|
|
|
|
s = ~(s | (s >> 16));
|
|
|
|
s = s - ((s >> 1) & 0x55555555);
|
|
|
|
s = (s & 0x33333333) + ((s >> 2) & 0x33333333);
|
|
|
|
s = (s + (s >> 4)) & 0x0f0f0f0f;
|
|
|
|
s += (s >> 8);
|
|
|
|
s = (s + (s >> 16)) & 0x3f;
|
|
|
|
|
2009-08-28 10:33:37 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* based on Hacker's Delight p152 */
|
2009-08-28 11:45:38 +00:00
|
|
|
static inline guint64
|
2009-08-28 10:33:37 +00:00
|
|
|
gst_util_div128_64 (GstUInt64 c1, GstUInt64 c0, guint64 denom)
|
|
|
|
{
|
|
|
|
GstUInt64 q1, q0, rhat;
|
|
|
|
GstUInt64 v, cmp1, cmp2;
|
|
|
|
guint s;
|
|
|
|
|
|
|
|
v.ll = denom;
|
|
|
|
|
|
|
|
/* count number of leading zeroes, we know they must be in the high
|
|
|
|
* part of denom since denom > G_MAXUINT32. */
|
|
|
|
s = gst_util_clz (v.l.high);
|
|
|
|
|
2010-12-26 21:20:31 +00:00
|
|
|
if (s > 0) {
|
2009-08-12 09:10:05 +00:00
|
|
|
/* normalize divisor and dividend */
|
|
|
|
v.ll <<= s;
|
|
|
|
c1.ll = (c1.ll << s) | (c0.l.high >> (32 - s));
|
|
|
|
c0.ll <<= s;
|
2005-11-25 00:02:05 +00:00
|
|
|
}
|
|
|
|
|
2009-08-12 09:10:05 +00:00
|
|
|
q1.ll = c1.ll / v.l.high;
|
|
|
|
rhat.ll = c1.ll - q1.ll * v.l.high;
|
2009-08-11 07:10:47 +00:00
|
|
|
|
2009-08-12 09:10:05 +00:00
|
|
|
cmp1.l.high = rhat.l.low;
|
|
|
|
cmp1.l.low = c0.l.high;
|
|
|
|
cmp2.ll = q1.ll * v.l.low;
|
2009-08-11 07:16:38 +00:00
|
|
|
|
2009-08-12 09:10:05 +00:00
|
|
|
while (q1.l.high || cmp2.ll > cmp1.ll) {
|
|
|
|
q1.ll--;
|
|
|
|
rhat.ll += v.l.high;
|
|
|
|
if (rhat.l.high)
|
|
|
|
break;
|
|
|
|
cmp1.l.high = rhat.l.low;
|
|
|
|
cmp2.ll -= v.l.low;
|
|
|
|
}
|
|
|
|
c1.l.high = c1.l.low;
|
|
|
|
c1.l.low = c0.l.high;
|
|
|
|
c1.ll -= q1.ll * v.ll;
|
|
|
|
q0.ll = c1.ll / v.l.high;
|
|
|
|
rhat.ll = c1.ll - q0.ll * v.l.high;
|
|
|
|
|
|
|
|
cmp1.l.high = rhat.l.low;
|
|
|
|
cmp1.l.low = c0.l.low;
|
|
|
|
cmp2.ll = q0.ll * v.l.low;
|
|
|
|
|
|
|
|
while (q0.l.high || cmp2.ll > cmp1.ll) {
|
|
|
|
q0.ll--;
|
|
|
|
rhat.ll += v.l.high;
|
|
|
|
if (rhat.l.high)
|
|
|
|
break;
|
|
|
|
cmp1.l.high = rhat.l.low;
|
|
|
|
cmp2.ll -= v.l.low;
|
2005-11-25 00:02:05 +00:00
|
|
|
}
|
2009-08-12 09:10:05 +00:00
|
|
|
q0.l.high += q1.l.low;
|
2009-08-11 07:10:47 +00:00
|
|
|
|
2009-08-12 09:10:05 +00:00
|
|
|
return q0.ll;
|
2005-11-25 00:02:05 +00:00
|
|
|
}
|
2009-08-31 09:45:17 +00:00
|
|
|
#endif /* defined (__GNUC__) */
|
2009-06-08 14:39:59 +00:00
|
|
|
|
2009-09-09 16:38:29 +00:00
|
|
|
/* This always gives the correct result because:
|
|
|
|
* a) val <= G_MAXUINT64-1
|
|
|
|
* b) (c0,c1) <= G_MAXUINT64 * (G_MAXUINT64-1)
|
|
|
|
* or
|
|
|
|
* (c0,c1) == G_MAXUINT64 * G_MAXUINT64 and denom < G_MAXUINT64
|
|
|
|
* (note: num==denom case is handled by short path)
|
|
|
|
* This means that (c0,c1) either has enough space for val
|
|
|
|
* or that the overall result will overflow anyway.
|
|
|
|
*/
|
|
|
|
|
2009-08-28 10:19:34 +00:00
|
|
|
/* add correction with carry */
|
|
|
|
#define CORRECT(c0,c1,val) \
|
|
|
|
if (val) { \
|
|
|
|
if (G_MAXUINT64 - c0.ll < val) { \
|
|
|
|
if (G_UNLIKELY (c1.ll == G_MAXUINT64)) \
|
|
|
|
/* overflow */ \
|
|
|
|
return G_MAXUINT64; \
|
|
|
|
c1.ll++; \
|
|
|
|
} \
|
|
|
|
c0.ll += val; \
|
|
|
|
}
|
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
static guint64
|
2009-08-13 14:10:31 +00:00
|
|
|
gst_util_uint64_scale_uint64_unchecked (guint64 val, guint64 num,
|
2009-08-28 10:30:41 +00:00
|
|
|
guint64 denom, guint64 correct)
|
2009-08-11 07:10:47 +00:00
|
|
|
{
|
2009-08-11 07:16:38 +00:00
|
|
|
GstUInt64 c1, c0;
|
2009-06-08 14:39:59 +00:00
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
/* compute 128-bit numerator product */
|
2009-08-11 07:16:38 +00:00
|
|
|
gst_util_uint64_mul_uint64 (&c1, &c0, val, num);
|
2009-06-08 14:39:59 +00:00
|
|
|
|
2009-08-28 10:30:41 +00:00
|
|
|
/* perform rounding correction */
|
|
|
|
CORRECT (c0, c1, correct);
|
2009-08-13 14:10:31 +00:00
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
/* high word as big as or bigger than denom --> overflow */
|
2009-08-11 07:16:38 +00:00
|
|
|
if (G_UNLIKELY (c1.ll >= denom))
|
2009-06-08 14:39:59 +00:00
|
|
|
return G_MAXUINT64;
|
2009-08-11 07:10:47 +00:00
|
|
|
|
|
|
|
/* compute quotient, fits in 64 bits */
|
2009-08-12 09:10:05 +00:00
|
|
|
return gst_util_div128_64 (c1, c0, denom);
|
2009-06-08 14:39:59 +00:00
|
|
|
}
|
2009-09-09 12:53:16 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
#define GST_MAXUINT128 ((__uint128_t) -1)
|
|
|
|
static guint64
|
|
|
|
gst_util_uint64_scale_uint64_unchecked (guint64 val, guint64 num,
|
|
|
|
guint64 denom, guint64 correct)
|
|
|
|
{
|
|
|
|
__uint128_t tmp;
|
|
|
|
|
|
|
|
/* Calculate val * num */
|
|
|
|
tmp = ((__uint128_t) val) * ((__uint128_t) num);
|
|
|
|
|
|
|
|
/* overflow checks */
|
|
|
|
if (G_UNLIKELY (GST_MAXUINT128 - correct < tmp))
|
|
|
|
return G_MAXUINT64;
|
|
|
|
|
|
|
|
/* perform rounding correction */
|
|
|
|
tmp += correct;
|
|
|
|
|
|
|
|
/* Divide by denom */
|
|
|
|
tmp /= denom;
|
|
|
|
|
|
|
|
/* if larger than G_MAXUINT64 --> overflow */
|
|
|
|
if (G_UNLIKELY (tmp > G_MAXUINT64))
|
|
|
|
return G_MAXUINT64;
|
|
|
|
|
|
|
|
/* compute quotient, fits in 64 bits */
|
|
|
|
return (guint64) tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2009-06-08 14:39:59 +00:00
|
|
|
|
2009-09-09 12:53:16 +00:00
|
|
|
#if !defined (__x86_64__) && !defined (HAVE_UINT128_T)
|
2009-08-31 09:45:17 +00:00
|
|
|
static inline void
|
|
|
|
gst_util_uint64_mul_uint32 (GstUInt64 * c1, GstUInt64 * c0, guint64 arg1,
|
|
|
|
guint32 arg2)
|
|
|
|
{
|
|
|
|
GstUInt64 a;
|
|
|
|
|
|
|
|
a.ll = arg1;
|
|
|
|
|
|
|
|
c0->ll = (guint64) a.l.low * arg2;
|
|
|
|
c1->ll = (guint64) a.l.high * arg2 + c0->l.high;
|
|
|
|
c0->l.high = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* divide a 96-bit unsigned int by a 32-bit unsigned int when we know the
|
|
|
|
* quotient fits into 64 bits. the high 64 bits and low 32 bits of the
|
|
|
|
* numerator are expected in c1 and c0 respectively. */
|
|
|
|
static inline guint64
|
|
|
|
gst_util_div96_32 (guint64 c1, guint64 c0, guint32 denom)
|
|
|
|
{
|
|
|
|
c0 += (c1 % denom) << 32;
|
|
|
|
return ((c1 / denom) << 32) + (c0 / denom);
|
|
|
|
}
|
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
static inline guint64
|
2009-08-13 14:10:31 +00:00
|
|
|
gst_util_uint64_scale_uint32_unchecked (guint64 val, guint32 num,
|
2009-08-28 10:30:41 +00:00
|
|
|
guint32 denom, guint32 correct)
|
2009-08-11 07:10:47 +00:00
|
|
|
{
|
|
|
|
GstUInt64 c1, c0;
|
|
|
|
|
|
|
|
/* compute 96-bit numerator product */
|
|
|
|
gst_util_uint64_mul_uint32 (&c1, &c0, val, num);
|
|
|
|
|
2009-08-13 14:10:31 +00:00
|
|
|
/* condition numerator based on rounding mode */
|
2009-08-28 10:30:41 +00:00
|
|
|
CORRECT (c0, c1, correct);
|
2009-08-13 14:10:31 +00:00
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
/* high 32 bits as big as or bigger than denom --> overflow */
|
|
|
|
if (G_UNLIKELY (c1.l.high >= denom))
|
|
|
|
return G_MAXUINT64;
|
|
|
|
|
|
|
|
/* compute quotient, fits in 64 bits */
|
2009-08-12 09:10:05 +00:00
|
|
|
return gst_util_div96_32 (c1.ll, c0.ll, denom);
|
2009-08-11 07:10:47 +00:00
|
|
|
}
|
2009-08-31 09:45:17 +00:00
|
|
|
#endif
|
2009-06-08 14:39:59 +00:00
|
|
|
|
2009-08-13 14:10:31 +00:00
|
|
|
/* the guts of the gst_util_uint64_scale() variants */
|
|
|
|
static guint64
|
|
|
|
_gst_util_uint64_scale (guint64 val, guint64 num, guint64 denom,
|
2009-08-28 10:30:41 +00:00
|
|
|
guint64 correct)
|
2005-08-29 16:10:36 +00:00
|
|
|
{
|
2005-11-24 18:03:15 +00:00
|
|
|
g_return_val_if_fail (denom != 0, G_MAXUINT64);
|
|
|
|
|
2009-06-08 14:39:59 +00:00
|
|
|
if (G_UNLIKELY (num == 0))
|
2005-11-28 16:05:35 +00:00
|
|
|
return 0;
|
|
|
|
|
2009-06-08 14:39:59 +00:00
|
|
|
if (G_UNLIKELY (num == denom))
|
2005-11-28 18:44:11 +00:00
|
|
|
return val;
|
|
|
|
|
2011-09-07 11:14:38 +00:00
|
|
|
/* on 64bits we always use a full 128bits multiply/division */
|
2009-09-09 12:53:16 +00:00
|
|
|
#if !defined (__x86_64__) && !defined (HAVE_UINT128_T)
|
2009-08-12 09:10:05 +00:00
|
|
|
/* denom is low --> try to use 96 bit muldiv */
|
2009-08-11 07:10:47 +00:00
|
|
|
if (G_LIKELY (denom <= G_MAXUINT32)) {
|
|
|
|
/* num is low --> use 96 bit muldiv */
|
|
|
|
if (G_LIKELY (num <= G_MAXUINT32))
|
|
|
|
return gst_util_uint64_scale_uint32_unchecked (val, (guint32) num,
|
2009-08-28 10:30:41 +00:00
|
|
|
(guint32) denom, correct);
|
2009-08-11 07:10:47 +00:00
|
|
|
|
|
|
|
/* num is high but val is low --> swap and use 96-bit muldiv */
|
|
|
|
if (G_LIKELY (val <= G_MAXUINT32))
|
|
|
|
return gst_util_uint64_scale_uint32_unchecked (num, (guint32) val,
|
2009-08-28 10:30:41 +00:00
|
|
|
(guint32) denom, correct);
|
2009-08-11 07:10:47 +00:00
|
|
|
}
|
2009-09-09 12:53:16 +00:00
|
|
|
#endif /* !defined (__x86_64__) && !defined (HAVE_UINT128_T) */
|
2005-11-24 18:03:15 +00:00
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
/* val is high and num is high --> use 128-bit muldiv */
|
2009-08-28 10:30:41 +00:00
|
|
|
return gst_util_uint64_scale_uint64_unchecked (val, num, denom, correct);
|
2005-08-29 16:10:36 +00:00
|
|
|
}
|
|
|
|
|
2005-11-22 15:15:53 +00:00
|
|
|
/**
|
2009-08-13 14:10:31 +00:00
|
|
|
* gst_util_uint64_scale:
|
|
|
|
* @val: the number to scale
|
|
|
|
* @num: the numerator of the scale ratio
|
|
|
|
* @denom: the denominator of the scale ratio
|
2005-11-22 15:15:53 +00:00
|
|
|
*
|
2009-08-11 07:10:47 +00:00
|
|
|
* Scale @val by the rational number @num / @denom, avoiding overflows and
|
2009-08-13 14:10:31 +00:00
|
|
|
* underflows and without loss of precision.
|
|
|
|
*
|
|
|
|
* This function can potentially be very slow if val and num are both
|
|
|
|
* greater than G_MAXUINT32.
|
2005-11-24 17:44:57 +00:00
|
|
|
*
|
2009-08-11 07:10:47 +00:00
|
|
|
* Returns: @val * @num / @denom. In the case of an overflow, this
|
2009-08-13 14:10:31 +00:00
|
|
|
* function returns G_MAXUINT64. If the result is not exactly
|
|
|
|
* representable as an integer it is truncated. See also
|
|
|
|
* gst_util_uint64_scale_round(), gst_util_uint64_scale_ceil(),
|
|
|
|
* gst_util_uint64_scale_int(), gst_util_uint64_scale_int_round(),
|
|
|
|
* gst_util_uint64_scale_int_ceil().
|
2005-11-22 15:15:53 +00:00
|
|
|
*/
|
2005-11-23 13:22:21 +00:00
|
|
|
guint64
|
2009-08-13 14:10:31 +00:00
|
|
|
gst_util_uint64_scale (guint64 val, guint64 num, guint64 denom)
|
|
|
|
{
|
2009-08-28 10:30:41 +00:00
|
|
|
return _gst_util_uint64_scale (val, num, denom, 0);
|
2009-08-13 14:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_uint64_scale_round:
|
|
|
|
* @val: the number to scale
|
|
|
|
* @num: the numerator of the scale ratio
|
|
|
|
* @denom: the denominator of the scale ratio
|
|
|
|
*
|
|
|
|
* Scale @val by the rational number @num / @denom, avoiding overflows and
|
|
|
|
* underflows and without loss of precision.
|
|
|
|
*
|
|
|
|
* This function can potentially be very slow if val and num are both
|
|
|
|
* greater than G_MAXUINT32.
|
|
|
|
*
|
|
|
|
* Returns: @val * @num / @denom. In the case of an overflow, this
|
|
|
|
* function returns G_MAXUINT64. If the result is not exactly
|
|
|
|
* representable as an integer, it is rounded to the nearest integer
|
|
|
|
* (half-way cases are rounded up). See also gst_util_uint64_scale(),
|
|
|
|
* gst_util_uint64_scale_ceil(), gst_util_uint64_scale_int(),
|
|
|
|
* gst_util_uint64_scale_int_round(), gst_util_uint64_scale_int_ceil().
|
|
|
|
*/
|
|
|
|
guint64
|
|
|
|
gst_util_uint64_scale_round (guint64 val, guint64 num, guint64 denom)
|
|
|
|
{
|
2009-08-28 13:32:26 +00:00
|
|
|
return _gst_util_uint64_scale (val, num, denom, denom >> 1);
|
2009-08-13 14:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_uint64_scale_ceil:
|
|
|
|
* @val: the number to scale
|
|
|
|
* @num: the numerator of the scale ratio
|
|
|
|
* @denom: the denominator of the scale ratio
|
|
|
|
*
|
|
|
|
* Scale @val by the rational number @num / @denom, avoiding overflows and
|
|
|
|
* underflows and without loss of precision.
|
|
|
|
*
|
|
|
|
* This function can potentially be very slow if val and num are both
|
|
|
|
* greater than G_MAXUINT32.
|
|
|
|
*
|
|
|
|
* Returns: @val * @num / @denom. In the case of an overflow, this
|
|
|
|
* function returns G_MAXUINT64. If the result is not exactly
|
|
|
|
* representable as an integer, it is rounded up. See also
|
|
|
|
* gst_util_uint64_scale(), gst_util_uint64_scale_round(),
|
|
|
|
* gst_util_uint64_scale_int(), gst_util_uint64_scale_int_round(),
|
|
|
|
* gst_util_uint64_scale_int_ceil().
|
|
|
|
*/
|
|
|
|
guint64
|
|
|
|
gst_util_uint64_scale_ceil (guint64 val, guint64 num, guint64 denom)
|
|
|
|
{
|
2009-08-28 10:30:41 +00:00
|
|
|
return _gst_util_uint64_scale (val, num, denom, denom - 1);
|
2009-08-13 14:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* the guts of the gst_util_uint64_scale_int() variants */
|
|
|
|
static guint64
|
2009-08-28 10:30:41 +00:00
|
|
|
_gst_util_uint64_scale_int (guint64 val, gint num, gint denom, gint correct)
|
2005-11-22 15:15:53 +00:00
|
|
|
{
|
2005-11-24 17:44:57 +00:00
|
|
|
g_return_val_if_fail (denom > 0, G_MAXUINT64);
|
|
|
|
g_return_val_if_fail (num >= 0, G_MAXUINT64);
|
|
|
|
|
2009-06-08 14:39:59 +00:00
|
|
|
if (G_UNLIKELY (num == 0))
|
2005-11-28 16:05:35 +00:00
|
|
|
return 0;
|
|
|
|
|
2009-06-08 14:39:59 +00:00
|
|
|
if (G_UNLIKELY (num == denom))
|
2005-11-28 18:44:11 +00:00
|
|
|
return val;
|
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
if (val <= G_MAXUINT32) {
|
2009-08-13 14:10:31 +00:00
|
|
|
/* simple case. num and denom are not negative so casts are OK. when
|
|
|
|
* not truncating, the additions to the numerator cannot overflow
|
|
|
|
* because val*num <= G_MAXUINT32 * G_MAXINT32 < G_MAXUINT64 -
|
|
|
|
* G_MAXINT32, so there's room to add another gint32. */
|
2009-08-11 07:10:47 +00:00
|
|
|
val *= (guint64) num;
|
2009-08-28 10:30:41 +00:00
|
|
|
/* add rounding correction */
|
|
|
|
val += correct;
|
|
|
|
|
2009-08-11 07:10:47 +00:00
|
|
|
return val / (guint64) denom;
|
|
|
|
}
|
2009-09-09 12:53:16 +00:00
|
|
|
#if !defined (__x86_64__) && !defined (HAVE_UINT128_T)
|
2009-08-11 07:10:47 +00:00
|
|
|
/* num and denom are not negative so casts are OK */
|
|
|
|
return gst_util_uint64_scale_uint32_unchecked (val, (guint32) num,
|
2009-08-28 10:30:41 +00:00
|
|
|
(guint32) denom, (guint32) correct);
|
2009-08-31 09:45:17 +00:00
|
|
|
#else
|
|
|
|
/* always use full 128bits scale */
|
|
|
|
return gst_util_uint64_scale_uint64_unchecked (val, num, denom, correct);
|
|
|
|
#endif
|
2009-08-13 14:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_uint64_scale_int:
|
|
|
|
* @val: guint64 (such as a #GstClockTime) to scale.
|
|
|
|
* @num: numerator of the scale factor.
|
|
|
|
* @denom: denominator of the scale factor.
|
|
|
|
*
|
|
|
|
* Scale @val by the rational number @num / @denom, avoiding overflows and
|
|
|
|
* underflows and without loss of precision. @num must be non-negative and
|
|
|
|
* @denom must be positive.
|
|
|
|
*
|
|
|
|
* Returns: @val * @num / @denom. In the case of an overflow, this
|
|
|
|
* function returns G_MAXUINT64. If the result is not exactly
|
|
|
|
* representable as an integer, it is truncated. See also
|
|
|
|
* gst_util_uint64_scale_int_round(), gst_util_uint64_scale_int_ceil(),
|
|
|
|
* gst_util_uint64_scale(), gst_util_uint64_scale_round(),
|
|
|
|
* gst_util_uint64_scale_ceil().
|
|
|
|
*/
|
|
|
|
guint64
|
|
|
|
gst_util_uint64_scale_int (guint64 val, gint num, gint denom)
|
|
|
|
{
|
2009-08-28 10:30:41 +00:00
|
|
|
return _gst_util_uint64_scale_int (val, num, denom, 0);
|
2009-08-13 14:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_uint64_scale_int_round:
|
|
|
|
* @val: guint64 (such as a #GstClockTime) to scale.
|
|
|
|
* @num: numerator of the scale factor.
|
|
|
|
* @denom: denominator of the scale factor.
|
|
|
|
*
|
|
|
|
* Scale @val by the rational number @num / @denom, avoiding overflows and
|
|
|
|
* underflows and without loss of precision. @num must be non-negative and
|
|
|
|
* @denom must be positive.
|
|
|
|
*
|
|
|
|
* Returns: @val * @num / @denom. In the case of an overflow, this
|
|
|
|
* function returns G_MAXUINT64. If the result is not exactly
|
|
|
|
* representable as an integer, it is rounded to the nearest integer
|
|
|
|
* (half-way cases are rounded up). See also gst_util_uint64_scale_int(),
|
|
|
|
* gst_util_uint64_scale_int_ceil(), gst_util_uint64_scale(),
|
|
|
|
* gst_util_uint64_scale_round(), gst_util_uint64_scale_ceil().
|
|
|
|
*/
|
|
|
|
guint64
|
|
|
|
gst_util_uint64_scale_int_round (guint64 val, gint num, gint denom)
|
|
|
|
{
|
2009-08-28 13:32:26 +00:00
|
|
|
/* we can use a shift to divide by 2 because denom is required to be
|
|
|
|
* positive. */
|
|
|
|
return _gst_util_uint64_scale_int (val, num, denom, denom >> 1);
|
2009-08-13 14:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_uint64_scale_int_ceil:
|
|
|
|
* @val: guint64 (such as a #GstClockTime) to scale.
|
|
|
|
* @num: numerator of the scale factor.
|
|
|
|
* @denom: denominator of the scale factor.
|
|
|
|
*
|
|
|
|
* Scale @val by the rational number @num / @denom, avoiding overflows and
|
|
|
|
* underflows and without loss of precision. @num must be non-negative and
|
|
|
|
* @denom must be positive.
|
|
|
|
*
|
|
|
|
* Returns: @val * @num / @denom. In the case of an overflow, this
|
|
|
|
* function returns G_MAXUINT64. If the result is not exactly
|
|
|
|
* representable as an integer, it is rounded up. See also
|
|
|
|
* gst_util_uint64_scale_int(), gst_util_uint64_scale_int_round(),
|
|
|
|
* gst_util_uint64_scale(), gst_util_uint64_scale_round(),
|
|
|
|
* gst_util_uint64_scale_ceil().
|
|
|
|
*/
|
|
|
|
guint64
|
|
|
|
gst_util_uint64_scale_int_ceil (guint64 val, gint num, gint denom)
|
|
|
|
{
|
2009-08-28 10:30:41 +00:00
|
|
|
return _gst_util_uint64_scale_int (val, num, denom, denom - 1);
|
2005-11-22 15:15:53 +00:00
|
|
|
}
|
|
|
|
|
2008-11-04 12:22:53 +00:00
|
|
|
/**
|
|
|
|
* gst_util_seqnum_next:
|
|
|
|
*
|
|
|
|
* Return a constantly incrementing sequence number.
|
|
|
|
*
|
|
|
|
* This function is used internally to GStreamer to be able to determine which
|
|
|
|
* events and messages are "the same". For example, elements may set the seqnum
|
|
|
|
* on a segment-done message to be the same as that of the last seek event, to
|
|
|
|
* indicate that event and the message correspond to the same segment.
|
|
|
|
*
|
|
|
|
* Returns: A constantly incrementing 32-bit unsigned integer, which might
|
|
|
|
* overflow back to 0 at some point. Use gst_util_seqnum_compare() to make sure
|
|
|
|
* you handle wraparound correctly.
|
|
|
|
*
|
|
|
|
* Since: 0.10.22
|
|
|
|
*/
|
|
|
|
guint32
|
|
|
|
gst_util_seqnum_next (void)
|
|
|
|
{
|
2008-11-04 13:56:37 +00:00
|
|
|
static gint counter = 0;
|
2011-06-04 07:30:15 +00:00
|
|
|
return G_ATOMIC_INT_ADD (&counter, 1);
|
2008-11-04 12:22:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_seqnum_compare:
|
|
|
|
* @s1: A sequence number.
|
|
|
|
* @s2: Another sequence number.
|
|
|
|
*
|
|
|
|
* Compare two sequence numbers, handling wraparound.
|
2009-08-28 10:21:28 +00:00
|
|
|
*
|
2008-11-04 12:22:53 +00:00
|
|
|
* The current implementation just returns (gint32)(@s1 - @s2).
|
|
|
|
*
|
|
|
|
* Returns: A negative number if @s1 is before @s2, 0 if they are equal, or a
|
|
|
|
* positive number if @s1 is after @s2.
|
|
|
|
*
|
|
|
|
* Since: 0.10.22
|
|
|
|
*/
|
|
|
|
gint32
|
|
|
|
gst_util_seqnum_compare (guint32 s1, guint32 s2)
|
|
|
|
{
|
|
|
|
return (gint32) (s1 - s2);
|
|
|
|
}
|
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* -----------------------------------------------------
|
|
|
|
*
|
|
|
|
* The following code will be moved out of the main
|
|
|
|
* gstreamer library someday.
|
|
|
|
*/
|
2001-09-17 23:44:07 +00:00
|
|
|
|
|
|
|
#include "gstpad.h"
|
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
static void
|
|
|
|
string_append_indent (GString * str, gint count)
|
2001-09-17 23:44:07 +00:00
|
|
|
{
|
|
|
|
gint xx;
|
2001-10-21 18:00:31 +00:00
|
|
|
|
|
|
|
for (xx = 0; xx < count; xx++)
|
2001-09-17 23:44:07 +00:00
|
|
|
g_string_append_c (str, ' ');
|
|
|
|
}
|
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
/**
|
|
|
|
* gst_print_pad_caps:
|
|
|
|
* @buf: the buffer to print the caps in
|
|
|
|
* @indent: initial indentation
|
2010-12-07 18:35:04 +00:00
|
|
|
* @pad: (transfer none): the pad to print the caps from
|
2001-10-21 18:00:31 +00:00
|
|
|
*
|
|
|
|
* Write the pad capabilities in a human readable format into
|
|
|
|
* the given GString.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_print_pad_caps (GString * buf, gint indent, GstPad * pad)
|
2001-09-17 23:44:07 +00:00
|
|
|
{
|
|
|
|
GstCaps *caps;
|
|
|
|
|
2011-05-09 08:54:10 +00:00
|
|
|
caps = gst_pad_get_current_caps (pad);
|
2001-09-17 23:44:07 +00:00
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
if (!caps) {
|
|
|
|
string_append_indent (buf, indent);
|
2004-03-13 15:27:01 +00:00
|
|
|
g_string_printf (buf, "%s:%s has no capabilities",
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_DEBUG_PAD_NAME (pad));
|
2004-03-13 15:27:01 +00:00
|
|
|
} else {
|
2003-12-22 01:39:35 +00:00
|
|
|
char *s;
|
2001-09-17 23:44:07 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
s = gst_caps_to_string (caps);
|
|
|
|
g_string_append (buf, s);
|
|
|
|
g_free (s);
|
2011-05-09 08:54:10 +00:00
|
|
|
|
|
|
|
gst_caps_unref (caps);
|
2001-10-21 18:00:31 +00:00
|
|
|
}
|
2001-09-17 23:44:07 +00:00
|
|
|
}
|
2001-09-18 04:20:04 +00:00
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
/**
|
|
|
|
* gst_print_element_args:
|
|
|
|
* @buf: the buffer to print the args in
|
|
|
|
* @indent: initial indentation
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element: (transfer none): the element to print the args of
|
2001-10-21 18:00:31 +00:00
|
|
|
*
|
|
|
|
* Print the element argument in a human readable format in the given
|
|
|
|
* GString.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_print_element_args (GString * buf, gint indent, GstElement * element)
|
2001-09-18 04:20:04 +00:00
|
|
|
{
|
|
|
|
guint width;
|
2004-03-15 19:27:17 +00:00
|
|
|
GValue value = { 0, }; /* the important thing is that value.type = 0 */
|
gst/: Aplied part of patch #157127: Cleanup of issues reported by sparse.
Original commit message from CVS:
reviewed by: Wim Taymans, Ronald Bultje.
* gst/cothreads.c: (cothread_create):
* gst/gstbin.c: (gst_bin_add_func), (gst_bin_remove_func),
(gst_bin_child_state_change_func):
* gst/gstbuffer.c: (gst_buffer_span):
* gst/gstelement.c: (gst_element_get_index),
(gst_element_get_event_masks), (gst_element_get_query_types),
(gst_element_get_formats):
* gst/gsterror.c: (_gst_core_errors_init),
(_gst_library_errors_init), (_gst_resource_errors_init),
(_gst_stream_errors_init):
* gst/gstobject.c: (gst_object_default_deep_notify):
* gst/gstpad.c: (gst_pad_get_event_masks),
(gst_pad_get_internal_links_default):
* gst/gstplugin.c: (gst_plugin_register_func),
(gst_plugin_get_module):
* gst/gststructure.c: (gst_structure_get_string),
(gst_structure_get_abbrs), (gst_structure_from_abbr),
(gst_structure_to_abbr):
* gst/gstutils.c: (gst_print_element_args):
* gst/schedulers/gstoptimalscheduler.c: (add_to_group),
(setup_group_scheduler), (gst_opt_scheduler_iterate):
Aplied part of patch #157127: Cleanup of issues reported by
sparse.
Also do not try to use cothreads when there is no cothread
context yet.
2004-11-02 15:02:12 +00:00
|
|
|
gchar *str = NULL;
|
2002-02-06 16:35:16 +00:00
|
|
|
GParamSpec *spec, **specs, **walk;
|
2001-09-18 04:20:04 +00:00
|
|
|
|
2002-02-06 16:35:16 +00:00
|
|
|
specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element), NULL);
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
width = 0;
|
2002-02-06 16:35:16 +00:00
|
|
|
for (walk = specs; *walk; walk++) {
|
|
|
|
spec = *walk;
|
|
|
|
if (width < strlen (spec->name))
|
|
|
|
width = strlen (spec->name);
|
2001-09-18 04:20:04 +00:00
|
|
|
}
|
|
|
|
|
2002-02-06 16:35:16 +00:00
|
|
|
for (walk = specs; *walk; walk++) {
|
|
|
|
spec = *walk;
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2002-02-06 16:35:16 +00:00
|
|
|
if (spec->flags & G_PARAM_READABLE) {
|
2009-12-28 16:25:20 +00:00
|
|
|
g_value_init (&value, spec->value_type);
|
2002-02-06 16:35:16 +00:00
|
|
|
g_object_get_property (G_OBJECT (element), spec->name, &value);
|
|
|
|
str = g_strdup_value_contents (&value);
|
2004-03-13 15:27:01 +00:00
|
|
|
g_value_unset (&value);
|
2002-02-06 16:35:16 +00:00
|
|
|
} else {
|
|
|
|
str = g_strdup ("Parameter not readable.");
|
2001-10-21 18:00:31 +00:00
|
|
|
}
|
2001-09-18 04:20:04 +00:00
|
|
|
|
2002-02-06 16:35:16 +00:00
|
|
|
string_append_indent (buf, indent);
|
|
|
|
g_string_append (buf, spec->name);
|
|
|
|
string_append_indent (buf, 2 + width - strlen (spec->name));
|
|
|
|
g_string_append (buf, str);
|
2001-09-18 04:20:04 +00:00
|
|
|
g_string_append_c (buf, '\n');
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2002-02-06 16:35:16 +00:00
|
|
|
g_free (str);
|
2001-09-18 04:20:04 +00:00
|
|
|
}
|
2002-02-06 16:35:16 +00:00
|
|
|
|
|
|
|
g_free (specs);
|
2001-09-18 04:20:04 +00:00
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2005-04-23 23:29:47 +00:00
|
|
|
/**
|
|
|
|
* gst_element_create_all_pads:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element: (transfer none): a #GstElement to create pads for
|
2005-04-23 23:29:47 +00:00
|
|
|
*
|
|
|
|
* Creates a pad for each pad template that is always available.
|
2011-09-07 11:14:38 +00:00
|
|
|
* This function is only useful during object initialization of
|
2005-04-23 23:29:47 +00:00
|
|
|
* subclasses of #GstElement.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_element_create_all_pads (GstElement * element)
|
|
|
|
{
|
|
|
|
GList *padlist;
|
|
|
|
|
|
|
|
/* FIXME: lock element */
|
|
|
|
|
|
|
|
padlist =
|
|
|
|
gst_element_class_get_pad_template_list (GST_ELEMENT_CLASS
|
|
|
|
(G_OBJECT_GET_CLASS (element)));
|
|
|
|
|
|
|
|
while (padlist) {
|
|
|
|
GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
|
|
|
|
|
|
|
|
if (padtempl->presence == GST_PAD_ALWAYS) {
|
|
|
|
GstPad *pad;
|
|
|
|
|
|
|
|
pad = gst_pad_new_from_template (padtempl, padtempl->name_template);
|
|
|
|
|
|
|
|
gst_element_add_pad (element, pad);
|
|
|
|
}
|
2005-04-24 21:16:45 +00:00
|
|
|
padlist = padlist->next;
|
2005-04-23 23:29:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/**
|
|
|
|
* gst_element_get_compatible_pad_template:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element: (transfer none): a #GstElement to get a compatible pad template for
|
|
|
|
* @compattempl: (transfer none): the #GstPadTemplate to find a compatible
|
|
|
|
* template for
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Retrieves a pad template from @element that is compatible with @compattempl.
|
|
|
|
* Pads from compatible templates can be linked together.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Returns: (transfer none): a compatible #GstPadTemplate, or NULL if none
|
|
|
|
* was found. No unreferencing is necessary.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
GstPadTemplate *
|
|
|
|
gst_element_get_compatible_pad_template (GstElement * element,
|
|
|
|
GstPadTemplate * compattempl)
|
|
|
|
{
|
|
|
|
GstPadTemplate *newtempl = NULL;
|
|
|
|
GList *padlist;
|
|
|
|
GstElementClass *class;
|
2009-07-22 08:24:59 +00:00
|
|
|
gboolean compatible;
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (element != NULL, NULL);
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
|
|
|
g_return_val_if_fail (compattempl != NULL, NULL);
|
|
|
|
|
|
|
|
class = GST_ELEMENT_GET_CLASS (element);
|
|
|
|
|
|
|
|
padlist = gst_element_class_get_pad_template_list (class);
|
|
|
|
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"Looking for a suitable pad template in %s out of %d templates...",
|
|
|
|
GST_ELEMENT_NAME (element), g_list_length (padlist));
|
|
|
|
|
|
|
|
while (padlist) {
|
|
|
|
GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
|
|
|
|
|
|
|
|
/* Ignore name
|
|
|
|
* Ignore presence
|
|
|
|
* Check direction (must be opposite)
|
|
|
|
* Check caps
|
|
|
|
*/
|
|
|
|
GST_CAT_LOG (GST_CAT_CAPS,
|
|
|
|
"checking pad template %s", padtempl->name_template);
|
|
|
|
if (padtempl->direction != compattempl->direction) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_CAPS,
|
|
|
|
"compatible direction: found %s pad template \"%s\"",
|
|
|
|
padtempl->direction == GST_PAD_SRC ? "src" : "sink",
|
|
|
|
padtempl->name_template);
|
|
|
|
|
gst/: Fix name lookup in GstBin.
Original commit message from CVS:
* gst/gstbin.c: (gst_bin_send_event), (compare_name),
(gst_bin_get_by_name):
* gst/gstbuffer.h:
* gst/gstclock.c: (gst_clock_entry_new), (gst_clock_class_init),
(gst_clock_finalize):
* gst/gstdata.c: (gst_data_replace):
* gst/gstdata.h:
* gst/gstelement.c: (gst_element_request_pad),
(gst_element_pads_activate):
* gst/gstobject.c: (gst_object_init), (gst_object_ref),
(gst_object_unref):
* gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
(gst_pad_set_checkgetrange_function),
(gst_pad_link_check_compatible_unlocked), (gst_pad_set_caps),
(gst_pad_check_pull_range), (gst_pad_pull_range),
(gst_static_pad_template_get_caps), (gst_pad_start_task),
(gst_pad_pause_task), (gst_pad_stop_task):
* gst/gstutils.c: (gst_element_get_compatible_pad_template),
(gst_element_request_pad), (gst_pad_proxy_getcaps):
Fix name lookup in GstBin.
Added _data_replace() function and _buffer_replace()
Use finalize method to clean up clock.
Fix refcounting on request pads.
Fix pad schedule mode error.
Some more object refcounting debug info,
2005-05-05 09:28:01 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_CAPS,
|
|
|
|
"intersecting %" GST_PTR_FORMAT, GST_PAD_TEMPLATE_CAPS (compattempl));
|
|
|
|
GST_CAT_DEBUG (GST_CAT_CAPS,
|
|
|
|
"..and %" GST_PTR_FORMAT, GST_PAD_TEMPLATE_CAPS (padtempl));
|
|
|
|
|
2009-07-22 08:24:59 +00:00
|
|
|
compatible = gst_caps_can_intersect (GST_PAD_TEMPLATE_CAPS (compattempl),
|
2005-03-07 18:27:42 +00:00
|
|
|
GST_PAD_TEMPLATE_CAPS (padtempl));
|
|
|
|
|
2009-07-22 08:24:59 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible",
|
|
|
|
(compatible ? "" : "not "));
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2009-07-22 08:24:59 +00:00
|
|
|
if (compatible) {
|
2005-03-07 18:27:42 +00:00
|
|
|
newtempl = padtempl;
|
|
|
|
break;
|
2009-07-22 08:24:59 +00:00
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
padlist = g_list_next (padlist);
|
|
|
|
}
|
|
|
|
if (newtempl)
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"Returning new pad template %p", newtempl);
|
|
|
|
else
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "No compatible pad template found");
|
|
|
|
|
|
|
|
return newtempl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_get_pad_from_template:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element: (transfer none): a #GstElement.
|
|
|
|
* @templ: (transfer none): a #GstPadTemplate belonging to @element.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Gets a pad from @element described by @templ. If the presence of @templ is
|
|
|
|
* #GST_PAD_REQUEST, requests a new pad. Can return %NULL for #GST_PAD_SOMETIMES
|
|
|
|
* templates.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Returns: (transfer full): the #GstPad, or NULL if one could not be found
|
|
|
|
* or created.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
static GstPad *
|
|
|
|
gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
|
|
|
|
{
|
|
|
|
GstPad *ret = NULL;
|
|
|
|
GstPadPresence presence;
|
|
|
|
|
|
|
|
/* If this function is ever exported, we need check the validity of `element'
|
|
|
|
* and `templ', and to make sure the template actually belongs to the
|
|
|
|
* element. */
|
|
|
|
|
|
|
|
presence = GST_PAD_TEMPLATE_PRESENCE (templ);
|
|
|
|
|
|
|
|
switch (presence) {
|
|
|
|
case GST_PAD_ALWAYS:
|
|
|
|
case GST_PAD_SOMETIMES:
|
|
|
|
ret = gst_element_get_static_pad (element, templ->name_template);
|
|
|
|
if (!ret && presence == GST_PAD_ALWAYS)
|
|
|
|
g_warning
|
|
|
|
("Element %s has an ALWAYS template %s, but no pad of the same name",
|
|
|
|
GST_OBJECT_NAME (element), templ->name_template);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GST_PAD_REQUEST:
|
2010-12-20 12:30:43 +00:00
|
|
|
ret = gst_element_request_pad (element, templ, NULL, NULL);
|
2005-03-07 18:27:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-03-02 21:58:06 +00:00
|
|
|
/*
|
2005-03-07 18:27:42 +00:00
|
|
|
* gst_element_request_compatible_pad:
|
|
|
|
* @element: a #GstElement.
|
|
|
|
* @templ: the #GstPadTemplate to which the new pad should be able to link.
|
|
|
|
*
|
|
|
|
* Requests a pad from @element. The returned pad should be unlinked and
|
|
|
|
* compatible with @templ. Might return an existing pad, or request a new one.
|
|
|
|
*
|
|
|
|
* Returns: a #GstPad, or %NULL if one could not be found or created.
|
|
|
|
*/
|
2010-03-02 21:58:06 +00:00
|
|
|
static GstPad *
|
2005-03-07 18:27:42 +00:00
|
|
|
gst_element_request_compatible_pad (GstElement * element,
|
|
|
|
GstPadTemplate * templ)
|
|
|
|
{
|
|
|
|
GstPadTemplate *templ_new;
|
|
|
|
GstPad *pad = NULL;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
|
|
|
g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
|
|
|
|
|
|
|
|
/* FIXME: should really loop through the templates, testing each for
|
|
|
|
* compatibility and pad availability. */
|
|
|
|
templ_new = gst_element_get_compatible_pad_template (element, templ);
|
|
|
|
if (templ_new)
|
|
|
|
pad = gst_element_get_pad_from_template (element, templ_new);
|
|
|
|
|
|
|
|
/* This can happen for non-request pads. No need to unref. */
|
|
|
|
if (pad && GST_PAD_PEER (pad))
|
|
|
|
pad = NULL;
|
|
|
|
|
|
|
|
return pad;
|
|
|
|
}
|
|
|
|
|
2009-04-15 22:26:13 +00:00
|
|
|
/*
|
2009-03-18 16:01:16 +00:00
|
|
|
* Checks if the source pad and the sink pad can be linked.
|
|
|
|
* Both @srcpad and @sinkpad must be unlinked and have a parent.
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
gst_pad_check_link (GstPad * srcpad, GstPad * sinkpad)
|
|
|
|
{
|
|
|
|
/* FIXME This function is gross. It's almost a direct copy of
|
|
|
|
* gst_pad_link_filtered(). Any decent programmer would attempt
|
|
|
|
* to merge the two functions, which I will do some day. --ds
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* generic checks */
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
|
|
|
|
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
|
|
|
|
|
|
|
|
/* FIXME: shouldn't we convert this to g_return_val_if_fail? */
|
|
|
|
if (GST_PAD_PEER (srcpad) != NULL) {
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "Source pad %s:%s has a peer, failed",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (GST_PAD_PEER (sinkpad) != NULL) {
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s has a peer, failed",
|
|
|
|
GST_DEBUG_PAD_NAME (sinkpad));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (!GST_PAD_IS_SRC (srcpad)) {
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "Src pad %s:%s is not source pad, failed",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (!GST_PAD_IS_SINK (sinkpad)) {
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s is not sink pad, failed",
|
|
|
|
GST_DEBUG_PAD_NAME (sinkpad));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (GST_PAD_PARENT (srcpad) == NULL) {
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "Src pad %s:%s has no parent, failed",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (GST_PAD_PARENT (sinkpad) == NULL) {
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "Sink pad %s:%s has no parent, failed",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/**
|
2005-04-24 21:16:45 +00:00
|
|
|
* gst_element_get_compatible_pad:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element: (transfer none): a #GstElement in which the pad should be found.
|
|
|
|
* @pad: (transfer none): the #GstPad to find a compatible one for.
|
2005-06-29 12:23:35 +00:00
|
|
|
* @caps: the #GstCaps to use as a filter.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Looks for an unlinked pad to which the given pad can link. It is not
|
|
|
|
* guaranteed that linking the pads will work, though it should work in most
|
|
|
|
* cases.
|
|
|
|
*
|
2010-07-08 14:24:21 +00:00
|
|
|
* This function will first attempt to find a compatible unlinked ALWAYS pad,
|
|
|
|
* and if none can be found, it will request a compatible REQUEST pad by looking
|
|
|
|
* at the templates of @element.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Returns: (transfer full): the #GstPad to which a link can be made, or %NULL
|
|
|
|
* if one cannot be found. gst_object_unref() after usage.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
GstPad *
|
2005-04-24 21:16:45 +00:00
|
|
|
gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
|
|
|
|
const GstCaps * caps)
|
2005-03-07 18:27:42 +00:00
|
|
|
{
|
|
|
|
GstIterator *pads;
|
|
|
|
GstPadTemplate *templ;
|
|
|
|
GstCaps *templcaps;
|
|
|
|
GstPad *foundpad = NULL;
|
|
|
|
gboolean done;
|
2011-03-17 10:31:59 +00:00
|
|
|
GValue padptr = { 0, };
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
|
|
|
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
2005-04-24 21:16:45 +00:00
|
|
|
"finding pad in %s compatible with %s:%s",
|
|
|
|
GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));
|
2005-03-07 18:27:42 +00:00
|
|
|
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
g_return_val_if_fail (GST_PAD_PEER (pad) == NULL, NULL);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
done = FALSE;
|
2010-08-05 09:04:47 +00:00
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/* try to get an existing unlinked pad */
|
2010-08-05 09:04:47 +00:00
|
|
|
if (GST_PAD_IS_SRC (pad)) {
|
|
|
|
pads = gst_element_iterate_sink_pads (element);
|
|
|
|
} else if (GST_PAD_IS_SINK (pad)) {
|
|
|
|
pads = gst_element_iterate_src_pads (element);
|
|
|
|
} else {
|
|
|
|
pads = gst_element_iterate_pads (element);
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
while (!done) {
|
|
|
|
switch (gst_iterator_next (pads, &padptr)) {
|
|
|
|
case GST_ITERATOR_OK:
|
|
|
|
{
|
|
|
|
GstPad *peer;
|
|
|
|
GstPad *current;
|
2011-01-26 08:46:25 +00:00
|
|
|
GstPad *srcpad;
|
|
|
|
GstPad *sinkpad;
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2011-03-17 10:31:59 +00:00
|
|
|
current = g_value_get_object (&padptr);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2005-06-02 15:45:16 +00:00
|
|
|
GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examining pad %s:%s",
|
2005-03-07 18:27:42 +00:00
|
|
|
GST_DEBUG_PAD_NAME (current));
|
|
|
|
|
2011-01-26 08:46:25 +00:00
|
|
|
if (GST_PAD_IS_SRC (current)) {
|
|
|
|
srcpad = current;
|
|
|
|
sinkpad = pad;
|
|
|
|
} else {
|
|
|
|
srcpad = pad;
|
|
|
|
sinkpad = current;
|
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
peer = gst_pad_get_peer (current);
|
|
|
|
|
2011-01-26 08:46:25 +00:00
|
|
|
if (peer == NULL && gst_pad_check_link (srcpad, sinkpad)) {
|
2009-07-22 08:24:59 +00:00
|
|
|
GstCaps *temp, *intersection;
|
|
|
|
gboolean compatible;
|
2008-12-09 15:45:36 +00:00
|
|
|
|
|
|
|
/* Now check if the two pads' caps are compatible */
|
2011-05-10 15:56:33 +00:00
|
|
|
temp = gst_pad_get_caps (pad, NULL);
|
2008-12-09 15:45:36 +00:00
|
|
|
if (caps) {
|
|
|
|
intersection = gst_caps_intersect (temp, caps);
|
|
|
|
gst_caps_unref (temp);
|
|
|
|
} else {
|
|
|
|
intersection = temp;
|
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2011-05-10 15:56:33 +00:00
|
|
|
temp = gst_pad_get_caps (current, NULL);
|
2009-07-22 08:24:59 +00:00
|
|
|
compatible = gst_caps_can_intersect (temp, intersection);
|
2008-12-09 15:45:36 +00:00
|
|
|
gst_caps_unref (temp);
|
|
|
|
gst_caps_unref (intersection);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2009-07-22 08:24:59 +00:00
|
|
|
if (compatible) {
|
2008-12-09 15:45:36 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"found existing unlinked compatible pad %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (current));
|
|
|
|
gst_iterator_free (pads);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2011-03-17 10:31:59 +00:00
|
|
|
current = gst_object_ref (current);
|
|
|
|
g_value_unset (&padptr);
|
|
|
|
|
2008-12-09 15:45:36 +00:00
|
|
|
return current;
|
2009-02-04 13:41:24 +00:00
|
|
|
} else {
|
2009-01-25 20:17:31 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "incompatible pads");
|
|
|
|
}
|
2009-02-04 13:41:24 +00:00
|
|
|
} else {
|
2009-01-25 20:17:31 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"already linked or cannot be linked (peer = %p)", peer);
|
|
|
|
}
|
2008-12-09 15:45:36 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads");
|
|
|
|
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_reset (&padptr);
|
2008-12-09 15:45:36 +00:00
|
|
|
if (peer)
|
|
|
|
gst_object_unref (peer);
|
2005-03-07 18:27:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GST_ITERATOR_DONE:
|
|
|
|
done = TRUE;
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_RESYNC:
|
|
|
|
gst_iterator_resync (pads);
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_ERROR:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_unset (&padptr);
|
2005-03-07 18:27:42 +00:00
|
|
|
gst_iterator_free (pads);
|
|
|
|
|
2008-05-14 18:17:34 +00:00
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
|
|
|
|
"Could not find a compatible unlinked always pad to link to %s:%s, now checking request pads",
|
|
|
|
GST_DEBUG_PAD_NAME (pad));
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/* try to create a new one */
|
|
|
|
/* requesting is a little crazy, we need a template. Let's create one */
|
2008-10-31 14:24:49 +00:00
|
|
|
/* FIXME: why not gst_pad_get_pad_template (pad); */
|
2011-05-10 15:56:33 +00:00
|
|
|
templcaps = gst_pad_get_caps (pad, NULL);
|
2005-03-07 18:27:42 +00:00
|
|
|
templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
|
|
|
|
GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps);
|
2011-05-17 10:04:27 +00:00
|
|
|
gst_caps_unref (templcaps);
|
2008-08-30 11:55:59 +00:00
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
foundpad = gst_element_request_compatible_pad (element, templ);
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (templ);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
if (foundpad) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"found existing request pad %s:%s", GST_DEBUG_PAD_NAME (foundpad));
|
|
|
|
return foundpad;
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element,
|
|
|
|
"Could not find a compatible pad to link to %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (pad));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_state_get_name:
|
2005-09-02 15:42:00 +00:00
|
|
|
* @state: a #GstState to get the name of.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Gets a string representing the given state.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Returns: (transfer none): a string with the name of the state.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
2011-06-09 16:13:35 +00:00
|
|
|
const gchar *
|
2005-09-02 15:42:00 +00:00
|
|
|
gst_element_state_get_name (GstState state)
|
2005-03-07 18:27:42 +00:00
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case GST_STATE_VOID_PENDING:
|
2005-09-11 12:01:12 +00:00
|
|
|
return "VOID_PENDING";
|
2005-03-07 18:27:42 +00:00
|
|
|
case GST_STATE_NULL:
|
|
|
|
return "NULL";
|
|
|
|
case GST_STATE_READY:
|
|
|
|
return "READY";
|
|
|
|
case GST_STATE_PLAYING:
|
|
|
|
return "PLAYING";
|
|
|
|
case GST_STATE_PAUSED:
|
|
|
|
return "PAUSED";
|
|
|
|
default:
|
2005-10-08 06:49:09 +00:00
|
|
|
/* This is a memory leak */
|
2005-03-07 18:27:42 +00:00
|
|
|
return g_strdup_printf ("UNKNOWN!(%d)", state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-06 15:14:46 +00:00
|
|
|
/**
|
|
|
|
* gst_element_state_change_return_get_name:
|
|
|
|
* @state_ret: a #GstStateChangeReturn to get the name of.
|
|
|
|
*
|
|
|
|
* Gets a string representing the given state change result.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Returns: (transfer none): a string with the name of the state
|
|
|
|
* result.
|
2007-12-12 06:58:56 +00:00
|
|
|
*
|
|
|
|
* Since: 0.10.11
|
2006-11-06 15:14:46 +00:00
|
|
|
*/
|
2011-06-09 16:13:35 +00:00
|
|
|
const gchar *
|
2006-11-06 15:14:46 +00:00
|
|
|
gst_element_state_change_return_get_name (GstStateChangeReturn state_ret)
|
|
|
|
{
|
|
|
|
switch (state_ret) {
|
|
|
|
case GST_STATE_CHANGE_FAILURE:
|
|
|
|
return "FAILURE";
|
|
|
|
case GST_STATE_CHANGE_SUCCESS:
|
|
|
|
return "SUCCESS";
|
|
|
|
case GST_STATE_CHANGE_ASYNC:
|
|
|
|
return "ASYNC";
|
|
|
|
case GST_STATE_CHANGE_NO_PREROLL:
|
|
|
|
return "NO PREROLL";
|
|
|
|
default:
|
|
|
|
/* This is a memory leak */
|
|
|
|
return g_strdup_printf ("UNKNOWN!(%d)", state_ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-23 20:00:04 +00:00
|
|
|
static gboolean
|
|
|
|
gst_element_factory_can_accept_all_caps_in_direction (GstElementFactory *
|
|
|
|
factory, const GstCaps * caps, GstPadDirection direction)
|
2005-06-29 15:17:25 +00:00
|
|
|
{
|
|
|
|
GList *templates;
|
|
|
|
|
|
|
|
g_return_val_if_fail (factory != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (caps != NULL, FALSE);
|
|
|
|
|
|
|
|
templates = factory->staticpadtemplates;
|
|
|
|
|
|
|
|
while (templates) {
|
|
|
|
GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
|
|
|
|
|
2010-06-23 20:00:04 +00:00
|
|
|
if (template->direction == direction) {
|
2011-04-14 06:59:14 +00:00
|
|
|
GstCaps *templcaps = gst_static_caps_get (&template->static_caps);
|
|
|
|
|
|
|
|
if (gst_caps_is_always_compatible (caps, templcaps)) {
|
|
|
|
gst_caps_unref (templcaps);
|
2005-06-29 15:17:25 +00:00
|
|
|
return TRUE;
|
2011-04-14 06:59:14 +00:00
|
|
|
}
|
|
|
|
gst_caps_unref (templcaps);
|
2005-06-29 15:17:25 +00:00
|
|
|
}
|
|
|
|
templates = g_list_next (templates);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2010-06-23 20:00:04 +00:00
|
|
|
static gboolean
|
|
|
|
gst_element_factory_can_accept_any_caps_in_direction (GstElementFactory *
|
|
|
|
factory, const GstCaps * caps, GstPadDirection direction)
|
2005-06-29 15:17:25 +00:00
|
|
|
{
|
|
|
|
GList *templates;
|
|
|
|
|
|
|
|
g_return_val_if_fail (factory != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (caps != NULL, FALSE);
|
|
|
|
|
|
|
|
templates = factory->staticpadtemplates;
|
|
|
|
|
|
|
|
while (templates) {
|
|
|
|
GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
|
|
|
|
|
2010-06-23 20:00:04 +00:00
|
|
|
if (template->direction == direction) {
|
2011-04-14 06:59:14 +00:00
|
|
|
GstCaps *templcaps = gst_static_caps_get (&template->static_caps);
|
|
|
|
|
|
|
|
if (gst_caps_can_intersect (caps, templcaps)) {
|
|
|
|
gst_caps_unref (templcaps);
|
2005-06-29 15:17:25 +00:00
|
|
|
return TRUE;
|
2011-04-14 06:59:14 +00:00
|
|
|
}
|
|
|
|
gst_caps_unref (templcaps);
|
2005-06-29 15:17:25 +00:00
|
|
|
}
|
|
|
|
templates = g_list_next (templates);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2010-06-23 20:00:04 +00:00
|
|
|
/**
|
|
|
|
* gst_element_factory_can_sink_all_caps:
|
|
|
|
* @factory: factory to query
|
|
|
|
* @caps: the caps to check
|
|
|
|
*
|
|
|
|
* Checks if the factory can sink all possible capabilities.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the caps are fully compatible.
|
|
|
|
*
|
|
|
|
* Since: 0.10.33
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_factory_can_sink_all_caps (GstElementFactory * factory,
|
|
|
|
const GstCaps * caps)
|
|
|
|
{
|
|
|
|
return gst_element_factory_can_accept_all_caps_in_direction (factory, caps,
|
|
|
|
GST_PAD_SINK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_factory_can_src_all_caps:
|
|
|
|
* @factory: factory to query
|
|
|
|
* @caps: the caps to check
|
|
|
|
*
|
|
|
|
* Checks if the factory can src all possible capabilities.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the caps are fully compatible.
|
|
|
|
*
|
|
|
|
* Since: 0.10.33
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_factory_can_src_all_caps (GstElementFactory * factory,
|
|
|
|
const GstCaps * caps)
|
|
|
|
{
|
|
|
|
return gst_element_factory_can_accept_all_caps_in_direction (factory, caps,
|
|
|
|
GST_PAD_SRC);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_factory_can_sink_any_caps:
|
|
|
|
* @factory: factory to query
|
|
|
|
* @caps: the caps to check
|
|
|
|
*
|
|
|
|
* Checks if the factory can sink any possible capability.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the caps have a common subset.
|
|
|
|
*
|
|
|
|
* Since: 0.10.33
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_factory_can_sink_any_caps (GstElementFactory * factory,
|
|
|
|
const GstCaps * caps)
|
|
|
|
{
|
|
|
|
return gst_element_factory_can_accept_any_caps_in_direction (factory, caps,
|
|
|
|
GST_PAD_SINK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_factory_can_src_any_caps:
|
|
|
|
* @factory: factory to query
|
|
|
|
* @caps: the caps to check
|
|
|
|
*
|
|
|
|
* Checks if the factory can src any possible capability.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the caps have a common subset.
|
|
|
|
*
|
|
|
|
* Since: 0.10.33
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_factory_can_src_any_caps (GstElementFactory * factory,
|
|
|
|
const GstCaps * caps)
|
|
|
|
{
|
|
|
|
return gst_element_factory_can_accept_any_caps_in_direction (factory, caps,
|
|
|
|
GST_PAD_SRC);
|
|
|
|
}
|
2005-06-29 15:17:25 +00:00
|
|
|
|
2005-05-14 15:32:36 +00:00
|
|
|
/* if return val is true, *direct_child is a caller-owned ref on the direct
|
|
|
|
* child of ancestor that is part of object's ancestry */
|
|
|
|
static gboolean
|
|
|
|
object_has_ancestor (GstObject * object, GstObject * ancestor,
|
|
|
|
GstObject ** direct_child)
|
|
|
|
{
|
|
|
|
GstObject *child, *parent;
|
|
|
|
|
|
|
|
if (direct_child)
|
|
|
|
*direct_child = NULL;
|
|
|
|
|
|
|
|
child = gst_object_ref (object);
|
|
|
|
parent = gst_object_get_parent (object);
|
|
|
|
|
|
|
|
while (parent) {
|
|
|
|
if (ancestor == parent) {
|
|
|
|
if (direct_child)
|
|
|
|
*direct_child = child;
|
|
|
|
else
|
|
|
|
gst_object_unref (child);
|
|
|
|
gst_object_unref (parent);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_object_unref (child);
|
|
|
|
child = parent;
|
|
|
|
parent = gst_object_get_parent (parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_object_unref (child);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* caller owns return */
|
|
|
|
static GstObject *
|
|
|
|
find_common_root (GstObject * o1, GstObject * o2)
|
|
|
|
{
|
|
|
|
GstObject *top = o1;
|
|
|
|
GstObject *kid1, *kid2;
|
|
|
|
GstObject *root = NULL;
|
|
|
|
|
|
|
|
while (GST_OBJECT_PARENT (top))
|
|
|
|
top = GST_OBJECT_PARENT (top);
|
|
|
|
|
|
|
|
/* the itsy-bitsy spider... */
|
|
|
|
|
|
|
|
if (!object_has_ancestor (o2, top, &kid2))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
root = gst_object_ref (top);
|
|
|
|
while (TRUE) {
|
|
|
|
if (!object_has_ancestor (o1, kid2, &kid1)) {
|
|
|
|
gst_object_unref (kid2);
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
root = kid2;
|
|
|
|
if (!object_has_ancestor (o2, kid1, &kid2)) {
|
|
|
|
gst_object_unref (kid1);
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
root = kid1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* caller does not own return */
|
|
|
|
static GstPad *
|
|
|
|
ghost_up (GstElement * e, GstPad * pad)
|
|
|
|
{
|
|
|
|
static gint ghost_pad_index = 0;
|
|
|
|
GstPad *gpad;
|
|
|
|
gchar *name;
|
2010-08-12 23:23:45 +00:00
|
|
|
GstState current;
|
|
|
|
GstState next;
|
2005-06-02 15:45:16 +00:00
|
|
|
GstObject *parent = GST_OBJECT_PARENT (e);
|
|
|
|
|
2005-05-14 15:32:36 +00:00
|
|
|
name = g_strdup_printf ("ghost%d", ghost_pad_index++);
|
|
|
|
gpad = gst_ghost_pad_new (name, pad);
|
|
|
|
g_free (name);
|
|
|
|
|
2010-08-12 23:23:45 +00:00
|
|
|
GST_STATE_LOCK (e);
|
|
|
|
gst_element_get_state (e, ¤t, &next, 0);
|
|
|
|
|
|
|
|
if (current > GST_STATE_READY || next == GST_STATE_PAUSED)
|
|
|
|
gst_pad_set_active (gpad, TRUE);
|
|
|
|
|
2005-06-02 15:45:16 +00:00
|
|
|
if (!gst_element_add_pad ((GstElement *) parent, gpad)) {
|
2005-05-14 15:32:36 +00:00
|
|
|
g_warning ("Pad named %s already exists in element %s\n",
|
2005-06-02 15:45:16 +00:00
|
|
|
GST_OBJECT_NAME (gpad), GST_OBJECT_NAME (parent));
|
2005-05-14 15:32:36 +00:00
|
|
|
gst_object_unref ((GstObject *) gpad);
|
2010-08-12 23:23:45 +00:00
|
|
|
GST_STATE_UNLOCK (e);
|
2005-05-14 15:32:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-08-12 23:23:45 +00:00
|
|
|
GST_STATE_UNLOCK (e);
|
2005-05-14 15:32:36 +00:00
|
|
|
|
|
|
|
return gpad;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_pad (gpointer ppad, gpointer unused)
|
|
|
|
{
|
|
|
|
GstPad *pad = ppad;
|
|
|
|
|
|
|
|
if (!gst_element_remove_pad ((GstElement *) GST_OBJECT_PARENT (pad), pad))
|
|
|
|
g_warning ("Couldn't remove pad %s from element %s",
|
|
|
|
GST_OBJECT_NAME (pad), GST_OBJECT_NAME (GST_OBJECT_PARENT (pad)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
prepare_link_maybe_ghosting (GstPad ** src, GstPad ** sink,
|
|
|
|
GSList ** pads_created)
|
|
|
|
{
|
|
|
|
GstObject *root;
|
|
|
|
GstObject *e1, *e2;
|
|
|
|
GSList *pads_created_local = NULL;
|
|
|
|
|
|
|
|
g_assert (pads_created);
|
|
|
|
|
|
|
|
e1 = GST_OBJECT_PARENT (*src);
|
|
|
|
e2 = GST_OBJECT_PARENT (*sink);
|
|
|
|
|
2006-12-09 18:48:57 +00:00
|
|
|
if (G_UNLIKELY (e1 == NULL)) {
|
|
|
|
GST_WARNING ("Trying to ghost a pad that doesn't have a parent: %"
|
|
|
|
GST_PTR_FORMAT, *src);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (G_UNLIKELY (e2 == NULL)) {
|
|
|
|
GST_WARNING ("Trying to ghost a pad that doesn't have a parent: %"
|
|
|
|
GST_PTR_FORMAT, *sink);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-05-14 15:32:36 +00:00
|
|
|
if (GST_OBJECT_PARENT (e1) == GST_OBJECT_PARENT (e2)) {
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "%s and %s in same bin, no need for ghost pads",
|
|
|
|
GST_OBJECT_NAME (e1), GST_OBJECT_NAME (e2));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_CAT_INFO (GST_CAT_PADS, "%s and %s not in same bin, making ghost pads",
|
|
|
|
GST_OBJECT_NAME (e1), GST_OBJECT_NAME (e2));
|
|
|
|
|
|
|
|
/* we need to setup some ghost pads */
|
|
|
|
root = find_common_root (e1, e2);
|
|
|
|
if (!root) {
|
2006-12-09 18:48:57 +00:00
|
|
|
g_warning ("Trying to connect elements that don't share a common "
|
|
|
|
"ancestor: %s and %s", GST_ELEMENT_NAME (e1), GST_ELEMENT_NAME (e2));
|
2005-05-14 15:32:36 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (GST_OBJECT_PARENT (e1) != root) {
|
|
|
|
*src = ghost_up ((GstElement *) e1, *src);
|
|
|
|
if (!*src)
|
|
|
|
goto cleanup_fail;
|
|
|
|
e1 = GST_OBJECT_PARENT (*src);
|
|
|
|
pads_created_local = g_slist_prepend (pads_created_local, *src);
|
|
|
|
}
|
|
|
|
while (GST_OBJECT_PARENT (e2) != root) {
|
|
|
|
*sink = ghost_up ((GstElement *) e2, *sink);
|
|
|
|
if (!*sink)
|
|
|
|
goto cleanup_fail;
|
|
|
|
e2 = GST_OBJECT_PARENT (*sink);
|
|
|
|
pads_created_local = g_slist_prepend (pads_created_local, *sink);
|
|
|
|
}
|
|
|
|
|
2005-05-14 17:12:11 +00:00
|
|
|
gst_object_unref (root);
|
2005-05-14 15:32:36 +00:00
|
|
|
*pads_created = g_slist_concat (*pads_created, pads_created_local);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
cleanup_fail:
|
2005-05-14 17:12:11 +00:00
|
|
|
gst_object_unref (root);
|
2005-05-14 15:32:36 +00:00
|
|
|
g_slist_foreach (pads_created_local, remove_pad, NULL);
|
|
|
|
g_slist_free (pads_created_local);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2010-06-23 15:00:17 +00:00
|
|
|
pad_link_maybe_ghosting (GstPad * src, GstPad * sink, GstPadLinkCheck flags)
|
2005-05-14 15:32:36 +00:00
|
|
|
{
|
|
|
|
GSList *pads_created = NULL;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
if (!prepare_link_maybe_ghosting (&src, &sink, &pads_created)) {
|
|
|
|
ret = FALSE;
|
|
|
|
} else {
|
2010-06-23 15:00:17 +00:00
|
|
|
ret = (gst_pad_link_full (src, sink, flags) == GST_PAD_LINK_OK);
|
2005-05-14 15:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
g_slist_foreach (pads_created, remove_pad, NULL);
|
|
|
|
}
|
|
|
|
g_slist_free (pads_created);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/**
|
2010-06-23 15:00:17 +00:00
|
|
|
* gst_element_link_pads_full:
|
2005-03-07 18:27:42 +00:00
|
|
|
* @src: a #GstElement containing the source pad.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @srcpadname: (allow-none): the name of the #GstPad in source element
|
|
|
|
* or NULL for any pad.
|
|
|
|
* @dest: (transfer none): the #GstElement containing the destination pad.
|
|
|
|
* @destpadname: (allow-none): the name of the #GstPad in destination element,
|
2005-10-05 21:34:42 +00:00
|
|
|
* or NULL for any pad.
|
2010-06-23 15:00:17 +00:00
|
|
|
* @flags: the #GstPadLinkCheck to be performed when linking pads.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Links the two named pads of the source and destination elements.
|
|
|
|
* Side effect is that if one of the pads has no parent, it becomes a
|
|
|
|
* child of the parent of the other element. If they have different
|
|
|
|
* parents, the link fails.
|
|
|
|
*
|
2010-07-05 14:50:33 +00:00
|
|
|
* Calling gst_element_link_pads_full() with @flags == %GST_PAD_LINK_CHECK_DEFAULT
|
|
|
|
* is the same as calling gst_element_link_pads() and the recommended way of
|
|
|
|
* linking pads with safety checks applied.
|
|
|
|
*
|
2011-02-28 15:01:54 +00:00
|
|
|
* This is a convenience function for gst_pad_link_full().
|
2011-02-28 14:27:01 +00:00
|
|
|
*
|
2005-03-07 18:27:42 +00:00
|
|
|
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
2010-06-23 15:00:17 +00:00
|
|
|
*
|
|
|
|
* Since: 0.10.30
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
gboolean
|
2010-06-23 15:00:17 +00:00
|
|
|
gst_element_link_pads_full (GstElement * src, const gchar * srcpadname,
|
|
|
|
GstElement * dest, const gchar * destpadname, GstPadLinkCheck flags)
|
2005-03-07 18:27:42 +00:00
|
|
|
{
|
|
|
|
const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
|
|
|
|
GstPad *srcpad, *destpad;
|
|
|
|
GstPadTemplate *srctempl, *desttempl;
|
|
|
|
GstElementClass *srcclass, *destclass;
|
|
|
|
|
|
|
|
/* checks */
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
|
|
|
|
|
|
|
|
GST_CAT_INFO (GST_CAT_ELEMENT_PADS,
|
|
|
|
"trying to link element %s:%s to element %s:%s", GST_ELEMENT_NAME (src),
|
|
|
|
srcpadname ? srcpadname : "(any)", GST_ELEMENT_NAME (dest),
|
|
|
|
destpadname ? destpadname : "(any)");
|
|
|
|
|
2005-10-05 21:34:42 +00:00
|
|
|
/* get a src pad */
|
2005-03-07 18:27:42 +00:00
|
|
|
if (srcpadname) {
|
2005-10-05 21:34:42 +00:00
|
|
|
/* name specified, look it up */
|
2008-05-21 15:57:52 +00:00
|
|
|
if (!(srcpad = gst_element_get_static_pad (src, srcpadname)))
|
|
|
|
srcpad = gst_element_get_request_pad (src, srcpadname);
|
2005-03-07 18:27:42 +00:00
|
|
|
if (!srcpad) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
|
|
|
|
GST_ELEMENT_NAME (src), srcpadname);
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad));
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (srcpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (GST_PAD_PEER (srcpad) != NULL) {
|
2011-02-16 13:13:05 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"pad %s:%s is already linked to %s:%s", GST_DEBUG_PAD_NAME (srcpad),
|
|
|
|
GST_DEBUG_PAD_NAME (GST_PAD_PEER (srcpad)));
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (srcpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srcpads = NULL;
|
|
|
|
} else {
|
2005-10-05 21:34:42 +00:00
|
|
|
/* no name given, get the first available pad */
|
2005-11-21 16:34:26 +00:00
|
|
|
GST_OBJECT_LOCK (src);
|
2005-03-07 18:27:42 +00:00
|
|
|
srcpads = GST_ELEMENT_PADS (src);
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
srcpad = srcpads ? GST_PAD_CAST (srcpads->data) : NULL;
|
2005-03-07 18:27:42 +00:00
|
|
|
if (srcpad)
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_ref (srcpad);
|
2005-11-21 16:34:26 +00:00
|
|
|
GST_OBJECT_UNLOCK (src);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
2005-10-05 21:34:42 +00:00
|
|
|
|
|
|
|
/* get a destination pad */
|
2005-03-07 18:27:42 +00:00
|
|
|
if (destpadname) {
|
2005-10-05 21:34:42 +00:00
|
|
|
/* name specified, look it up */
|
2008-05-21 15:57:52 +00:00
|
|
|
if (!(destpad = gst_element_get_static_pad (dest, destpadname)))
|
|
|
|
destpad = gst_element_get_request_pad (dest, destpadname);
|
2005-03-07 18:27:42 +00:00
|
|
|
if (!destpad) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
|
|
|
|
GST_ELEMENT_NAME (dest), destpadname);
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",
|
|
|
|
GST_DEBUG_PAD_NAME (destpad));
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (GST_PAD_PEER (destpad) != NULL) {
|
2011-02-16 13:13:05 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"pad %s:%s is already linked to %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (destpad),
|
|
|
|
GST_DEBUG_PAD_NAME (GST_PAD_PEER (destpad)));
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
destpads = NULL;
|
|
|
|
} else {
|
2005-10-05 21:34:42 +00:00
|
|
|
/* no name given, get the first available pad */
|
2005-11-21 16:34:26 +00:00
|
|
|
GST_OBJECT_LOCK (dest);
|
2005-03-07 18:27:42 +00:00
|
|
|
destpads = GST_ELEMENT_PADS (dest);
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
destpad = destpads ? GST_PAD_CAST (destpads->data) : NULL;
|
2005-03-07 18:27:42 +00:00
|
|
|
if (destpad)
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_ref (destpad);
|
2005-11-21 16:34:26 +00:00
|
|
|
GST_OBJECT_UNLOCK (dest);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (srcpadname && destpadname) {
|
|
|
|
gboolean result;
|
|
|
|
|
|
|
|
/* two explicitly specified pads */
|
2010-06-23 15:00:17 +00:00
|
|
|
result = pad_link_maybe_ghosting (srcpad, destpad, flags);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (srcpad);
|
|
|
|
gst_object_unref (destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2005-10-05 21:34:42 +00:00
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
if (srcpad) {
|
|
|
|
/* loop through the allowed pads in the source, trying to find a
|
|
|
|
* compatible destination pad */
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"looping through allowed src and dest pads");
|
|
|
|
do {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad));
|
|
|
|
if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
|
|
|
|
(GST_PAD_PEER (srcpad) == NULL)) {
|
2005-05-11 09:21:24 +00:00
|
|
|
GstPad *temp;
|
|
|
|
|
|
|
|
if (destpadname) {
|
|
|
|
temp = destpad;
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_ref (temp);
|
2005-05-11 09:21:24 +00:00
|
|
|
} else {
|
|
|
|
temp = gst_element_get_compatible_pad (dest, srcpad, NULL);
|
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2010-06-23 15:00:17 +00:00
|
|
|
if (temp && pad_link_maybe_ghosting (srcpad, temp, flags)) {
|
2005-03-07 18:27:42 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
|
|
|
|
if (destpad)
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (destpad);
|
|
|
|
gst_object_unref (srcpad);
|
|
|
|
gst_object_unref (temp);
|
2005-03-07 18:27:42 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
|
|
|
|
if (temp) {
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (temp);
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
/* find a better way for this mess */
|
|
|
|
if (srcpads) {
|
|
|
|
srcpads = g_list_next (srcpads);
|
|
|
|
if (srcpads) {
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (srcpad);
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
srcpad = GST_PAD_CAST (srcpads->data);
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_ref (srcpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (srcpads);
|
|
|
|
}
|
|
|
|
if (srcpadname) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
|
|
|
|
if (destpad)
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (destpad);
|
2005-10-05 21:34:42 +00:00
|
|
|
destpad = NULL;
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
2006-04-28 17:52:13 +00:00
|
|
|
if (srcpad)
|
|
|
|
gst_object_unref (srcpad);
|
|
|
|
srcpad = NULL;
|
2005-10-05 21:34:42 +00:00
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
if (destpad) {
|
|
|
|
/* loop through the existing pads in the destination */
|
|
|
|
do {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (destpad));
|
|
|
|
if ((GST_PAD_DIRECTION (destpad) == GST_PAD_SINK) &&
|
|
|
|
(GST_PAD_PEER (destpad) == NULL)) {
|
2005-04-24 21:16:45 +00:00
|
|
|
GstPad *temp = gst_element_get_compatible_pad (src, destpad, NULL);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2010-06-23 15:00:17 +00:00
|
|
|
if (temp && pad_link_maybe_ghosting (temp, destpad, flags)) {
|
2005-03-07 18:27:42 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (temp);
|
|
|
|
gst_object_unref (destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
if (temp) {
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (temp);
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
if (destpads) {
|
|
|
|
destpads = g_list_next (destpads);
|
|
|
|
if (destpads) {
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (destpad);
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
destpad = GST_PAD_CAST (destpads->data);
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_ref (destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (destpads);
|
|
|
|
}
|
2005-10-05 21:34:42 +00:00
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
if (destpadname) {
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
|
|
|
|
GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
return FALSE;
|
|
|
|
} else {
|
2005-10-05 21:34:42 +00:00
|
|
|
if (destpad)
|
|
|
|
gst_object_unref (destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
destpad = NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-10 19:49:25 +00:00
|
|
|
srcclass = GST_ELEMENT_GET_CLASS (src);
|
|
|
|
destclass = GST_ELEMENT_GET_CLASS (dest);
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"we might have request pads on both sides, checking...");
|
|
|
|
srctempls = gst_element_class_get_pad_template_list (srcclass);
|
|
|
|
desttempls = gst_element_class_get_pad_template_list (destclass);
|
|
|
|
|
|
|
|
if (srctempls && desttempls) {
|
|
|
|
while (srctempls) {
|
|
|
|
srctempl = (GstPadTemplate *) srctempls->data;
|
|
|
|
if (srctempl->presence == GST_PAD_REQUEST) {
|
|
|
|
for (l = desttempls; l; l = l->next) {
|
|
|
|
desttempl = (GstPadTemplate *) l->data;
|
|
|
|
if (desttempl->presence == GST_PAD_REQUEST &&
|
|
|
|
desttempl->direction != srctempl->direction) {
|
2011-05-17 10:04:27 +00:00
|
|
|
GstCaps *srccaps, *destcaps;
|
|
|
|
|
|
|
|
srccaps = gst_pad_template_get_caps (srctempl);
|
|
|
|
destcaps = gst_pad_template_get_caps (desttempl);
|
|
|
|
if (gst_caps_is_always_compatible (srccaps, destcaps)) {
|
2005-03-07 18:27:42 +00:00
|
|
|
srcpad =
|
2010-12-20 12:30:43 +00:00
|
|
|
gst_element_request_pad (src, srctempl,
|
|
|
|
srctempl->name_template, NULL);
|
2005-03-07 18:27:42 +00:00
|
|
|
destpad =
|
2010-12-20 12:30:43 +00:00
|
|
|
gst_element_request_pad (dest, desttempl,
|
|
|
|
desttempl->name_template, NULL);
|
2008-02-01 11:27:32 +00:00
|
|
|
if (srcpad && destpad
|
2010-06-23 15:00:17 +00:00
|
|
|
&& pad_link_maybe_ghosting (srcpad, destpad, flags)) {
|
2005-03-07 18:27:42 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"linked pad %s:%s to pad %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (srcpad);
|
|
|
|
gst_object_unref (destpad);
|
2011-05-17 10:04:27 +00:00
|
|
|
gst_caps_unref (srccaps);
|
|
|
|
gst_caps_unref (destcaps);
|
2005-03-07 18:27:42 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/* it failed, so we release the request pads */
|
2008-02-01 11:27:32 +00:00
|
|
|
if (srcpad)
|
|
|
|
gst_element_release_request_pad (src, srcpad);
|
|
|
|
if (destpad)
|
|
|
|
gst_element_release_request_pad (dest, destpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
2011-05-17 10:04:27 +00:00
|
|
|
gst_caps_unref (srccaps);
|
|
|
|
gst_caps_unref (destcaps);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srctempls = srctempls->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s",
|
|
|
|
GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2010-06-23 15:00:17 +00:00
|
|
|
/**
|
|
|
|
* gst_element_link_pads:
|
|
|
|
* @src: a #GstElement containing the source pad.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @srcpadname: (allow-none): the name of the #GstPad in source element
|
|
|
|
* or NULL for any pad.
|
|
|
|
* @dest: (transfer none): the #GstElement containing the destination pad.
|
|
|
|
* @destpadname: (allow-none): the name of the #GstPad in destination element,
|
2010-06-23 15:00:17 +00:00
|
|
|
* or NULL for any pad.
|
|
|
|
*
|
|
|
|
* Links the two named pads of the source and destination elements.
|
|
|
|
* Side effect is that if one of the pads has no parent, it becomes a
|
|
|
|
* child of the parent of the other element. If they have different
|
|
|
|
* parents, the link fails.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_link_pads (GstElement * src, const gchar * srcpadname,
|
|
|
|
GstElement * dest, const gchar * destpadname)
|
|
|
|
{
|
|
|
|
return gst_element_link_pads_full (src, srcpadname, dest, destpadname,
|
|
|
|
GST_PAD_LINK_CHECK_DEFAULT);
|
|
|
|
}
|
|
|
|
|
2005-07-13 16:26:07 +00:00
|
|
|
/**
|
|
|
|
* gst_element_link_pads_filtered:
|
|
|
|
* @src: a #GstElement containing the source pad.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @srcpadname: (allow-none): the name of the #GstPad in source element
|
|
|
|
* or NULL for any pad.
|
|
|
|
* @dest: (transfer none): the #GstElement containing the destination pad.
|
|
|
|
* @destpadname: (allow-none): the name of the #GstPad in destination element
|
|
|
|
* or NULL for any pad.
|
|
|
|
* @filter: (transfer none) (allow-none): the #GstCaps to filter the link,
|
|
|
|
* or #NULL for no filter.
|
2005-07-13 16:26:07 +00:00
|
|
|
*
|
|
|
|
* Links the two named pads of the source and destination elements. Side effect
|
|
|
|
* is that if one of the pads has no parent, it becomes a child of the parent of
|
|
|
|
* the other element. If they have different parents, the link fails. If @caps
|
|
|
|
* is not #NULL, makes sure that the caps of the link is a subset of @caps.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
|
|
|
GstElement * dest, const gchar * destpadname, GstCaps * filter)
|
|
|
|
{
|
|
|
|
/* checks */
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
|
|
|
|
g_return_val_if_fail (filter == NULL || GST_IS_CAPS (filter), FALSE);
|
|
|
|
|
|
|
|
if (filter) {
|
|
|
|
GstElement *capsfilter;
|
|
|
|
GstObject *parent;
|
2005-09-02 15:42:00 +00:00
|
|
|
GstState state, pending;
|
2010-06-30 08:46:11 +00:00
|
|
|
gboolean lr1, lr2;
|
2005-07-13 16:26:07 +00:00
|
|
|
|
|
|
|
capsfilter = gst_element_factory_make ("capsfilter", NULL);
|
|
|
|
if (!capsfilter) {
|
|
|
|
GST_ERROR ("Could not make a capsfilter");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
parent = gst_object_get_parent (GST_OBJECT (src));
|
|
|
|
g_return_val_if_fail (GST_IS_BIN (parent), FALSE);
|
|
|
|
|
Use GstClockTime in _get_state() instead of GTimeVal.
Original commit message from CVS:
* check/gst/gstbin.c: (GST_START_TEST):
* check/gst/gstelement.c: (GST_START_TEST):
* check/gst/gstevent.c: (GST_START_TEST), (test_event):
* check/gst/gstghostpad.c: (GST_START_TEST):
* check/gst/gstpipeline.c: (GST_START_TEST):
* check/pipelines/simple_launch_lines.c: (run_pipeline):
* check/states/sinks.c: (GST_START_TEST):
* gst/elements/gsttypefindelement.c: (stop_typefinding):
* gst/gstbin.c: (gst_bin_provide_clock_func), (gst_bin_add_func),
(gst_bin_remove_func), (gst_bin_get_state_func),
(gst_bin_recalc_state), (gst_bin_change_state_func),
(bin_bus_handler):
* gst/gstelement.c: (gst_element_get_state_func),
(gst_element_get_state), (gst_element_abort_state),
(gst_element_commit_state), (gst_element_set_state),
(gst_element_change_state), (gst_element_change_state_func):
* gst/gstelement.h:
* gst/gstpipeline.c: (gst_pipeline_class_init), (do_pipeline_seek),
(gst_pipeline_provide_clock_func):
* gst/gstutils.c: (gst_element_link_pads_filtered):
* tools/gst-launch.c: (main):
* tools/gst-typefind.c: (main):
Use GstClockTime in _get_state() instead of GTimeVal.
Remove old code in gstutils.c
2005-10-12 12:18:48 +00:00
|
|
|
gst_element_get_state (GST_ELEMENT_CAST (parent), &state, &pending, 0);
|
2005-08-30 19:29:59 +00:00
|
|
|
|
2005-07-13 16:26:07 +00:00
|
|
|
if (!gst_bin_add (GST_BIN (parent), capsfilter)) {
|
|
|
|
GST_ERROR ("Could not add capsfilter");
|
|
|
|
gst_object_unref (capsfilter);
|
|
|
|
gst_object_unref (parent);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-08-30 19:29:59 +00:00
|
|
|
if (pending != GST_STATE_VOID_PENDING)
|
|
|
|
state = pending;
|
|
|
|
|
|
|
|
gst_element_set_state (capsfilter, state);
|
|
|
|
|
2005-07-13 16:26:07 +00:00
|
|
|
gst_object_unref (parent);
|
|
|
|
|
2005-09-29 12:37:38 +00:00
|
|
|
g_object_set (capsfilter, "caps", filter, NULL);
|
2005-07-13 16:26:07 +00:00
|
|
|
|
2010-06-30 08:46:11 +00:00
|
|
|
lr1 = gst_element_link_pads (src, srcpadname, capsfilter, "sink");
|
|
|
|
lr2 = gst_element_link_pads (capsfilter, "src", dest, destpadname);
|
|
|
|
if (lr1 && lr2) {
|
2005-07-13 16:26:07 +00:00
|
|
|
return TRUE;
|
|
|
|
} else {
|
2010-06-30 08:46:11 +00:00
|
|
|
if (!lr1) {
|
|
|
|
GST_INFO ("Could not link pads: %s:%s - capsfilter:sink",
|
|
|
|
GST_ELEMENT_NAME (src), srcpadname);
|
|
|
|
} else {
|
|
|
|
GST_INFO ("Could not link pads: capsfilter:src - %s:%s",
|
|
|
|
GST_ELEMENT_NAME (dest), destpadname);
|
|
|
|
}
|
2006-08-31 17:13:34 +00:00
|
|
|
gst_element_set_state (capsfilter, GST_STATE_NULL);
|
|
|
|
/* this will unlink and unref as appropriate */
|
2005-07-13 16:26:07 +00:00
|
|
|
gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (capsfilter)), capsfilter);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
2010-06-30 08:46:11 +00:00
|
|
|
if (gst_element_link_pads (src, srcpadname, dest, destpadname)) {
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
GST_INFO ("Could not link pads: %s:%s - %s:%s", GST_ELEMENT_NAME (src),
|
|
|
|
srcpadname, GST_ELEMENT_NAME (dest), destpadname);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-07-13 16:26:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/**
|
2005-04-24 21:16:45 +00:00
|
|
|
* gst_element_link:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @src: (transfer none): a #GstElement containing the source pad.
|
|
|
|
* @dest: (transfer none): the #GstElement containing the destination pad.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
2005-04-24 21:16:45 +00:00
|
|
|
* Links @src to @dest. The link must be from source to
|
2005-03-07 18:27:42 +00:00
|
|
|
* destination; the other direction will not be tried. The function looks for
|
|
|
|
* existing pads that aren't linked yet. It will request new pads if necessary.
|
2011-09-07 11:14:38 +00:00
|
|
|
* Such pads need to be released manually when unlinking.
|
2005-03-07 18:27:42 +00:00
|
|
|
* If multiple links are possible, only one is established.
|
|
|
|
*
|
2006-07-26 11:43:23 +00:00
|
|
|
* Make sure you have added your elements to a bin or pipeline with
|
|
|
|
* gst_bin_add() before trying to link them.
|
|
|
|
*
|
2005-03-07 18:27:42 +00:00
|
|
|
* Returns: TRUE if the elements could be linked, FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
2005-04-24 21:16:45 +00:00
|
|
|
gst_element_link (GstElement * src, GstElement * dest)
|
2005-03-07 18:27:42 +00:00
|
|
|
{
|
2010-01-10 19:40:24 +00:00
|
|
|
return gst_element_link_pads (src, NULL, dest, NULL);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_link_many:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element_1: (transfer none): the first #GstElement in the link chain.
|
|
|
|
* @element_2: (transfer none): the second #GstElement in the link chain.
|
2005-03-07 18:27:42 +00:00
|
|
|
* @...: the NULL-terminated list of elements to link in order.
|
|
|
|
*
|
|
|
|
* Chain together a series of elements. Uses gst_element_link().
|
2006-07-26 11:43:23 +00:00
|
|
|
* Make sure you have added your elements to a bin or pipeline with
|
|
|
|
* gst_bin_add() before trying to link them.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Returns: TRUE on success, FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
|
|
|
|
{
|
2009-02-04 13:41:24 +00:00
|
|
|
gboolean res = TRUE;
|
2005-03-07 18:27:42 +00:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element_1), FALSE);
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element_2), FALSE);
|
|
|
|
|
|
|
|
va_start (args, element_2);
|
|
|
|
|
|
|
|
while (element_2) {
|
2009-02-04 13:41:24 +00:00
|
|
|
if (!gst_element_link (element_1, element_2)) {
|
|
|
|
res = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
element_1 = element_2;
|
|
|
|
element_2 = va_arg (args, GstElement *);
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
|
2009-02-04 13:41:24 +00:00
|
|
|
return res;
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2005-08-31 15:27:55 +00:00
|
|
|
/**
|
|
|
|
* gst_element_link_filtered:
|
|
|
|
* @src: a #GstElement containing the source pad.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @dest: (transfer none): the #GstElement containing the destination pad.
|
|
|
|
* @filter: (transfer none) (allow-none): the #GstCaps to filter the link,
|
|
|
|
* or #NULL for no filter.
|
2005-08-31 15:27:55 +00:00
|
|
|
*
|
|
|
|
* Links @src to @dest using the given caps as filtercaps.
|
|
|
|
* The link must be from source to
|
|
|
|
* destination; the other direction will not be tried. The function looks for
|
|
|
|
* existing pads that aren't linked yet. It will request new pads if necessary.
|
|
|
|
* If multiple links are possible, only one is established.
|
|
|
|
*
|
2006-07-26 11:43:23 +00:00
|
|
|
* Make sure you have added your elements to a bin or pipeline with
|
|
|
|
* gst_bin_add() before trying to link them.
|
|
|
|
*
|
2005-08-31 15:27:55 +00:00
|
|
|
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_link_filtered (GstElement * src, GstElement * dest,
|
|
|
|
GstCaps * filter)
|
|
|
|
{
|
|
|
|
return gst_element_link_pads_filtered (src, NULL, dest, NULL, filter);
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/**
|
|
|
|
* gst_element_unlink_pads:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @src: a (transfer none): #GstElement containing the source pad.
|
2005-03-07 18:27:42 +00:00
|
|
|
* @srcpadname: the name of the #GstPad in source element.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @dest: (transfer none): a #GstElement containing the destination pad.
|
2005-03-07 18:27:42 +00:00
|
|
|
* @destpadname: the name of the #GstPad in destination element.
|
|
|
|
*
|
|
|
|
* Unlinks the two named pads of the source and destination elements.
|
2011-02-28 14:27:01 +00:00
|
|
|
*
|
2011-02-28 15:01:54 +00:00
|
|
|
* This is a convenience function for gst_pad_unlink().
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_element_unlink_pads (GstElement * src, const gchar * srcpadname,
|
|
|
|
GstElement * dest, const gchar * destpadname)
|
|
|
|
{
|
|
|
|
GstPad *srcpad, *destpad;
|
2008-05-21 15:57:52 +00:00
|
|
|
gboolean srcrequest, destrequest;
|
|
|
|
|
|
|
|
srcrequest = destrequest = FALSE;
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
g_return_if_fail (src != NULL);
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (src));
|
|
|
|
g_return_if_fail (srcpadname != NULL);
|
|
|
|
g_return_if_fail (dest != NULL);
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (dest));
|
|
|
|
g_return_if_fail (destpadname != NULL);
|
|
|
|
|
|
|
|
/* obtain the pads requested */
|
2008-05-21 15:57:52 +00:00
|
|
|
if (!(srcpad = gst_element_get_static_pad (src, srcpadname)))
|
|
|
|
if ((srcpad = gst_element_get_request_pad (src, srcpadname)))
|
|
|
|
srcrequest = TRUE;
|
2005-03-07 18:27:42 +00:00
|
|
|
if (srcpad == NULL) {
|
|
|
|
GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
|
|
|
|
return;
|
|
|
|
}
|
2008-05-21 15:57:52 +00:00
|
|
|
if (!(destpad = gst_element_get_static_pad (dest, destpadname)))
|
|
|
|
if ((destpad = gst_element_get_request_pad (dest, destpadname)))
|
|
|
|
destrequest = TRUE;
|
2006-01-28 00:59:37 +00:00
|
|
|
if (destpad == NULL) {
|
2005-03-07 18:27:42 +00:00
|
|
|
GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"",
|
|
|
|
destpadname);
|
2008-05-21 15:57:52 +00:00
|
|
|
goto free_src;
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2011-09-07 11:14:38 +00:00
|
|
|
/* we're satisfied they can be unlinked, let's do it */
|
2005-03-07 18:27:42 +00:00
|
|
|
gst_pad_unlink (srcpad, destpad);
|
2008-05-21 15:57:52 +00:00
|
|
|
|
|
|
|
if (destrequest)
|
|
|
|
gst_element_release_request_pad (dest, destpad);
|
2006-01-28 00:59:37 +00:00
|
|
|
gst_object_unref (destpad);
|
2008-05-21 15:57:52 +00:00
|
|
|
|
|
|
|
free_src:
|
|
|
|
if (srcrequest)
|
|
|
|
gst_element_release_request_pad (src, srcpad);
|
|
|
|
gst_object_unref (srcpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_unlink_many:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element_1: (transfer none): the first #GstElement in the link chain.
|
|
|
|
* @element_2: (transfer none): the second #GstElement in the link chain.
|
2005-03-07 18:27:42 +00:00
|
|
|
* @...: the NULL-terminated list of elements to unlink in order.
|
|
|
|
*
|
|
|
|
* Unlinks a series of elements. Uses gst_element_unlink().
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_element_unlink_many (GstElement * element_1, GstElement * element_2, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
g_return_if_fail (element_1 != NULL && element_2 != NULL);
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
|
|
|
|
|
|
|
|
va_start (args, element_2);
|
|
|
|
|
|
|
|
while (element_2) {
|
|
|
|
gst_element_unlink (element_1, element_2);
|
|
|
|
|
|
|
|
element_1 = element_2;
|
|
|
|
element_2 = va_arg (args, GstElement *);
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_unlink:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @src: (transfer none): the source #GstElement to unlink.
|
|
|
|
* @dest: (transfer none): the sink #GstElement to unlink.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Unlinks all source pads of the source element with all sink pads
|
|
|
|
* of the sink element to which they are linked.
|
2007-04-29 17:36:18 +00:00
|
|
|
*
|
|
|
|
* If the link has been made using gst_element_link(), it could have created an
|
|
|
|
* requestpad, which has to be released using gst_element_release_request_pad().
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_element_unlink (GstElement * src, GstElement * dest)
|
|
|
|
{
|
|
|
|
GstIterator *pads;
|
|
|
|
gboolean done = FALSE;
|
2011-03-17 10:31:59 +00:00
|
|
|
GValue data = { 0, };
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (src));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (dest));
|
|
|
|
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
|
|
|
|
GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
|
|
|
|
|
|
|
|
pads = gst_element_iterate_pads (src);
|
|
|
|
while (!done) {
|
|
|
|
switch (gst_iterator_next (pads, &data)) {
|
|
|
|
case GST_ITERATOR_OK:
|
|
|
|
{
|
2011-03-17 10:31:59 +00:00
|
|
|
GstPad *pad = g_value_get_object (&data);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
gst/gstutils.c: RPAD fixes all around.
Original commit message from CVS:
2005-06-08 Andy Wingo <wingo@pobox.com>
* gst/gstutils.c: RPAD fixes all around.
(gst_element_link_pads): Refcounting fixes.
* tools/gst-inspect.c:
* tools/gst-xmlinspect.c:
* parse/grammar.y:
* gst/base/gsttypefindhelper.c:
* gst/base/gstbasesink.c:
* gst/gstqueue.c: RPAD fixes.
* gst/gstghostpad.h:
* gst/gstghostpad.c: New ghost pad implementation as full proxy
pads. The tricky thing is they provide both source and sink
interfaces, since they proxy the internal pad for the external
pad, and vice versa. Implement with lower-level ProxyPad objects,
with the interior proxy pad as a child of the exterior ghost pad.
Should write a doc on this.
* gst/gstpad.h: s/RPAD/PAD/, s/RealPad/Pad/.
(gst_pad_set_name, gst_pad_set_parent): Macros removed, use
gst_object API.
* gst/gstpad.c: Big changes. No more stub base GstPad, now all
pads are real pads. No ghost pads in this file. Not documenting
the myriad s/RPAD/PAD/ and REALIZE fixes.
(gst_pad_class_init): Add properties for "direction" and
"template". Both are construct-only, so they can't change during
the life of the pad. Fixes properly deriving from GstPad.
(gst_pad_custom_new, gst_pad_custom_new_from_template): Gone. For
derived objects, just set properties when creating the objects via
g_object_new.
(gst_pad_get_parent): Implement as a function, return NULL if the
parent is not an element.
(gst_pad_get_real_parent, gst_pad_add_ghost_pad)
(gst_pad_remove_ghost_pad, gst_pad_realize): Removed.
* gst/gstobject.c (gst_object_class_init): Make name a construct
property. Don't set it in the object init.
* gst/gstelement.c (gst_element_add_pad): Don't allow adding pads
with UNKNOWN direction.
(gst_element_add_ghost_pad): Remove non-orthogonal API. Replace
with gst_element_add_pad (e, gst_ghost_pad_new (name, pad)).
(gst_element_remove_pad): Remove ghost-pad special cases.
(gst_element_pads_activate): Remove rpad cruft.
* gst/gstbin.c (gst_bin_change_state): Use gst_pad_get_parent to
catch the pad's-parent-not-an-element case.
* gst/gst.h: Include gstghostpad.h.
* gst/gst.c (init_post): No more real, ghost pads.
* gst/Makefile.am: Add gstghostpad.[ch].
* check/Makefile.am:
* check/gst/gstbin.c:
* check/gst/gstghostpad.c (test_ghost_pads): Check that linking
into a bin creates ghost pads, and that the refcounts are right.
Partly moved from gstbin.c.
2005-06-08 22:16:27 +00:00
|
|
|
if (GST_PAD_IS_SRC (pad)) {
|
2005-03-07 18:27:42 +00:00
|
|
|
GstPad *peerpad = gst_pad_get_peer (pad);
|
|
|
|
|
2008-05-25 16:34:32 +00:00
|
|
|
/* see if the pad is linked and is really a pad of dest */
|
2005-03-07 18:27:42 +00:00
|
|
|
if (peerpad) {
|
docs/design/: Some more docs in the works.
Original commit message from CVS:
* docs/design/part-dynamic.txt:
* docs/design/part-events.txt:
* docs/design/part-seeking.txt:
Some more docs in the works.
* gst/base/gstbasetransform.c: (gst_base_transform_transform_caps),
(gst_base_transform_getcaps), (gst_base_transform_configure_caps),
(gst_base_transform_setcaps), (gst_base_transform_get_size),
(gst_base_transform_buffer_alloc), (gst_base_transform_event),
(gst_base_transform_handle_buffer),
(gst_base_transform_sink_activate_push),
(gst_base_transform_src_activate_pull),
(gst_base_transform_set_passthrough),
(gst_base_transform_is_passthrough):
Refcounting fixes.
* gst/gstbus.c: (gst_bus_source_dispatch), (gst_bus_poll):
Cleanups.
* gst/gstevent.c: (gst_event_finalize):
Set SRC to NULL.
* gst/gstutils.c: (gst_element_unlink),
(gst_pad_get_parent_element), (gst_pad_proxy_getcaps),
(gst_pad_proxy_setcaps):
* gst/gstutils.h:
Add _get_parent_element() to get a pads parent as an element.
2005-07-18 08:28:48 +00:00
|
|
|
GstElement *peerelem;
|
|
|
|
|
|
|
|
peerelem = gst_pad_get_parent_element (peerpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
if (peerelem == dest) {
|
|
|
|
gst_pad_unlink (pad, peerpad);
|
|
|
|
}
|
|
|
|
if (peerelem)
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (peerelem);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2005-06-28 09:59:01 +00:00
|
|
|
gst_object_unref (peerpad);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
}
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_reset (&data);
|
2005-03-07 18:27:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GST_ITERATOR_RESYNC:
|
|
|
|
gst_iterator_resync (pads);
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_DONE:
|
|
|
|
done = TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_unset (&data);
|
2006-07-14 16:20:18 +00:00
|
|
|
gst_iterator_free (pads);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
/**
|
|
|
|
* gst_element_query_position:
|
|
|
|
* @element: a #GstElement to invoke the position query on.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @format: the #GstFormat requested
|
2010-12-07 18:35:04 +00:00
|
|
|
* @cur: (out) (allow-none): a location in which to store the current
|
|
|
|
* position, or NULL.
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
*
|
2011-02-28 14:27:01 +00:00
|
|
|
* Queries an element for the stream position. If one repeatedly calls this
|
|
|
|
* function one can also create and reuse it in gst_element_query().
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
2005-05-09 10:53:13 +00:00
|
|
|
gboolean
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_element_query_position (GstElement * element, GstFormat format,
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
gint64 * cur)
|
2005-05-09 10:53:13 +00:00
|
|
|
{
|
|
|
|
GstQuery *query;
|
|
|
|
gboolean ret;
|
|
|
|
|
2005-05-12 12:27:07 +00:00
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (format != GST_FORMAT_UNDEFINED, FALSE);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
query = gst_query_new_position (format);
|
2011-05-17 09:20:05 +00:00
|
|
|
ret = gst_element_query (element, query);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
if (ret)
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_query_parse_position (query, NULL, cur);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
gst_query_unref (query);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
/**
|
|
|
|
* gst_element_query_duration:
|
|
|
|
* @element: a #GstElement to invoke the duration query on.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @format: the #GstFormat requested
|
2009-09-17 20:30:43 +00:00
|
|
|
* @duration: (out): A location in which to store the total duration, or NULL.
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
*
|
|
|
|
* Queries an element for the total stream duration.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
|
|
|
gboolean
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_element_query_duration (GstElement * element, GstFormat format,
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
gint64 * duration)
|
|
|
|
{
|
|
|
|
GstQuery *query;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (format != GST_FORMAT_UNDEFINED, FALSE);
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
query = gst_query_new_duration (format);
|
2011-05-17 09:20:05 +00:00
|
|
|
ret = gst_element_query (element, query);
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
|
|
|
|
if (ret)
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_query_parse_duration (query, NULL, duration);
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
|
|
|
|
gst_query_unref (query);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_query_convert:
|
|
|
|
* @element: a #GstElement to invoke the convert query on.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @src_format: (inout): a #GstFormat to convert from.
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
* @src_val: a value to convert.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @dest_format: the #GstFormat to convert to.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @dest_val: (out): a pointer to the result.
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
*
|
|
|
|
* Queries an element to convert @src_val in @src_format to @dest_format.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
2005-05-09 10:53:13 +00:00
|
|
|
gboolean
|
|
|
|
gst_element_query_convert (GstElement * element, GstFormat src_format,
|
2011-07-26 23:17:02 +00:00
|
|
|
gint64 src_val, GstFormat dest_format, gint64 * dest_val)
|
2005-05-09 10:53:13 +00:00
|
|
|
{
|
|
|
|
GstQuery *query;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (dest_format != GST_FORMAT_UNDEFINED, FALSE);
|
2005-05-09 10:53:13 +00:00
|
|
|
g_return_val_if_fail (dest_val != NULL, FALSE);
|
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
if (dest_format == src_format || src_val == -1) {
|
2005-05-09 10:53:13 +00:00
|
|
|
*dest_val = src_val;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
query = gst_query_new_convert (src_format, src_val, dest_format);
|
2011-05-17 09:20:05 +00:00
|
|
|
ret = gst_element_query (element, query);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
if (ret)
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_query_parse_convert (query, NULL, NULL, NULL, dest_val);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
gst_query_unref (query);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-05-19 10:29:07 +00:00
|
|
|
/**
|
|
|
|
* gst_element_seek_simple
|
|
|
|
* @element: a #GstElement to seek on
|
|
|
|
* @format: a #GstFormat to execute the seek in, such as #GST_FORMAT_TIME
|
2007-06-07 17:22:47 +00:00
|
|
|
* @seek_flags: seek options; playback applications will usually want to use
|
|
|
|
* GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT here
|
2006-05-19 10:29:07 +00:00
|
|
|
* @seek_pos: position to seek to (relative to the start); if you are doing
|
|
|
|
* a seek in #GST_FORMAT_TIME this value is in nanoseconds -
|
|
|
|
* multiply with #GST_SECOND to convert seconds to nanoseconds or
|
|
|
|
* with #GST_MSECOND to convert milliseconds to nanoseconds.
|
|
|
|
*
|
|
|
|
* Simple API to perform a seek on the given element, meaning it just seeks
|
|
|
|
* to the given position relative to the start of the stream. For more complex
|
|
|
|
* operations like segment seeks (e.g. for looping) or changing the playback
|
gst/gstbin.c: Update documentation.
Original commit message from CVS:
* gst/gstbin.c:
Update documentation.
* gst/gstelement.c: (gst_element_class_init),
(gst_element_release_request_pad), (gst_element_set_clock),
(gst_element_get_index), (gst_element_add_pad),
(gst_element_remove_pad), (gst_element_get_random_pad),
(gst_element_send_event), (gst_element_get_query_types),
(gst_element_query), (gst_element_post_message),
(gst_element_message_full), (gst_element_continue_state),
(gst_element_lost_state), (gst_element_save_thyself),
(gst_element_restore_thyself):
Documentation updates.
Rename last bit of the new-pad -> pad-added signal rename.
Fix the case where an element query would only work if the source
pad was linked.
Avoid some useless type checking in message handling.
* gst/gstevent.c:
* gst/gstevent.h:
* gst/gstutils.c:
Documentation updates.
2006-09-15 08:32:57 +00:00
|
|
|
* rate or seeking relative to the last configured playback segment you should
|
|
|
|
* use gst_element_seek().
|
2006-05-19 10:29:07 +00:00
|
|
|
*
|
gst/gstbin.c: Update documentation.
Original commit message from CVS:
* gst/gstbin.c:
Update documentation.
* gst/gstelement.c: (gst_element_class_init),
(gst_element_release_request_pad), (gst_element_set_clock),
(gst_element_get_index), (gst_element_add_pad),
(gst_element_remove_pad), (gst_element_get_random_pad),
(gst_element_send_event), (gst_element_get_query_types),
(gst_element_query), (gst_element_post_message),
(gst_element_message_full), (gst_element_continue_state),
(gst_element_lost_state), (gst_element_save_thyself),
(gst_element_restore_thyself):
Documentation updates.
Rename last bit of the new-pad -> pad-added signal rename.
Fix the case where an element query would only work if the source
pad was linked.
Avoid some useless type checking in message handling.
* gst/gstevent.c:
* gst/gstevent.h:
* gst/gstutils.c:
Documentation updates.
2006-09-15 08:32:57 +00:00
|
|
|
* In a completely prerolled PAUSED or PLAYING pipeline, seeking is always
|
|
|
|
* guaranteed to return %TRUE on a seekable media type or %FALSE when the media
|
|
|
|
* type is certainly not seekable (such as a live stream).
|
2006-05-19 10:29:07 +00:00
|
|
|
*
|
gst/gstbin.c: Update documentation.
Original commit message from CVS:
* gst/gstbin.c:
Update documentation.
* gst/gstelement.c: (gst_element_class_init),
(gst_element_release_request_pad), (gst_element_set_clock),
(gst_element_get_index), (gst_element_add_pad),
(gst_element_remove_pad), (gst_element_get_random_pad),
(gst_element_send_event), (gst_element_get_query_types),
(gst_element_query), (gst_element_post_message),
(gst_element_message_full), (gst_element_continue_state),
(gst_element_lost_state), (gst_element_save_thyself),
(gst_element_restore_thyself):
Documentation updates.
Rename last bit of the new-pad -> pad-added signal rename.
Fix the case where an element query would only work if the source
pad was linked.
Avoid some useless type checking in message handling.
* gst/gstevent.c:
* gst/gstevent.h:
* gst/gstutils.c:
Documentation updates.
2006-09-15 08:32:57 +00:00
|
|
|
* Some elements allow for seeking in the READY state, in this
|
|
|
|
* case they will store the seek event and execute it when they are put to
|
|
|
|
* PAUSED. If the element supports seek in READY, it will always return %TRUE when
|
|
|
|
* it receives the event in the READY state.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the seek operation succeeded (the seek might not always be
|
|
|
|
* executed instantly though)
|
2006-05-19 10:29:07 +00:00
|
|
|
*
|
|
|
|
* Since: 0.10.7
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_element_seek_simple (GstElement * element, GstFormat format,
|
|
|
|
GstSeekFlags seek_flags, gint64 seek_pos)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
|
|
|
g_return_val_if_fail (seek_pos >= 0, FALSE);
|
|
|
|
|
|
|
|
return gst_element_seek (element, 1.0, format, seek_flags,
|
|
|
|
GST_SEEK_TYPE_SET, seek_pos, GST_SEEK_TYPE_NONE, 0);
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_use_fixed_caps:
|
|
|
|
* @pad: the pad to use
|
|
|
|
*
|
2011-05-06 15:59:33 +00:00
|
|
|
* A helper function you can use that sets the FIXED_CAPS flag
|
|
|
|
* This way the default getcaps function will always return the negotiated caps
|
2005-03-07 18:27:42 +00:00
|
|
|
* or in case the pad is not negotiated, the padtemplate caps.
|
2005-07-12 17:17:34 +00:00
|
|
|
*
|
2009-11-25 14:44:05 +00:00
|
|
|
* Use this function on a pad that, once gst_pad_set_caps() has been called
|
2005-10-24 09:13:27 +00:00
|
|
|
* on it, cannot be renegotiated to something else.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_pad_use_fixed_caps (GstPad * pad)
|
|
|
|
{
|
2011-05-06 15:59:33 +00:00
|
|
|
GST_OBJECT_FLAG_SET (pad, GST_PAD_FIXED_CAPS);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
docs/design/: Some more docs in the works.
Original commit message from CVS:
* docs/design/part-dynamic.txt:
* docs/design/part-events.txt:
* docs/design/part-seeking.txt:
Some more docs in the works.
* gst/base/gstbasetransform.c: (gst_base_transform_transform_caps),
(gst_base_transform_getcaps), (gst_base_transform_configure_caps),
(gst_base_transform_setcaps), (gst_base_transform_get_size),
(gst_base_transform_buffer_alloc), (gst_base_transform_event),
(gst_base_transform_handle_buffer),
(gst_base_transform_sink_activate_push),
(gst_base_transform_src_activate_pull),
(gst_base_transform_set_passthrough),
(gst_base_transform_is_passthrough):
Refcounting fixes.
* gst/gstbus.c: (gst_bus_source_dispatch), (gst_bus_poll):
Cleanups.
* gst/gstevent.c: (gst_event_finalize):
Set SRC to NULL.
* gst/gstutils.c: (gst_element_unlink),
(gst_pad_get_parent_element), (gst_pad_proxy_getcaps),
(gst_pad_proxy_setcaps):
* gst/gstutils.h:
Add _get_parent_element() to get a pads parent as an element.
2005-07-18 08:28:48 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_get_parent_element:
|
|
|
|
* @pad: a pad
|
|
|
|
*
|
|
|
|
* Gets the parent of @pad, cast to a #GstElement. If a @pad has no parent or
|
|
|
|
* its parent is not an element, return NULL.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Returns: (transfer full): the parent of the pad. The caller has a
|
|
|
|
* reference on the parent, so unref when you're finished with it.
|
docs/design/: Some more docs in the works.
Original commit message from CVS:
* docs/design/part-dynamic.txt:
* docs/design/part-events.txt:
* docs/design/part-seeking.txt:
Some more docs in the works.
* gst/base/gstbasetransform.c: (gst_base_transform_transform_caps),
(gst_base_transform_getcaps), (gst_base_transform_configure_caps),
(gst_base_transform_setcaps), (gst_base_transform_get_size),
(gst_base_transform_buffer_alloc), (gst_base_transform_event),
(gst_base_transform_handle_buffer),
(gst_base_transform_sink_activate_push),
(gst_base_transform_src_activate_pull),
(gst_base_transform_set_passthrough),
(gst_base_transform_is_passthrough):
Refcounting fixes.
* gst/gstbus.c: (gst_bus_source_dispatch), (gst_bus_poll):
Cleanups.
* gst/gstevent.c: (gst_event_finalize):
Set SRC to NULL.
* gst/gstutils.c: (gst_element_unlink),
(gst_pad_get_parent_element), (gst_pad_proxy_getcaps),
(gst_pad_proxy_setcaps):
* gst/gstutils.h:
Add _get_parent_element() to get a pads parent as an element.
2005-07-18 08:28:48 +00:00
|
|
|
*
|
|
|
|
* MT safe.
|
|
|
|
*/
|
|
|
|
GstElement *
|
|
|
|
gst_pad_get_parent_element (GstPad * pad)
|
|
|
|
{
|
|
|
|
GstObject *p;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
|
|
|
|
|
|
|
p = gst_object_get_parent (GST_OBJECT_CAST (pad));
|
|
|
|
|
|
|
|
if (p && !GST_IS_ELEMENT (p)) {
|
|
|
|
gst_object_unref (p);
|
|
|
|
p = NULL;
|
|
|
|
}
|
|
|
|
return GST_ELEMENT_CAST (p);
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
/**
|
|
|
|
* gst_object_default_error:
|
2005-08-25 23:17:18 +00:00
|
|
|
* @source: the #GstObject that initiated the error.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @error: (in): the GError.
|
|
|
|
* @debug: (in) (allow-none): an additional debug information string, or NULL
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
2011-06-02 13:38:04 +00:00
|
|
|
* A default error function that uses g_printerr() to display the error message
|
|
|
|
* and the optional debug sting..
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* The default handler will simply print the error string using g_print.
|
|
|
|
*/
|
|
|
|
void
|
2010-12-07 19:35:24 +00:00
|
|
|
gst_object_default_error (GstObject * source, const GError * error,
|
|
|
|
const gchar * debug)
|
2005-03-07 18:27:42 +00:00
|
|
|
{
|
|
|
|
gchar *name = gst_object_get_path_string (source);
|
|
|
|
|
2011-06-02 13:38:04 +00:00
|
|
|
g_printerr (_("ERROR: from element %s: %s\n"), name, error->message);
|
2005-03-07 18:27:42 +00:00
|
|
|
if (debug)
|
2011-06-02 13:38:04 +00:00
|
|
|
g_printerr (_("Additional debug info:\n%s\n"), debug);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
g_free (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_bin_add_many:
|
2005-10-28 17:35:43 +00:00
|
|
|
* @bin: a #GstBin
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element_1: (transfer full): the #GstElement element to add to the bin
|
|
|
|
* @...: (transfer full): additional elements to add to the bin
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Adds a NULL-terminated list of elements to a bin. This function is
|
2007-10-05 14:44:18 +00:00
|
|
|
* equivalent to calling gst_bin_add() for each member of the list. The return
|
|
|
|
* value of each gst_bin_add() is ignored.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (element_1));
|
|
|
|
|
|
|
|
va_start (args, element_1);
|
|
|
|
|
|
|
|
while (element_1) {
|
|
|
|
gst_bin_add (bin, element_1);
|
|
|
|
|
|
|
|
element_1 = va_arg (args, GstElement *);
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_bin_remove_many:
|
2005-10-28 17:35:43 +00:00
|
|
|
* @bin: a #GstBin
|
2010-12-07 18:35:04 +00:00
|
|
|
* @element_1: (transfer none): the first #GstElement to remove from the bin
|
|
|
|
* @...: (transfer none): NULL-terminated list of elements to remove from the bin
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Remove a list of elements from a bin. This function is equivalent
|
2005-08-24 21:35:43 +00:00
|
|
|
* to calling gst_bin_remove() with each member of the list.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (element_1));
|
|
|
|
|
|
|
|
va_start (args, element_1);
|
|
|
|
|
|
|
|
while (element_1) {
|
|
|
|
gst_bin_remove (bin, element_1);
|
|
|
|
|
|
|
|
element_1 = va_arg (args, GstElement *);
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_element_populate_std_props (GObjectClass * klass, const gchar * prop_name,
|
|
|
|
guint arg_id, GParamFlags flags)
|
|
|
|
{
|
|
|
|
GQuark prop_id = g_quark_from_string (prop_name);
|
|
|
|
GParamSpec *pspec;
|
|
|
|
|
|
|
|
static GQuark fd_id = 0;
|
|
|
|
static GQuark blocksize_id;
|
|
|
|
static GQuark bytesperread_id;
|
|
|
|
static GQuark dump_id;
|
|
|
|
static GQuark filesize_id;
|
|
|
|
static GQuark mmapsize_id;
|
|
|
|
static GQuark location_id;
|
|
|
|
static GQuark offset_id;
|
|
|
|
static GQuark silent_id;
|
|
|
|
static GQuark touch_id;
|
|
|
|
|
2010-06-04 15:10:05 +00:00
|
|
|
flags |= G_PARAM_STATIC_STRINGS;
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
if (!fd_id) {
|
|
|
|
fd_id = g_quark_from_static_string ("fd");
|
|
|
|
blocksize_id = g_quark_from_static_string ("blocksize");
|
|
|
|
bytesperread_id = g_quark_from_static_string ("bytesperread");
|
|
|
|
dump_id = g_quark_from_static_string ("dump");
|
|
|
|
filesize_id = g_quark_from_static_string ("filesize");
|
|
|
|
mmapsize_id = g_quark_from_static_string ("mmapsize");
|
|
|
|
location_id = g_quark_from_static_string ("location");
|
|
|
|
offset_id = g_quark_from_static_string ("offset");
|
|
|
|
silent_id = g_quark_from_static_string ("silent");
|
|
|
|
touch_id = g_quark_from_static_string ("touch");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prop_id == fd_id) {
|
|
|
|
pspec = g_param_spec_int ("fd", "File-descriptor",
|
|
|
|
"File-descriptor for the file being read", 0, G_MAXINT, 0, flags);
|
|
|
|
} else if (prop_id == blocksize_id) {
|
|
|
|
pspec = g_param_spec_ulong ("blocksize", "Block Size",
|
|
|
|
"Block size to read per buffer", 0, G_MAXULONG, 4096, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == bytesperread_id) {
|
|
|
|
pspec = g_param_spec_int ("bytesperread", "Bytes per read",
|
|
|
|
"Number of bytes to read per buffer", G_MININT, G_MAXINT, 0, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == dump_id) {
|
|
|
|
pspec = g_param_spec_boolean ("dump", "Dump",
|
|
|
|
"Dump bytes to stdout", FALSE, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == filesize_id) {
|
|
|
|
pspec = g_param_spec_int64 ("filesize", "File Size",
|
|
|
|
"Size of the file being read", 0, G_MAXINT64, 0, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == mmapsize_id) {
|
|
|
|
pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
|
|
|
|
"Size in bytes of mmap()d regions", 0, G_MAXULONG, 4 * 1048576, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == location_id) {
|
|
|
|
pspec = g_param_spec_string ("location", "File Location",
|
|
|
|
"Location of the file to read", NULL, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == offset_id) {
|
|
|
|
pspec = g_param_spec_int64 ("offset", "File Offset",
|
|
|
|
"Byte offset of current read pointer", 0, G_MAXINT64, 0, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == silent_id) {
|
|
|
|
pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
|
|
|
|
FALSE, flags);
|
|
|
|
|
|
|
|
} else if (prop_id == touch_id) {
|
|
|
|
pspec = g_param_spec_boolean ("touch", "Touch read data",
|
|
|
|
"Touch data to force disk read before " "push ()", TRUE, flags);
|
|
|
|
} else {
|
|
|
|
g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
|
|
|
|
prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
|
|
|
|
pspec = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pspec) {
|
|
|
|
g_object_class_install_property (klass, arg_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_element_class_install_std_props:
|
|
|
|
* @klass: the #GstElementClass to add the properties to.
|
|
|
|
* @first_name: the name of the first property.
|
|
|
|
* in a NULL terminated
|
|
|
|
* @...: the id and flags of the first property, followed by
|
|
|
|
* further 'name', 'id', 'flags' triplets and terminated by NULL.
|
|
|
|
*
|
|
|
|
* Adds a list of standardized properties with types to the @klass.
|
|
|
|
* the id is for the property switch in your get_prop method, and
|
|
|
|
* the flags determine readability / writeability.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
gst_element_class_install_std_props (GstElementClass * klass,
|
|
|
|
const gchar * first_name, ...)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
|
|
|
|
|
|
|
|
va_start (args, first_name);
|
|
|
|
|
|
|
|
name = first_name;
|
|
|
|
|
|
|
|
while (name) {
|
|
|
|
int arg_id = va_arg (args, int);
|
2011-08-25 20:29:45 +00:00
|
|
|
GParamFlags flags = (GParamFlags) va_arg (args, int);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id,
|
|
|
|
flags);
|
|
|
|
|
|
|
|
name = va_arg (args, char *);
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_buffer_merge:
|
2010-12-07 18:35:04 +00:00
|
|
|
* @buf1: (transfer none): the first source #GstBuffer to merge.
|
|
|
|
* @buf2: (transfer none): the second source #GstBuffer to merge.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Create a new buffer that is the concatenation of the two source
|
|
|
|
* buffers. The original source buffers will not be modified or
|
|
|
|
* unref'd. Make sure you unref the source buffers if they are not used
|
|
|
|
* anymore afterwards.
|
|
|
|
*
|
|
|
|
* If the buffers point to contiguous areas of memory, the buffer
|
|
|
|
* is created without copying the data.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Free-function: gst_buffer_unref
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): the new #GstBuffer which is the concatenation
|
|
|
|
* of the source buffers.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
GstBuffer *
|
|
|
|
gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
|
|
|
|
{
|
|
|
|
GstBuffer *result;
|
2011-03-21 17:13:55 +00:00
|
|
|
gsize size1, size2;
|
|
|
|
|
|
|
|
size1 = gst_buffer_get_size (buf1);
|
|
|
|
size2 = gst_buffer_get_size (buf2);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
/* we're just a specific case of the more general gst_buffer_span() */
|
2011-03-21 17:13:55 +00:00
|
|
|
result = gst_buffer_span (buf1, 0, buf2, size1 + size2);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
gst/base/gstbasesrc.c: Don't go in pull mode for non-seekable sources.
Original commit message from CVS:
* gst/base/gstbasesrc.c: (gst_basesrc_activate):
Don't go in pull mode for non-seekable sources.
* gst/elements/gsttypefindelement.c: (gst_type_find_element_init),
(gst_type_find_element_dispose), (gst_type_find_handle_src_query),
(free_entry), (stop_typefinding),
(gst_type_find_element_handle_event), (find_peek),
(gst_type_find_element_chain), (do_pull_typefind),
(gst_type_find_element_change_state):
Allow typefinding (w/o seeking) in push-mode, simplified version
of what was in 0.8.
* gst/gstutils.c: (gst_buffer_join):
* gst/gstutils.h:
gst_buffer_join() from 0.8.
2005-05-25 15:57:57 +00:00
|
|
|
/**
|
gst/: Removed atomic operations, use existing LOCK.
Original commit message from CVS:
* gst/gstpad.c: (_gst_do_pass_data_accumulator),
(default_have_data), (gst_pad_class_init), (gst_pad_init),
(gst_pad_emit_have_data_signal), (gst_pad_chain), (gst_pad_push),
(gst_pad_check_pull_range), (gst_pad_get_range),
(gst_pad_pull_range), (gst_pad_push_event), (gst_pad_send_event):
* gst/gstpad.h:
* gst/gstutils.c: (gst_atomic_int_set), (gst_pad_add_data_probe),
(gst_pad_add_event_probe), (gst_pad_add_buffer_probe),
(gst_pad_remove_data_probe), (gst_pad_remove_event_probe),
(gst_pad_remove_buffer_probe):
Removed atomic operations, use existing LOCK.
Move exception handling out of main code path.
2005-06-30 09:23:54 +00:00
|
|
|
* gst_buffer_join:
|
2011-10-14 07:35:09 +00:00
|
|
|
* @buf1: (transfer full): the first source #GstBuffer.
|
|
|
|
* @buf2: (transfer full): the second source #GstBuffer.
|
gst/base/gstbasesrc.c: Don't go in pull mode for non-seekable sources.
Original commit message from CVS:
* gst/base/gstbasesrc.c: (gst_basesrc_activate):
Don't go in pull mode for non-seekable sources.
* gst/elements/gsttypefindelement.c: (gst_type_find_element_init),
(gst_type_find_element_dispose), (gst_type_find_handle_src_query),
(free_entry), (stop_typefinding),
(gst_type_find_element_handle_event), (find_peek),
(gst_type_find_element_chain), (do_pull_typefind),
(gst_type_find_element_change_state):
Allow typefinding (w/o seeking) in push-mode, simplified version
of what was in 0.8.
* gst/gstutils.c: (gst_buffer_join):
* gst/gstutils.h:
gst_buffer_join() from 0.8.
2005-05-25 15:57:57 +00:00
|
|
|
*
|
|
|
|
* Create a new buffer that is the concatenation of the two source
|
2005-10-28 17:01:14 +00:00
|
|
|
* buffers, and unrefs the original source buffers.
|
gst/base/gstbasesrc.c: Don't go in pull mode for non-seekable sources.
Original commit message from CVS:
* gst/base/gstbasesrc.c: (gst_basesrc_activate):
Don't go in pull mode for non-seekable sources.
* gst/elements/gsttypefindelement.c: (gst_type_find_element_init),
(gst_type_find_element_dispose), (gst_type_find_handle_src_query),
(free_entry), (stop_typefinding),
(gst_type_find_element_handle_event), (find_peek),
(gst_type_find_element_chain), (do_pull_typefind),
(gst_type_find_element_change_state):
Allow typefinding (w/o seeking) in push-mode, simplified version
of what was in 0.8.
* gst/gstutils.c: (gst_buffer_join):
* gst/gstutils.h:
gst_buffer_join() from 0.8.
2005-05-25 15:57:57 +00:00
|
|
|
*
|
|
|
|
* If the buffers point to contiguous areas of memory, the buffer
|
|
|
|
* is created without copying the data.
|
|
|
|
*
|
2009-08-28 10:21:28 +00:00
|
|
|
* This is a convenience function for C programmers. See also
|
|
|
|
* gst_buffer_merge(), which does the same thing without
|
|
|
|
* unreffing the input parameters. Language bindings without
|
2008-08-20 07:22:11 +00:00
|
|
|
* explicit reference counting should not wrap this function.
|
|
|
|
*
|
2010-12-17 18:14:41 +00:00
|
|
|
* Returns: (transfer full): the new #GstBuffer which is the concatenation of
|
|
|
|
* the source buffers.
|
gst/base/gstbasesrc.c: Don't go in pull mode for non-seekable sources.
Original commit message from CVS:
* gst/base/gstbasesrc.c: (gst_basesrc_activate):
Don't go in pull mode for non-seekable sources.
* gst/elements/gsttypefindelement.c: (gst_type_find_element_init),
(gst_type_find_element_dispose), (gst_type_find_handle_src_query),
(free_entry), (stop_typefinding),
(gst_type_find_element_handle_event), (find_peek),
(gst_type_find_element_chain), (do_pull_typefind),
(gst_type_find_element_change_state):
Allow typefinding (w/o seeking) in push-mode, simplified version
of what was in 0.8.
* gst/gstutils.c: (gst_buffer_join):
* gst/gstutils.h:
gst_buffer_join() from 0.8.
2005-05-25 15:57:57 +00:00
|
|
|
*/
|
|
|
|
GstBuffer *
|
|
|
|
gst_buffer_join (GstBuffer * buf1, GstBuffer * buf2)
|
|
|
|
{
|
|
|
|
GstBuffer *result;
|
2011-03-21 17:13:55 +00:00
|
|
|
gsize size1, size2;
|
|
|
|
|
|
|
|
size1 = gst_buffer_get_size (buf1);
|
|
|
|
size2 = gst_buffer_get_size (buf2);
|
gst/base/gstbasesrc.c: Don't go in pull mode for non-seekable sources.
Original commit message from CVS:
* gst/base/gstbasesrc.c: (gst_basesrc_activate):
Don't go in pull mode for non-seekable sources.
* gst/elements/gsttypefindelement.c: (gst_type_find_element_init),
(gst_type_find_element_dispose), (gst_type_find_handle_src_query),
(free_entry), (stop_typefinding),
(gst_type_find_element_handle_event), (find_peek),
(gst_type_find_element_chain), (do_pull_typefind),
(gst_type_find_element_change_state):
Allow typefinding (w/o seeking) in push-mode, simplified version
of what was in 0.8.
* gst/gstutils.c: (gst_buffer_join):
* gst/gstutils.h:
gst_buffer_join() from 0.8.
2005-05-25 15:57:57 +00:00
|
|
|
|
2011-03-21 17:13:55 +00:00
|
|
|
result = gst_buffer_span (buf1, 0, buf2, size1 + size2);
|
gst/base/gstbasesrc.c: Don't go in pull mode for non-seekable sources.
Original commit message from CVS:
* gst/base/gstbasesrc.c: (gst_basesrc_activate):
Don't go in pull mode for non-seekable sources.
* gst/elements/gsttypefindelement.c: (gst_type_find_element_init),
(gst_type_find_element_dispose), (gst_type_find_handle_src_query),
(free_entry), (stop_typefinding),
(gst_type_find_element_handle_event), (find_peek),
(gst_type_find_element_chain), (do_pull_typefind),
(gst_type_find_element_change_state):
Allow typefinding (w/o seeking) in push-mode, simplified version
of what was in 0.8.
* gst/gstutils.c: (gst_buffer_join):
* gst/gstutils.h:
gst_buffer_join() from 0.8.
2005-05-25 15:57:57 +00:00
|
|
|
gst_buffer_unref (buf1);
|
|
|
|
gst_buffer_unref (buf2);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2005-03-07 18:27:42 +00:00
|
|
|
static gboolean
|
2011-05-10 15:56:33 +00:00
|
|
|
getcaps_fold_func (const GValue * vpad, GValue * ret, GstCaps * filter)
|
2005-03-07 18:27:42 +00:00
|
|
|
{
|
2011-03-17 10:31:59 +00:00
|
|
|
GstPad *pad = g_value_get_object (vpad);
|
2009-12-08 15:09:02 +00:00
|
|
|
gboolean empty = FALSE;
|
2009-12-08 15:21:41 +00:00
|
|
|
GstCaps *peercaps, *existing;
|
2009-12-08 15:09:02 +00:00
|
|
|
|
2009-12-08 15:21:41 +00:00
|
|
|
existing = g_value_get_pointer (ret);
|
2011-05-10 15:56:33 +00:00
|
|
|
peercaps = gst_pad_peer_get_caps (pad, filter);
|
2009-12-08 15:21:41 +00:00
|
|
|
if (G_LIKELY (peercaps)) {
|
|
|
|
GstCaps *intersection = gst_caps_intersect (existing, peercaps);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2009-12-08 15:21:41 +00:00
|
|
|
empty = gst_caps_is_empty (intersection);
|
2009-12-08 15:09:02 +00:00
|
|
|
|
2009-12-08 15:21:41 +00:00
|
|
|
g_value_set_pointer (ret, intersection);
|
|
|
|
gst_caps_unref (existing);
|
|
|
|
gst_caps_unref (peercaps);
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
2009-12-08 15:09:02 +00:00
|
|
|
return !empty;
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_pad_proxy_getcaps:
|
|
|
|
* @pad: a #GstPad to proxy.
|
2011-05-10 15:56:33 +00:00
|
|
|
* @filter: a #GstCaps filter.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
|
|
|
* Calls gst_pad_get_allowed_caps() for every other pad belonging to the
|
|
|
|
* same element as @pad, and returns the intersection of the results.
|
|
|
|
*
|
|
|
|
* This function is useful as a default getcaps function for an element
|
|
|
|
* that can handle any stream format, but requires all its pads to have
|
2009-09-30 13:41:07 +00:00
|
|
|
* the same caps. Two such elements are tee and adder.
|
2005-03-07 18:27:42 +00:00
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Free-function: gst_caps_unref
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): the intersection of the other pads' allowed caps.
|
2005-03-07 18:27:42 +00:00
|
|
|
*/
|
|
|
|
GstCaps *
|
2011-05-10 15:56:33 +00:00
|
|
|
gst_pad_proxy_getcaps (GstPad * pad, GstCaps * filter)
|
2005-03-07 18:27:42 +00:00
|
|
|
{
|
|
|
|
GstElement *element;
|
|
|
|
GstCaps *caps, *intersected;
|
|
|
|
GstIterator *iter;
|
|
|
|
GstIteratorResult res;
|
|
|
|
GValue ret = { 0, };
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
|
|
|
|
2009-01-03 18:10:08 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_PADS, "proxying getcaps for %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (pad));
|
2005-03-07 18:27:42 +00:00
|
|
|
|
docs/design/: Some more docs in the works.
Original commit message from CVS:
* docs/design/part-dynamic.txt:
* docs/design/part-events.txt:
* docs/design/part-seeking.txt:
Some more docs in the works.
* gst/base/gstbasetransform.c: (gst_base_transform_transform_caps),
(gst_base_transform_getcaps), (gst_base_transform_configure_caps),
(gst_base_transform_setcaps), (gst_base_transform_get_size),
(gst_base_transform_buffer_alloc), (gst_base_transform_event),
(gst_base_transform_handle_buffer),
(gst_base_transform_sink_activate_push),
(gst_base_transform_src_activate_pull),
(gst_base_transform_set_passthrough),
(gst_base_transform_is_passthrough):
Refcounting fixes.
* gst/gstbus.c: (gst_bus_source_dispatch), (gst_bus_poll):
Cleanups.
* gst/gstevent.c: (gst_event_finalize):
Set SRC to NULL.
* gst/gstutils.c: (gst_element_unlink),
(gst_pad_get_parent_element), (gst_pad_proxy_getcaps),
(gst_pad_proxy_setcaps):
* gst/gstutils.h:
Add _get_parent_element() to get a pads parent as an element.
2005-07-18 08:28:48 +00:00
|
|
|
element = gst_pad_get_parent_element (pad);
|
gst/: Fix name lookup in GstBin.
Original commit message from CVS:
* gst/gstbin.c: (gst_bin_send_event), (compare_name),
(gst_bin_get_by_name):
* gst/gstbuffer.h:
* gst/gstclock.c: (gst_clock_entry_new), (gst_clock_class_init),
(gst_clock_finalize):
* gst/gstdata.c: (gst_data_replace):
* gst/gstdata.h:
* gst/gstelement.c: (gst_element_request_pad),
(gst_element_pads_activate):
* gst/gstobject.c: (gst_object_init), (gst_object_ref),
(gst_object_unref):
* gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
(gst_pad_set_checkgetrange_function),
(gst_pad_link_check_compatible_unlocked), (gst_pad_set_caps),
(gst_pad_check_pull_range), (gst_pad_pull_range),
(gst_static_pad_template_get_caps), (gst_pad_start_task),
(gst_pad_pause_task), (gst_pad_stop_task):
* gst/gstutils.c: (gst_element_get_compatible_pad_template),
(gst_element_request_pad), (gst_pad_proxy_getcaps):
Fix name lookup in GstBin.
Added _data_replace() function and _buffer_replace()
Use finalize method to clean up clock.
Fix refcounting on request pads.
Fix pad schedule mode error.
Some more object refcounting debug info,
2005-05-05 09:28:01 +00:00
|
|
|
if (element == NULL)
|
2009-12-08 15:21:41 +00:00
|
|
|
goto no_parent;
|
2005-03-07 18:27:42 +00:00
|
|
|
|
2006-08-23 10:59:47 +00:00
|
|
|
/* value to hold the return, by default it holds ANY, the ref is taken by
|
|
|
|
* the GValue. */
|
2005-03-07 18:27:42 +00:00
|
|
|
g_value_init (&ret, G_TYPE_POINTER);
|
|
|
|
g_value_set_pointer (&ret, gst_caps_new_any ());
|
|
|
|
|
2009-12-08 15:21:41 +00:00
|
|
|
/* only iterate the pads in the oposite direction */
|
|
|
|
if (GST_PAD_IS_SRC (pad))
|
|
|
|
iter = gst_element_iterate_sink_pads (element);
|
|
|
|
else
|
|
|
|
iter = gst_element_iterate_src_pads (element);
|
|
|
|
|
2006-08-23 10:59:47 +00:00
|
|
|
while (1) {
|
|
|
|
res =
|
2009-12-08 15:14:28 +00:00
|
|
|
gst_iterator_fold (iter, (GstIteratorFoldFunction) getcaps_fold_func,
|
2011-05-10 15:56:33 +00:00
|
|
|
&ret, filter);
|
2006-08-23 10:59:47 +00:00
|
|
|
switch (res) {
|
|
|
|
case GST_ITERATOR_RESYNC:
|
|
|
|
/* unref any value stored */
|
|
|
|
if ((caps = g_value_get_pointer (&ret)))
|
|
|
|
gst_caps_unref (caps);
|
|
|
|
/* need to reset the result again to ANY */
|
|
|
|
g_value_set_pointer (&ret, gst_caps_new_any ());
|
|
|
|
gst_iterator_resync (iter);
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_DONE:
|
|
|
|
/* all pads iterated, return collected value */
|
|
|
|
goto done;
|
2010-08-05 00:06:57 +00:00
|
|
|
case GST_ITERATOR_OK:
|
|
|
|
/* premature exit (happens if caps intersection is empty) */
|
|
|
|
goto done;
|
2006-08-23 10:59:47 +00:00
|
|
|
default:
|
2010-08-05 00:06:57 +00:00
|
|
|
/* iterator returned _ERROR, mark an error and exit */
|
2006-08-23 10:59:47 +00:00
|
|
|
if ((caps = g_value_get_pointer (&ret)))
|
|
|
|
gst_caps_unref (caps);
|
|
|
|
g_value_set_pointer (&ret, NULL);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
2005-03-07 18:27:42 +00:00
|
|
|
gst_iterator_free (iter);
|
|
|
|
|
2005-09-27 15:37:40 +00:00
|
|
|
gst_object_unref (element);
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
caps = g_value_get_pointer (&ret);
|
|
|
|
g_value_unset (&ret);
|
|
|
|
|
2009-12-08 15:21:41 +00:00
|
|
|
if (caps) {
|
|
|
|
intersected =
|
|
|
|
gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
|
|
|
|
gst_caps_unref (caps);
|
|
|
|
} else {
|
|
|
|
intersected = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
|
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
|
|
|
|
return intersected;
|
2005-09-27 15:37:40 +00:00
|
|
|
|
|
|
|
/* ERRORS */
|
2009-12-08 15:21:41 +00:00
|
|
|
no_parent:
|
|
|
|
{
|
|
|
|
GST_DEBUG_OBJECT (pad, "no parent");
|
|
|
|
return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
|
|
|
|
}
|
2006-08-23 10:59:47 +00:00
|
|
|
error:
|
2005-09-27 15:37:40 +00:00
|
|
|
{
|
2006-08-23 10:59:47 +00:00
|
|
|
g_warning ("Pad list returned error on element %s",
|
2005-09-27 15:37:40 +00:00
|
|
|
GST_ELEMENT_NAME (element));
|
2006-08-23 10:59:47 +00:00
|
|
|
gst_iterator_free (iter);
|
2005-09-27 15:37:40 +00:00
|
|
|
gst_object_unref (element);
|
2009-12-08 15:21:41 +00:00
|
|
|
return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
|
2005-09-27 15:37:40 +00:00
|
|
|
}
|
2005-03-07 18:27:42 +00:00
|
|
|
}
|
|
|
|
|
2005-05-09 10:53:13 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_query_position:
|
|
|
|
* @pad: a #GstPad to invoke the position query on.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @format: the #GstFormat requested
|
2009-09-17 20:30:43 +00:00
|
|
|
* @cur: (out): A location in which to store the current position, or NULL.
|
2005-05-09 10:53:13 +00:00
|
|
|
*
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
* Queries a pad for the stream position.
|
2005-05-09 10:53:13 +00:00
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
|
|
|
gboolean
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_pad_query_position (GstPad * pad, GstFormat format, gint64 * cur)
|
2005-05-09 10:53:13 +00:00
|
|
|
{
|
|
|
|
GstQuery *query;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (format != GST_FORMAT_UNDEFINED, FALSE);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
query = gst_query_new_position (format);
|
2011-05-17 09:20:05 +00:00
|
|
|
ret = gst_pad_query (pad, query);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
if (ret)
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_query_parse_position (query, NULL, cur);
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
|
|
|
|
gst_query_unref (query);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-03-23 18:45:02 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_query_peer_position:
|
|
|
|
* @pad: a #GstPad on whose peer to invoke the position query on.
|
|
|
|
* Must be a sink pad.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @format: the #GstFormat requested
|
2010-12-07 18:35:04 +00:00
|
|
|
* @cur: (out) (allow-none): a location in which to store the current
|
|
|
|
* position, or NULL.
|
2006-03-23 18:45:02 +00:00
|
|
|
*
|
|
|
|
* Queries the peer of a given sink pad for the stream position.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
|
|
|
gboolean
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_pad_query_peer_position (GstPad * pad, GstFormat format, gint64 * cur)
|
2006-03-23 18:45:02 +00:00
|
|
|
{
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
GstPad *peer;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
|
|
|
g_return_val_if_fail (GST_PAD_IS_SINK (pad), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (format != GST_FORMAT_UNDEFINED, FALSE);
|
2006-03-23 18:45:02 +00:00
|
|
|
|
|
|
|
peer = gst_pad_get_peer (pad);
|
|
|
|
if (peer) {
|
|
|
|
ret = gst_pad_query_position (peer, format, cur);
|
|
|
|
gst_object_unref (peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_query_duration:
|
|
|
|
* @pad: a #GstPad to invoke the duration query on.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @format: the #GstFormat requested
|
2010-12-07 18:35:04 +00:00
|
|
|
* @duration: (out) (allow-none): a location in which to store the total
|
|
|
|
* duration, or NULL.
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
*
|
|
|
|
* Queries a pad for the total stream duration.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
|
|
|
gboolean
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_pad_query_duration (GstPad * pad, GstFormat format, gint64 * duration)
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
{
|
|
|
|
GstQuery *query;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (format != GST_FORMAT_UNDEFINED, FALSE);
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
query = gst_query_new_duration (format);
|
2011-05-17 09:20:05 +00:00
|
|
|
ret = gst_pad_query (pad, query);
|
gst/: API change fix.
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_commit_state),
(gst_base_sink_handle_object), (gst_base_sink_query), (do_playing):
* gst/base/gstbasesrc.c: (gst_base_src_query):
* gst/elements/gstfilesink.c: (gst_file_sink_query):
* gst/elements/gsttypefindelement.c:
(gst_type_find_handle_src_query), (find_element_get_length),
(gst_type_find_element_activate):
API change fix.
* gst/gstquery.c: (gst_query_new_position),
(gst_query_set_position), (gst_query_parse_position),
(gst_query_new_duration), (gst_query_set_duration),
(gst_query_parse_duration), (gst_query_set_segment),
(gst_query_parse_segment):
* gst/gstquery.h:
Bundling query position/duration is not a good idea since duration
does not change much and we don't want to recalculate it for every
position query, so they are separated again..
Base value in segment query is not needed.
* gst/gstqueue.c: (gst_queue_handle_src_query):
* gst/gstutils.c: (gst_element_query_position),
(gst_element_query_duration), (gst_pad_query_position),
(gst_pad_query_duration):
* gst/gstutils.h:
Updates for query API change.
Added some docs here and there.
2005-10-19 15:50:10 +00:00
|
|
|
|
|
|
|
if (ret)
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_query_parse_duration (query, NULL, duration);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
gst_query_unref (query);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-03-23 18:45:02 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_query_peer_duration:
|
|
|
|
* @pad: a #GstPad on whose peer pad to invoke the duration query on.
|
|
|
|
* Must be a sink pad.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @format: the #GstFormat requested
|
2010-12-07 18:35:04 +00:00
|
|
|
* @duration: (out) (allow-none): a location in which to store the total
|
|
|
|
* duration, or NULL.
|
2006-03-23 18:45:02 +00:00
|
|
|
*
|
|
|
|
* Queries the peer pad of a given sink pad for the total stream duration.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
|
|
|
gboolean
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_pad_query_peer_duration (GstPad * pad, GstFormat format, gint64 * duration)
|
2006-03-23 18:45:02 +00:00
|
|
|
{
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
GstPad *peer;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
|
|
|
g_return_val_if_fail (GST_PAD_IS_SINK (pad), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (format != GST_FORMAT_UNDEFINED, FALSE);
|
2006-03-23 18:45:02 +00:00
|
|
|
|
|
|
|
peer = gst_pad_get_peer (pad);
|
|
|
|
if (peer) {
|
|
|
|
ret = gst_pad_query_duration (peer, format, duration);
|
|
|
|
gst_object_unref (peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-05-09 10:53:13 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_query_convert:
|
|
|
|
* @pad: a #GstPad to invoke the convert query on.
|
|
|
|
* @src_format: a #GstFormat to convert from.
|
|
|
|
* @src_val: a value to convert.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @dest_format: the #GstFormat to convert to.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @dest_val: (out): a pointer to the result.
|
2005-05-09 10:53:13 +00:00
|
|
|
*
|
|
|
|
* Queries a pad to convert @src_val in @src_format to @dest_format.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_pad_query_convert (GstPad * pad, GstFormat src_format, gint64 src_val,
|
2011-07-26 23:17:02 +00:00
|
|
|
GstFormat dest_format, gint64 * dest_val)
|
2005-05-09 10:53:13 +00:00
|
|
|
{
|
|
|
|
GstQuery *query;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (dest_format != GST_FORMAT_UNDEFINED, FALSE);
|
2005-05-09 10:53:13 +00:00
|
|
|
g_return_val_if_fail (dest_val != NULL, FALSE);
|
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
if (dest_format == src_format || src_val == -1) {
|
2005-05-09 10:53:13 +00:00
|
|
|
*dest_val = src_val;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-07-26 23:17:02 +00:00
|
|
|
query = gst_query_new_convert (src_format, src_val, dest_format);
|
2011-05-17 09:20:05 +00:00
|
|
|
ret = gst_pad_query (pad, query);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
if (ret)
|
2011-07-26 23:17:02 +00:00
|
|
|
gst_query_parse_convert (query, NULL, NULL, NULL, dest_val);
|
2005-05-09 10:53:13 +00:00
|
|
|
|
|
|
|
gst_query_unref (query);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2005-04-24 22:49:45 +00:00
|
|
|
|
2006-03-23 18:45:02 +00:00
|
|
|
/**
|
|
|
|
* gst_pad_query_peer_convert:
|
|
|
|
* @pad: a #GstPad, on whose peer pad to invoke the convert query on.
|
|
|
|
* Must be a sink pad.
|
|
|
|
* @src_format: a #GstFormat to convert from.
|
|
|
|
* @src_val: a value to convert.
|
2011-07-26 23:17:02 +00:00
|
|
|
* @dest_format: the #GstFormat to convert to.
|
2010-12-07 18:35:04 +00:00
|
|
|
* @dest_val: (out): a pointer to the result.
|
2006-03-23 18:45:02 +00:00
|
|
|
*
|
|
|
|
* Queries the peer pad of a given sink pad to convert @src_val in @src_format
|
|
|
|
* to @dest_format.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the query could be performed.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_pad_query_peer_convert (GstPad * pad, GstFormat src_format, gint64 src_val,
|
2011-07-26 23:17:02 +00:00
|
|
|
GstFormat dest_format, gint64 * dest_val)
|
2006-03-23 18:45:02 +00:00
|
|
|
{
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
GstPad *peer;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
|
|
|
g_return_val_if_fail (GST_PAD_IS_SINK (pad), FALSE);
|
2011-07-26 23:17:02 +00:00
|
|
|
g_return_val_if_fail (dest_format != GST_FORMAT_UNDEFINED, FALSE);
|
2006-03-23 18:45:02 +00:00
|
|
|
g_return_val_if_fail (dest_val != NULL, FALSE);
|
|
|
|
|
|
|
|
peer = gst_pad_get_peer (pad);
|
|
|
|
if (peer) {
|
|
|
|
ret = gst_pad_query_convert (peer, src_format, src_val, dest_format,
|
|
|
|
dest_val);
|
|
|
|
gst_object_unref (peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-02-02 09:51:18 +00:00
|
|
|
static GstPad *
|
2008-05-25 16:34:32 +00:00
|
|
|
element_find_unlinked_pad (GstElement * element, GstPadDirection direction)
|
2006-02-02 09:51:18 +00:00
|
|
|
{
|
|
|
|
GstIterator *iter;
|
2008-05-25 16:34:32 +00:00
|
|
|
GstPad *unlinked_pad = NULL;
|
2006-02-02 09:51:18 +00:00
|
|
|
gboolean done;
|
2011-03-17 10:31:59 +00:00
|
|
|
GValue data = { 0, };
|
2006-02-02 09:51:18 +00:00
|
|
|
|
|
|
|
switch (direction) {
|
|
|
|
case GST_PAD_SRC:
|
|
|
|
iter = gst_element_iterate_src_pads (element);
|
|
|
|
break;
|
|
|
|
case GST_PAD_SINK:
|
|
|
|
iter = gst_element_iterate_sink_pads (element);
|
|
|
|
break;
|
|
|
|
default:
|
2007-12-13 13:59:04 +00:00
|
|
|
g_return_val_if_reached (NULL);
|
2006-02-02 09:51:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
done = FALSE;
|
|
|
|
while (!done) {
|
2011-03-17 10:31:59 +00:00
|
|
|
switch (gst_iterator_next (iter, &data)) {
|
2006-02-02 09:51:18 +00:00
|
|
|
case GST_ITERATOR_OK:{
|
|
|
|
GstPad *peer;
|
2011-03-17 10:31:59 +00:00
|
|
|
GstPad *pad = g_value_get_object (&data);
|
2006-02-02 09:51:18 +00:00
|
|
|
|
|
|
|
GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examining pad %s:%s",
|
|
|
|
GST_DEBUG_PAD_NAME (pad));
|
|
|
|
|
2011-03-17 10:31:59 +00:00
|
|
|
peer = gst_pad_get_peer (pad);
|
2006-02-02 09:51:18 +00:00
|
|
|
if (peer == NULL) {
|
2011-03-17 10:31:59 +00:00
|
|
|
unlinked_pad = gst_object_ref (pad);
|
2006-02-02 09:51:18 +00:00
|
|
|
done = TRUE;
|
|
|
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
|
|
|
"found existing unlinked pad %s:%s",
|
2008-05-25 16:34:32 +00:00
|
|
|
GST_DEBUG_PAD_NAME (unlinked_pad));
|
2006-02-02 09:51:18 +00:00
|
|
|
} else {
|
|
|
|
gst_object_unref (peer);
|
|
|
|
}
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_reset (&data);
|
2006-02-02 09:51:18 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GST_ITERATOR_DONE:
|
|
|
|
done = TRUE;
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_RESYNC:
|
|
|
|
gst_iterator_resync (iter);
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_ERROR:
|
|
|
|
g_return_val_if_reached (NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_unset (&data);
|
2006-02-02 09:51:18 +00:00
|
|
|
gst_iterator_free (iter);
|
|
|
|
|
2008-05-25 16:34:32 +00:00
|
|
|
return unlinked_pad;
|
2006-02-02 09:51:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-05-27 10:50:49 +00:00
|
|
|
* gst_bin_find_unlinked_pad:
|
2008-05-25 16:34:32 +00:00
|
|
|
* @bin: bin in which to look for elements with unlinked pads
|
|
|
|
* @direction: whether to look for an unlinked source or sink pad
|
2006-02-02 09:51:18 +00:00
|
|
|
*
|
2008-05-25 16:34:32 +00:00
|
|
|
* Recursively looks for elements with an unlinked pad of the given
|
|
|
|
* direction within the specified bin and returns an unlinked pad
|
2006-02-02 09:51:18 +00:00
|
|
|
* if one is found, or NULL otherwise. If a pad is found, the caller
|
|
|
|
* owns a reference to it and should use gst_object_unref() on the
|
|
|
|
* pad when it is not needed any longer.
|
|
|
|
*
|
2010-12-07 18:35:04 +00:00
|
|
|
* Returns: (transfer full): unlinked pad of the given direction, or NULL.
|
2006-02-02 09:51:18 +00:00
|
|
|
*
|
2008-05-27 10:50:49 +00:00
|
|
|
* Since: 0.10.20
|
2006-02-02 09:51:18 +00:00
|
|
|
*/
|
|
|
|
GstPad *
|
2008-05-27 10:50:49 +00:00
|
|
|
gst_bin_find_unlinked_pad (GstBin * bin, GstPadDirection direction)
|
2006-02-02 09:51:18 +00:00
|
|
|
{
|
|
|
|
GstIterator *iter;
|
|
|
|
gboolean done;
|
|
|
|
GstPad *pad = NULL;
|
2011-03-17 10:31:59 +00:00
|
|
|
GValue data = { 0, };
|
2006-02-02 09:51:18 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
|
|
|
g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL);
|
|
|
|
|
|
|
|
done = FALSE;
|
|
|
|
iter = gst_bin_iterate_recurse (bin);
|
|
|
|
while (!done) {
|
2011-03-17 10:31:59 +00:00
|
|
|
switch (gst_iterator_next (iter, &data)) {
|
|
|
|
case GST_ITERATOR_OK:{
|
|
|
|
GstElement *element = g_value_get_object (&data);
|
2006-02-02 09:51:18 +00:00
|
|
|
|
2011-03-17 10:31:59 +00:00
|
|
|
pad = element_find_unlinked_pad (element, direction);
|
2006-02-02 09:51:18 +00:00
|
|
|
if (pad != NULL)
|
|
|
|
done = TRUE;
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_reset (&data);
|
2006-02-02 09:51:18 +00:00
|
|
|
break;
|
2011-03-17 10:31:59 +00:00
|
|
|
}
|
2006-02-02 09:51:18 +00:00
|
|
|
case GST_ITERATOR_DONE:
|
|
|
|
done = TRUE;
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_RESYNC:
|
|
|
|
gst_iterator_resync (iter);
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_ERROR:
|
|
|
|
g_return_val_if_reached (NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-03-17 10:31:59 +00:00
|
|
|
g_value_unset (&data);
|
2006-02-02 09:51:18 +00:00
|
|
|
gst_iterator_free (iter);
|
|
|
|
|
|
|
|
return pad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_parse_bin_from_description:
|
|
|
|
* @bin_description: command line describing the bin
|
2008-05-25 16:34:32 +00:00
|
|
|
* @ghost_unlinked_pads: whether to automatically create ghost pads
|
|
|
|
* for unlinked source or sink pads within the bin
|
2006-02-02 09:51:18 +00:00
|
|
|
* @err: where to store the error message in case of an error, or NULL
|
|
|
|
*
|
|
|
|
* This is a convenience wrapper around gst_parse_launch() to create a
|
|
|
|
* #GstBin from a gst-launch-style pipeline description. See
|
|
|
|
* gst_parse_launch() and the gst-launch man page for details about the
|
2008-05-25 16:34:32 +00:00
|
|
|
* syntax. Ghost pads on the bin for unlinked source or sink pads
|
2006-02-02 09:51:18 +00:00
|
|
|
* within the bin can automatically be created (but only a maximum of
|
|
|
|
* one ghost pad for each direction will be created; if you expect
|
2008-05-25 16:34:32 +00:00
|
|
|
* multiple unlinked source pads or multiple unlinked sink pads
|
2006-02-02 09:51:18 +00:00
|
|
|
* and want them all ghosted, you will have to create the ghost pads
|
|
|
|
* yourself).
|
|
|
|
*
|
2010-12-17 18:14:41 +00:00
|
|
|
* Returns: (transfer full): a newly-created bin, or NULL if an error occurred.
|
2006-02-02 09:51:18 +00:00
|
|
|
*
|
|
|
|
* Since: 0.10.3
|
|
|
|
*/
|
|
|
|
GstElement *
|
|
|
|
gst_parse_bin_from_description (const gchar * bin_description,
|
2008-05-25 16:34:32 +00:00
|
|
|
gboolean ghost_unlinked_pads, GError ** err)
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
{
|
|
|
|
return gst_parse_bin_from_description_full (bin_description,
|
2011-04-25 09:10:47 +00:00
|
|
|
ghost_unlinked_pads, NULL, GST_PARSE_FLAG_NONE, err);
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_parse_bin_from_description_full:
|
|
|
|
* @bin_description: command line describing the bin
|
2008-05-25 16:34:32 +00:00
|
|
|
* @ghost_unlinked_pads: whether to automatically create ghost pads
|
|
|
|
* for unlinked source or sink pads within the bin
|
2010-12-07 18:35:04 +00:00
|
|
|
* @context: (transfer none) (allow-none): a parse context allocated with
|
|
|
|
* gst_parse_context_new(), or %NULL
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
* @flags: parsing options, or #GST_PARSE_FLAG_NONE
|
|
|
|
* @err: where to store the error message in case of an error, or NULL
|
|
|
|
*
|
|
|
|
* This is a convenience wrapper around gst_parse_launch() to create a
|
|
|
|
* #GstBin from a gst-launch-style pipeline description. See
|
|
|
|
* gst_parse_launch() and the gst-launch man page for details about the
|
2008-05-25 16:34:32 +00:00
|
|
|
* syntax. Ghost pads on the bin for unlinked source or sink pads
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
* within the bin can automatically be created (but only a maximum of
|
|
|
|
* one ghost pad for each direction will be created; if you expect
|
2008-05-25 16:34:32 +00:00
|
|
|
* multiple unlinked source pads or multiple unlinked sink pads
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
* and want them all ghosted, you will have to create the ghost pads
|
|
|
|
* yourself).
|
|
|
|
*
|
2010-12-17 18:14:41 +00:00
|
|
|
* Returns: (transfer full): a newly-created bin, or NULL if an error occurred.
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
*
|
|
|
|
* Since: 0.10.20
|
|
|
|
*/
|
|
|
|
GstElement *
|
|
|
|
gst_parse_bin_from_description_full (const gchar * bin_description,
|
2008-05-25 16:34:32 +00:00
|
|
|
gboolean ghost_unlinked_pads, GstParseContext * context,
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
GstParseFlags flags, GError ** err)
|
2006-02-02 09:51:18 +00:00
|
|
|
{
|
2007-05-09 16:32:07 +00:00
|
|
|
#ifndef GST_DISABLE_PARSE
|
2006-02-02 09:51:18 +00:00
|
|
|
GstPad *pad = NULL;
|
|
|
|
GstBin *bin;
|
|
|
|
gchar *desc;
|
|
|
|
|
|
|
|
g_return_val_if_fail (bin_description != NULL, NULL);
|
|
|
|
g_return_val_if_fail (err == NULL || *err == NULL, NULL);
|
|
|
|
|
|
|
|
GST_DEBUG ("Making bin from description '%s'", bin_description);
|
|
|
|
|
|
|
|
/* parse the pipeline to a bin */
|
|
|
|
desc = g_strdup_printf ("bin.( %s )", bin_description);
|
API: gst_parse_launch_full()
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gst.c: (init_post):
* gst/gst_private.h: (_GstParseContext):
* gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new),
(gst_parse_context_free), (gst_parse_context_get_missing_elements),
(gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch),
(gst_parse_launch_full):
* gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS),
(GstParseFlags), (GstParseContext):
* gst/gstutils.c: (gst_parse_bin_from_description),
(gst_parse_bin_from_description_full):
* gst/gstutils.h:
* gst/parse/grammar.y:
* gst/parse/types.h:
* win32/common/libgstreamer.def:
Add new gst_parse_*_full API (#528178):
API: gst_parse_launch_full()
API: gst_parse_launchv_full()
API: gst_parse_bin_from_description_full()
API: gst_parse_context_new()
API: gst_parse_context_free()
API: gst_parse_context_get_missing_elements()
2008-05-24 15:33:53 +00:00
|
|
|
bin = (GstBin *) gst_parse_launch_full (desc, context, flags, err);
|
2006-02-02 09:51:18 +00:00
|
|
|
g_free (desc);
|
|
|
|
|
|
|
|
if (bin == NULL || (err && *err != NULL)) {
|
|
|
|
if (bin)
|
|
|
|
gst_object_unref (bin);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find pads and ghost them if necessary */
|
2008-05-25 16:34:32 +00:00
|
|
|
if (ghost_unlinked_pads) {
|
2008-05-27 10:50:49 +00:00
|
|
|
if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC))) {
|
2006-02-02 09:51:18 +00:00
|
|
|
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
|
|
|
|
gst_object_unref (pad);
|
|
|
|
}
|
2008-05-27 10:50:49 +00:00
|
|
|
if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK))) {
|
2006-02-02 09:51:18 +00:00
|
|
|
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
|
|
|
|
gst_object_unref (pad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return GST_ELEMENT (bin);
|
2007-05-09 16:32:07 +00:00
|
|
|
#else
|
|
|
|
gchar *msg;
|
|
|
|
|
2008-05-22 15:38:54 +00:00
|
|
|
GST_WARNING ("Disabled API called");
|
2007-05-09 16:32:07 +00:00
|
|
|
|
|
|
|
msg = gst_error_get_message (GST_CORE_ERROR, GST_CORE_ERROR_DISABLED);
|
|
|
|
g_set_error (err, GST_CORE_ERROR, GST_CORE_ERROR_DISABLED, "%s", msg);
|
|
|
|
g_free (msg);
|
|
|
|
|
|
|
|
return NULL;
|
2006-02-20 23:34:40 +00:00
|
|
|
#endif
|
2007-05-09 16:32:07 +00:00
|
|
|
}
|
2007-06-21 14:29:05 +00:00
|
|
|
|
2007-12-11 20:23:58 +00:00
|
|
|
/**
|
|
|
|
* gst_util_get_timestamp:
|
|
|
|
*
|
2011-09-07 11:14:38 +00:00
|
|
|
* Get a timestamp as GstClockTime to be used for interval measurements.
|
2007-12-11 20:23:58 +00:00
|
|
|
* The timestamp should not be interpreted in any other way.
|
|
|
|
*
|
|
|
|
* Returns: the timestamp
|
|
|
|
*
|
|
|
|
* Since: 0.10.16
|
|
|
|
*/
|
2007-12-11 20:32:29 +00:00
|
|
|
GstClockTime
|
2007-12-11 20:23:58 +00:00
|
|
|
gst_util_get_timestamp (void)
|
|
|
|
{
|
2008-01-30 12:44:13 +00:00
|
|
|
#if defined (HAVE_POSIX_TIMERS) && defined(HAVE_MONOTONIC_CLOCK)
|
2007-12-11 20:23:58 +00:00
|
|
|
struct timespec now;
|
|
|
|
|
|
|
|
clock_gettime (CLOCK_MONOTONIC, &now);
|
|
|
|
return GST_TIMESPEC_TO_TIME (now);
|
|
|
|
#else
|
|
|
|
GTimeVal now;
|
|
|
|
|
|
|
|
g_get_current_time (&now);
|
|
|
|
return GST_TIMEVAL_TO_TIME (now);
|
|
|
|
#endif
|
|
|
|
}
|
2009-03-02 15:17:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_array_binary_search:
|
|
|
|
* @array: the sorted input array
|
|
|
|
* @num_elements: number of elements in the array
|
|
|
|
* @element_size: size of every element in bytes
|
2011-04-14 13:51:24 +00:00
|
|
|
* @search_func: (scope call): function to compare two elements, @search_data will always be passed as second argument
|
2009-03-02 15:17:45 +00:00
|
|
|
* @mode: search mode that should be used
|
|
|
|
* @search_data: element that should be found
|
2010-12-07 18:35:04 +00:00
|
|
|
* @user_data: (closure): data to pass to @search_func
|
2009-03-02 15:17:45 +00:00
|
|
|
*
|
|
|
|
* Searches inside @array for @search_data by using the comparison function
|
|
|
|
* @search_func. @array must be sorted ascending.
|
|
|
|
*
|
|
|
|
* As @search_data is always passed as second argument to @search_func it's
|
|
|
|
* not required that @search_data has the same type as the array elements.
|
|
|
|
*
|
|
|
|
* The complexity of this search function is O(log (num_elements)).
|
|
|
|
*
|
2011-04-14 13:51:24 +00:00
|
|
|
* Returns: (transfer none): The address of the found element or %NULL if nothing was found
|
2009-03-02 15:17:45 +00:00
|
|
|
*
|
|
|
|
* Since: 0.10.23
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_util_array_binary_search (gpointer array, guint num_elements,
|
|
|
|
gsize element_size, GCompareDataFunc search_func, GstSearchMode mode,
|
|
|
|
gconstpointer search_data, gpointer user_data)
|
|
|
|
{
|
|
|
|
glong left = 0, right = num_elements - 1, m;
|
|
|
|
gint ret;
|
|
|
|
guint8 *data = (guint8 *) array;
|
|
|
|
|
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
|
|
|
g_return_val_if_fail (element_size > 0, NULL);
|
|
|
|
g_return_val_if_fail (search_func != NULL, NULL);
|
|
|
|
|
|
|
|
/* 0. No elements => return NULL */
|
|
|
|
if (num_elements == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* 1. If search_data is before the 0th element return the 0th element */
|
|
|
|
ret = search_func (data, search_data, user_data);
|
|
|
|
if ((ret >= 0 && mode == GST_SEARCH_MODE_AFTER) || ret == 0)
|
|
|
|
return data;
|
|
|
|
else if (ret > 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* 2. If search_data is after the last element return the last element */
|
|
|
|
ret =
|
|
|
|
search_func (data + (num_elements - 1) * element_size, search_data,
|
|
|
|
user_data);
|
|
|
|
if ((ret <= 0 && mode == GST_SEARCH_MODE_BEFORE) || ret == 0)
|
|
|
|
return data + (num_elements - 1) * element_size;
|
|
|
|
else if (ret < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* 3. else binary search */
|
|
|
|
while (TRUE) {
|
|
|
|
m = left + (right - left) / 2;
|
|
|
|
|
|
|
|
ret = search_func (data + m * element_size, search_data, user_data);
|
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
return data + m * element_size;
|
|
|
|
} else if (ret < 0) {
|
|
|
|
left = m + 1;
|
|
|
|
} else {
|
|
|
|
right = m - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No exact match found */
|
|
|
|
if (right < left) {
|
|
|
|
if (mode == GST_SEARCH_MODE_EXACT) {
|
|
|
|
return NULL;
|
|
|
|
} else if (mode == GST_SEARCH_MODE_AFTER) {
|
|
|
|
if (ret < 0)
|
|
|
|
return (m < num_elements) ? data + (m + 1) * element_size : NULL;
|
|
|
|
else
|
|
|
|
return data + m * element_size;
|
|
|
|
} else {
|
|
|
|
if (ret < 0)
|
|
|
|
return data + m * element_size;
|
|
|
|
else
|
|
|
|
return (m > 0) ? data + (m - 1) * element_size : NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-11-16 08:29:10 +00:00
|
|
|
|
|
|
|
/* Finds the greatest common divisor.
|
|
|
|
* Returns 1 if none other found.
|
|
|
|
* This is Euclid's algorithm. */
|
|
|
|
|
2009-11-25 12:18:14 +00:00
|
|
|
/**
|
|
|
|
* gst_util_greatest_common_divisor:
|
2009-11-16 08:29:10 +00:00
|
|
|
* @a: First value as #gint
|
|
|
|
* @b: Second value as #gint
|
|
|
|
*
|
|
|
|
* Calculates the greatest common divisor of @a
|
|
|
|
* and @b.
|
|
|
|
*
|
|
|
|
* Returns: Greatest common divisor of @a and @b
|
|
|
|
*
|
|
|
|
* Since: 0.10.26
|
|
|
|
*/
|
|
|
|
gint
|
|
|
|
gst_util_greatest_common_divisor (gint a, gint b)
|
|
|
|
{
|
|
|
|
while (b != 0) {
|
|
|
|
int temp = a;
|
|
|
|
|
|
|
|
a = b;
|
|
|
|
b = temp % b;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ABS (a);
|
|
|
|
}
|
|
|
|
|
2009-11-25 12:18:14 +00:00
|
|
|
/**
|
|
|
|
* gst_util_fraction_to_double:
|
2009-11-16 08:29:10 +00:00
|
|
|
* @src_n: Fraction numerator as #gint
|
|
|
|
* @src_d: Fraction denominator #gint
|
2010-12-07 18:35:04 +00:00
|
|
|
* @dest: (out): pointer to a #gdouble for the result
|
2009-11-16 08:29:10 +00:00
|
|
|
*
|
2011-04-16 05:00:11 +00:00
|
|
|
* Transforms a fraction to a #gdouble.
|
2009-11-16 08:29:10 +00:00
|
|
|
*
|
|
|
|
* Since: 0.10.26
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_util_fraction_to_double (gint src_n, gint src_d, gdouble * dest)
|
|
|
|
{
|
|
|
|
g_return_if_fail (dest != NULL);
|
|
|
|
g_return_if_fail (src_d != 0);
|
|
|
|
|
|
|
|
*dest = ((gdouble) src_n) / ((gdouble) src_d);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_TERMS 30
|
|
|
|
#define MIN_DIVISOR 1.0e-10
|
|
|
|
#define MAX_ERROR 1.0e-20
|
|
|
|
|
|
|
|
/* use continued fractions to transform a double into a fraction,
|
|
|
|
* see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
|
|
|
|
* This algorithm takes care of overflows.
|
|
|
|
*/
|
|
|
|
|
2009-11-25 12:18:14 +00:00
|
|
|
/**
|
|
|
|
* gst_util_double_to_fraction:
|
2009-11-16 08:29:10 +00:00
|
|
|
* @src: #gdouble to transform
|
2010-12-07 18:35:04 +00:00
|
|
|
* @dest_n: (out): pointer to a #gint to hold the result numerator
|
|
|
|
* @dest_d: (out): pointer to a #gint to hold the result denominator
|
2009-11-16 08:29:10 +00:00
|
|
|
*
|
2009-11-25 14:44:05 +00:00
|
|
|
* Transforms a #gdouble to a fraction and simplifies
|
2009-11-16 08:29:10 +00:00
|
|
|
* the result.
|
|
|
|
*
|
|
|
|
* Since: 0.10.26
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_util_double_to_fraction (gdouble src, gint * dest_n, gint * dest_d)
|
|
|
|
{
|
|
|
|
|
|
|
|
gdouble V, F; /* double being converted */
|
|
|
|
gint N, D; /* will contain the result */
|
|
|
|
gint A; /* current term in continued fraction */
|
|
|
|
gint64 N1, D1; /* numerator, denominator of last approx */
|
|
|
|
gint64 N2, D2; /* numerator, denominator of previous approx */
|
|
|
|
gint i;
|
|
|
|
gint gcd;
|
|
|
|
gboolean negative = FALSE;
|
|
|
|
|
|
|
|
g_return_if_fail (dest_n != NULL);
|
|
|
|
g_return_if_fail (dest_d != NULL);
|
|
|
|
|
|
|
|
/* initialize fraction being converted */
|
|
|
|
F = src;
|
|
|
|
if (F < 0.0) {
|
|
|
|
F = -F;
|
|
|
|
negative = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
V = F;
|
|
|
|
/* initialize fractions with 1/0, 0/1 */
|
|
|
|
N1 = 1;
|
|
|
|
D1 = 0;
|
|
|
|
N2 = 0;
|
|
|
|
D2 = 1;
|
|
|
|
N = 1;
|
|
|
|
D = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_TERMS; i++) {
|
|
|
|
/* get next term */
|
|
|
|
A = (gint) F; /* no floor() needed, F is always >= 0 */
|
|
|
|
/* get new divisor */
|
|
|
|
F = F - A;
|
|
|
|
|
|
|
|
/* calculate new fraction in temp */
|
|
|
|
N2 = N1 * A + N2;
|
|
|
|
D2 = D1 * A + D2;
|
|
|
|
|
|
|
|
/* guard against overflow */
|
|
|
|
if (N2 > G_MAXINT || D2 > G_MAXINT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
N = N2;
|
|
|
|
D = D2;
|
|
|
|
|
|
|
|
/* save last two fractions */
|
|
|
|
N2 = N1;
|
|
|
|
D2 = D1;
|
|
|
|
N1 = N;
|
|
|
|
D1 = D;
|
|
|
|
|
|
|
|
/* quit if dividing by zero or close enough to target */
|
|
|
|
if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Take reciprocal */
|
|
|
|
F = 1 / F;
|
|
|
|
}
|
|
|
|
/* fix for overflow */
|
|
|
|
if (D == 0) {
|
|
|
|
N = G_MAXINT;
|
|
|
|
D = 1;
|
|
|
|
}
|
|
|
|
/* fix for negative */
|
|
|
|
if (negative)
|
|
|
|
N = -N;
|
|
|
|
|
|
|
|
/* simplify */
|
|
|
|
gcd = gst_util_greatest_common_divisor (N, D);
|
2010-05-13 06:00:08 +00:00
|
|
|
if (gcd) {
|
|
|
|
N /= gcd;
|
|
|
|
D /= gcd;
|
|
|
|
}
|
2009-11-16 08:29:10 +00:00
|
|
|
|
|
|
|
/* set results */
|
|
|
|
*dest_n = N;
|
|
|
|
*dest_d = D;
|
|
|
|
}
|
2009-11-16 08:49:46 +00:00
|
|
|
|
2009-11-25 12:18:14 +00:00
|
|
|
/**
|
|
|
|
* gst_util_fraction_multiply:
|
2009-11-16 08:49:46 +00:00
|
|
|
* @a_n: Numerator of first value
|
|
|
|
* @a_d: Denominator of first value
|
|
|
|
* @b_n: Numerator of second value
|
|
|
|
* @b_d: Denominator of second value
|
2010-12-07 18:35:04 +00:00
|
|
|
* @res_n: (out): Pointer to #gint to hold the result numerator
|
|
|
|
* @res_d: (out): Pointer to #gint to hold the result denominator
|
2009-11-16 08:49:46 +00:00
|
|
|
*
|
|
|
|
* Multiplies the fractions @a_n/@a_d and @b_n/@b_d and stores
|
|
|
|
* the result in @res_n and @res_d.
|
|
|
|
*
|
|
|
|
* Returns: %FALSE on overflow, %TRUE otherwise.
|
|
|
|
*
|
|
|
|
* Since: 0.10.26
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_util_fraction_multiply (gint a_n, gint a_d, gint b_n, gint b_d,
|
|
|
|
gint * res_n, gint * res_d)
|
|
|
|
{
|
|
|
|
gint gcd;
|
|
|
|
|
|
|
|
g_return_val_if_fail (res_n != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (res_d != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (a_d != 0, FALSE);
|
|
|
|
g_return_val_if_fail (b_d != 0, FALSE);
|
|
|
|
|
2010-05-13 06:21:37 +00:00
|
|
|
gcd = gst_util_greatest_common_divisor (a_n, a_d);
|
|
|
|
a_n /= gcd;
|
|
|
|
a_d /= gcd;
|
|
|
|
|
|
|
|
gcd = gst_util_greatest_common_divisor (b_n, b_d);
|
|
|
|
b_n /= gcd;
|
|
|
|
b_d /= gcd;
|
|
|
|
|
2009-11-16 08:49:46 +00:00
|
|
|
gcd = gst_util_greatest_common_divisor (a_n, b_d);
|
2010-05-13 06:21:37 +00:00
|
|
|
a_n /= gcd;
|
|
|
|
b_d /= gcd;
|
2010-05-13 06:00:08 +00:00
|
|
|
|
2009-11-16 08:49:46 +00:00
|
|
|
gcd = gst_util_greatest_common_divisor (a_d, b_n);
|
2010-05-13 06:21:37 +00:00
|
|
|
a_d /= gcd;
|
|
|
|
b_n /= gcd;
|
2009-11-16 08:49:46 +00:00
|
|
|
|
2010-05-13 06:00:08 +00:00
|
|
|
/* This would result in overflow */
|
|
|
|
if (a_n != 0 && G_MAXINT / ABS (a_n) < ABS (b_n))
|
|
|
|
return FALSE;
|
|
|
|
if (G_MAXINT / ABS (a_d) < ABS (b_d))
|
|
|
|
return FALSE;
|
2009-11-16 08:49:46 +00:00
|
|
|
|
|
|
|
*res_n = a_n * b_n;
|
|
|
|
*res_d = a_d * b_d;
|
2010-05-13 06:00:08 +00:00
|
|
|
|
2010-05-13 05:51:14 +00:00
|
|
|
gcd = gst_util_greatest_common_divisor (*res_n, *res_d);
|
2010-05-13 06:21:37 +00:00
|
|
|
*res_n /= gcd;
|
|
|
|
*res_d /= gcd;
|
2009-11-16 08:49:46 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-11-25 12:18:14 +00:00
|
|
|
/**
|
|
|
|
* gst_util_fraction_add:
|
2009-11-16 08:49:46 +00:00
|
|
|
* @a_n: Numerator of first value
|
|
|
|
* @a_d: Denominator of first value
|
|
|
|
* @b_n: Numerator of second value
|
|
|
|
* @b_d: Denominator of second value
|
2010-12-07 18:35:04 +00:00
|
|
|
* @res_n: (out): Pointer to #gint to hold the result numerator
|
|
|
|
* @res_d: (out): Pointer to #gint to hold the result denominator
|
2009-11-16 08:49:46 +00:00
|
|
|
*
|
|
|
|
* Adds the fractions @a_n/@a_d and @b_n/@b_d and stores
|
|
|
|
* the result in @res_n and @res_d.
|
|
|
|
*
|
|
|
|
* Returns: %FALSE on overflow, %TRUE otherwise.
|
|
|
|
*
|
|
|
|
* Since: 0.10.26
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_util_fraction_add (gint a_n, gint a_d, gint b_n, gint b_d, gint * res_n,
|
|
|
|
gint * res_d)
|
|
|
|
{
|
|
|
|
gint gcd;
|
|
|
|
|
|
|
|
g_return_val_if_fail (res_n != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (res_d != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (a_d != 0, FALSE);
|
|
|
|
g_return_val_if_fail (b_d != 0, FALSE);
|
|
|
|
|
2010-05-13 06:21:37 +00:00
|
|
|
gcd = gst_util_greatest_common_divisor (a_n, a_d);
|
|
|
|
a_n /= gcd;
|
|
|
|
a_d /= gcd;
|
|
|
|
|
|
|
|
gcd = gst_util_greatest_common_divisor (b_n, b_d);
|
|
|
|
b_n /= gcd;
|
|
|
|
b_d /= gcd;
|
|
|
|
|
2009-11-16 08:49:46 +00:00
|
|
|
if (a_n == 0) {
|
|
|
|
*res_n = b_n;
|
|
|
|
*res_d = b_d;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (b_n == 0) {
|
|
|
|
*res_n = a_n;
|
|
|
|
*res_d = a_d;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2010-05-13 06:00:08 +00:00
|
|
|
/* This would result in overflow */
|
|
|
|
if (G_MAXINT / ABS (a_n) < ABS (b_n))
|
|
|
|
return FALSE;
|
|
|
|
if (G_MAXINT / ABS (a_d) < ABS (b_d))
|
|
|
|
return FALSE;
|
|
|
|
if (G_MAXINT / ABS (a_d) < ABS (b_d))
|
|
|
|
return FALSE;
|
2009-11-16 08:49:46 +00:00
|
|
|
|
|
|
|
*res_n = (a_n * b_d) + (a_d * b_n);
|
|
|
|
*res_d = a_d * b_d;
|
|
|
|
|
|
|
|
gcd = gst_util_greatest_common_divisor (*res_n, *res_d);
|
2010-05-13 06:00:08 +00:00
|
|
|
if (gcd) {
|
|
|
|
*res_n /= gcd;
|
|
|
|
*res_d /= gcd;
|
2010-05-13 06:21:37 +00:00
|
|
|
} else {
|
|
|
|
/* res_n == 0 */
|
|
|
|
*res_d = 1;
|
2010-05-13 06:00:08 +00:00
|
|
|
}
|
2009-11-16 08:49:46 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2010-08-28 07:30:18 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_util_fraction_compare:
|
|
|
|
* @a_n: Numerator of first value
|
|
|
|
* @a_d: Denominator of first value
|
|
|
|
* @b_n: Numerator of second value
|
|
|
|
* @b_d: Denominator of second value
|
|
|
|
*
|
|
|
|
* Compares the fractions @a_n/@a_d and @b_n/@b_d and returns
|
|
|
|
* -1 if a < b, 0 if a = b and 1 if a > b.
|
|
|
|
*
|
|
|
|
* Returns: -1 if a < b; 0 if a = b; 1 if a > b.
|
|
|
|
*
|
|
|
|
* Since: 0.10.31
|
|
|
|
*/
|
|
|
|
gint
|
|
|
|
gst_util_fraction_compare (gint a_n, gint a_d, gint b_n, gint b_d)
|
|
|
|
{
|
|
|
|
gint64 new_num_1;
|
|
|
|
gint64 new_num_2;
|
|
|
|
gint gcd;
|
|
|
|
|
2010-08-28 07:35:01 +00:00
|
|
|
g_return_val_if_fail (a_d != 0 && b_d != 0, 0);
|
2010-08-28 07:30:18 +00:00
|
|
|
|
|
|
|
/* Simplify */
|
|
|
|
gcd = gst_util_greatest_common_divisor (a_n, a_d);
|
|
|
|
a_n /= gcd;
|
|
|
|
a_d /= gcd;
|
|
|
|
|
|
|
|
gcd = gst_util_greatest_common_divisor (b_n, b_d);
|
|
|
|
b_n /= gcd;
|
|
|
|
b_d /= gcd;
|
|
|
|
|
|
|
|
/* fractions are reduced when set, so we can quickly see if they're equal */
|
|
|
|
if (a_n == b_n && a_d == b_d)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* extend to 64 bits */
|
|
|
|
new_num_1 = ((gint64) a_n) * b_d;
|
|
|
|
new_num_2 = ((gint64) b_n) * a_d;
|
|
|
|
if (new_num_1 < new_num_2)
|
|
|
|
return -1;
|
|
|
|
if (new_num_1 > new_num_2)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Should not happen because a_d and b_d are not 0 */
|
|
|
|
g_return_val_if_reached (0);
|
|
|
|
}
|