+2005-08-05 Stefan Kost <ensonic@users.sf.net>
+
+ * check/gst-libs/controller.c: (gst_test_mono_source_get_property),
+ (gst_test_mono_source_set_property),
+ (gst_test_mono_source_class_init), (GST_START_TEST),
+ (gst_controller_suite):
+ * docs/gst/gstreamer-docs.sgml:
+ * docs/gst/gstreamer-sections.txt:
+ * docs/gst/gstreamer.types:
+ * docs/libs/gstreamer-libs-docs.sgml:
+ * docs/libs/gstreamer-libs-sections.txt:
+ * gst/base/gstadapter.c:
+ * libs/gst/controller/gst-controller.c:
+ (gst_controlled_property_new), (gst_controlled_property_free),
+ (gst_controller_new_valist),
+ (gst_controller_remove_properties_valist),
+ (gst_controller_sink_values), (_gst_controller_finalize):
+ * libs/gst/controller/gst-controller.h:
+ * libs/gst/controller/gst-helper.c:
+ (gst_object_control_properties), (gst_object_uncontrol_properties),
+ (gst_object_get_controller), (gst_object_set_controller),
+ (gst_object_sink_values), (gst_object_get_value_arrays),
+ (gst_object_get_value_array):
+ more tests (and fixes) for the controller
+ more docs for the controller
+ integrated companies docs for the adapter
+
2005-08-05 Thomas Vander Stichele <thomas at apestaart dot org>
* check/elements/gstfakesrc.c: (setup_fakesrc), (cleanup_fakesrc),
{
ARG_ULONG = 1,
ARG_DOUBLE,
- ARG_SWITCH,
+ ARG_BOOLEAN,
ARG_COUNT
};
struct _GstTestMonoSource
{
GstElement parent;
+ gulong val_ulong;
+ gdouble val_double;
+ gboolean val_bool;
};
struct _GstTestMonoSourceClass
{
gst_test_mono_source_get_property (GObject * object,
guint property_id, GValue * value, GParamSpec * pspec)
{
- //GstTestMonoSource *self = GST_TEST_MONO_SOURCE(object);
+ GstTestMonoSource *self = GST_TEST_MONO_SOURCE (object);
switch (property_id) {
case ARG_ULONG:
+ g_value_set_ulong (value, self->val_ulong);
break;
- default:{
+ case ARG_DOUBLE:
+ g_value_set_double (value, self->val_double);
+ break;
+ default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
break;
}
}
gst_test_mono_source_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec)
{
- //GstTestMonoSource *self = GST_TEST_MONO_SOURCE(object);
+ GstTestMonoSource *self = GST_TEST_MONO_SOURCE (object);
switch (property_id) {
case ARG_ULONG:
+ self->val_ulong = g_value_get_ulong (value);
+ break;
+ case ARG_DOUBLE:
+ self->val_double = g_value_get_double (value);
break;
- default:{
+ default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
break;
}
}
"ulong prop",
"ulong number parameter for the test_mono_source",
0, G_MAXULONG, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+
+ g_object_class_install_property (gobject_class, ARG_DOUBLE,
+ g_param_spec_double ("double",
+ "double prop",
+ "double number parameter for the test_mono_source",
+ 0.0, 100.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
}
static void
ctrl = gst_controller_new (G_OBJECT (elem), "_schrompf_", NULL);
fail_unless (ctrl == NULL, NULL);
- /* that property exists, but is not controllable */
- ASSERT_CRITICAL (ctrl = gst_controller_new (G_OBJECT (elem), "name", NULL));
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* tests for an element with controlled params */
+GST_START_TEST (controller_new_okay1)
+{
+ GstController *ctrl;
+ GstElement *elem;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+ fail_unless (ctrl != NULL, NULL);
+
+ g_object_unref (ctrl);
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* controlling several params should return the same controller */
+GST_START_TEST (controller_new_okay2)
+{
+ GstController *ctrl1, *ctrl2;
+ GstElement *elem;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl1 = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+ fail_unless (ctrl1 != NULL, NULL);
+
+ /* that property should exist and should be controllable */
+ ctrl2 = gst_controller_new (G_OBJECT (elem), "double", NULL);
+ fail_unless (ctrl2 != NULL, NULL);
+ fail_unless (ctrl1 == ctrl2, NULL);
+
+ g_object_unref (ctrl2);
+ g_object_unref (ctrl1);
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* controlling a params twice should be handled */
+GST_START_TEST (controller_param_twice)
+{
+ GstController *ctrl;
+ GstElement *elem;
+ gboolean res;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl = gst_controller_new (G_OBJECT (elem), "ulong", "ulong", NULL);
+ fail_unless (ctrl != NULL, NULL);
+
+ /* it should have been added at least once, let remove it */
+ res = gst_controller_remove_properties (ctrl, "ulong", NULL);
+ fail_unless (res, NULL);
+
+ /* removing it agian should not work */
+ res = gst_controller_remove_properties (ctrl, "ulong", NULL);
+ fail_unless (!res, NULL);
+
+ g_object_unref (ctrl);
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* tests if we cleanup properly */
+GST_START_TEST (controller_finalize)
+{
+ GstController *ctrl;
+ GstElement *elem;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+ fail_unless (ctrl != NULL, NULL);
+
+ /* free the controller */
+ g_object_unref (ctrl);
+
+ /* object shouldn't have a controller anymore */
+ ctrl = gst_object_get_controller (G_OBJECT (elem));
fail_unless (ctrl == NULL, NULL);
g_object_unref (elem);
GST_END_TEST;
-/* tests for an element with controlled params */
-GST_START_TEST (controller_new_okay)
+/* test timed value handling without interpolation */
+GST_START_TEST (controller_interpolate_none)
{
GstController *ctrl;
GstElement *elem;
+ gboolean res;
+ GValue val_ulong = { 0, };
elem = gst_element_factory_make ("testmonosource", "test_source");
ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
fail_unless (ctrl != NULL, NULL);
+ /* set interpolation mode */
+ gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_NONE);
+
+ /* set control values */
+ g_value_init (&val_ulong, G_TYPE_ULONG);
+ g_value_set_ulong (&val_ulong, 0);
+ res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+ fail_unless (res, NULL);
+ g_value_set_ulong (&val_ulong, 100);
+ res = gst_controller_set (ctrl, "ulong", 2 * GST_SECOND, &val_ulong);
+ fail_unless (res, NULL);
+
+ /* now pull in values for some timestamps */
+ gst_controller_sink_values (ctrl, 0 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+ gst_controller_sink_values (ctrl, 1 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+ gst_controller_sink_values (ctrl, 2 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
+
g_object_unref (ctrl);
g_object_unref (elem);
}
suite_add_tcase (s, tc);
tcase_add_test (tc, controller_init);
tcase_add_test (tc, controller_new_fail);
- tcase_add_test (tc, controller_new_okay);
+ tcase_add_test (tc, controller_new_okay1);
+ tcase_add_test (tc, controller_new_okay2);
+ tcase_add_test (tc, controller_param_twice);
+ tcase_add_test (tc, controller_finalize);
+ tcase_add_test (tc, controller_interpolate_none);
return s;
}
<!ENTITY GstVersion SYSTEM "xml/gstversion.xml">
<!ENTITY GstXML SYSTEM "xml/gstxml.xml">
+<!ENTITY GstAdapter SYSTEM "xml/gstadapter.xml">
<!ENTITY GstBaseSrc SYSTEM "xml/gstbasesrc.xml">
<!ENTITY GstBaseSink SYSTEM "xml/gstbasesink.xml">
<!ENTITY GstBaseTransform SYSTEM "xml/gstbasetransform.xml">
These base classes are provided to be extended by elements.
</para>
+ &GstAdapter;
&GstBaseSrc;
&GstBaseSink;
&GstBaseTransform;
- &GstPushSrc;
+ &GstPushSrc;
</chapter>
# base classes
<SECTION>
+<FILE>gstadapter</FILE>
+<TITLE>GstAdapter</TITLE>
+GstAdapter
+GstAdapterClass
+gst_adapter_new
+gst_adapter_clear
+gst_adapter_push
+gst_adapter_peek
+gst_adapter_flush
+gst_adapter_available
+gst_adapter_available_fast
+<SUBSECTION Standard>
+GST_ADAPTER_SRC
+GST_IS_ADAPTER_SRC
+GST_TYPE_ADAPTER_SRC
+GST_ADAPTER_SRC_CLASS
+GST_IS_ADAPTER_SRC_CLASS
+GST_ADAPTER_SRC_GET_CLASS
+<SUBSECTION Private>
+gst_adapter_src_get_type
+</SECTION>
+
+
+<SECTION>
<FILE>gstbasesrc</FILE>
<TITLE>GstBaseSrc</TITLE>
GstBaseSrc
% base classes
+#include <gst/base/gstadapter.h>
#include <gst/base/gstbasesrc.h>
#include <gst/base/gstbasesink.h>
#include <gst/base/gstbasetransform.h>
#include <gst/base/gstpushsrc.h>
+gst_adapter_get_type
gst_base_src_get_type
gst_base_sink_get_type
gst_base_transform_get_type
pipeline</ulink> and Microsoft's DirectShow for some background.
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### FUNCTION gst_init ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstBaseSink ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstBaseSrc ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstBaseTransform ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstBin ##### -->
<para>
#GstPad, #GstMiniObject
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstBuffer ##### -->
<para>
The basic structure of a buffer.
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstCaps ##### -->
<para>
#GstSystemClock
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstClock ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### MACRO GST_DISABLE_LOADSAVE_REGISTRY ##### -->
<para>
<!-- basic object functions -->
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstElement ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstElementDetails ##### -->
<para>
This struct is used to define public information about the element. It
#GstElement, #GstPlugin, #GstPluginFeature, #GstPadTemplate.
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstElementFactory ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### ENUM GstCoreError ##### -->
<para>
#GstPad, #GstElement
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstEvent ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstFakeSink ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstFakeSrc ##### -->
<para>
@:
@:
@:
+@:
@:
<!-- ##### ARG GstFakeSrc:data ##### -->
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstFileSink ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstFileSrc ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### USER_FUNCTION GstFilterFunc ##### -->
<para>
#GstPad, #GstElement
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### ENUM GstFormat ##### -->
<para>
Standard predefined formats
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstGhostPad ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstImplementsInterface ##### -->
<para>
#GstIndexFactory
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstIndex ##### -->
<para>
#GstIndex
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstIndexFactory ##### -->
<para>
The GstIndexFactory object
and environment variables that affect the debugging output.
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### ENUM GstDebugLevel ##### -->
<para>
The level defines the importance of a debugging message. The more important a
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstIterator ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
#GstBuffer, #GstEvent, #GstData
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstMemChunk ##### -->
<para>
The memchunk structure
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstMiniObject ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstObject ##### -->
<para>
#GstPadTemplate, #GstElement, #GstEvent
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstPad ##### -->
<para>
#GstPad, #GstElementFactory
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstPadTemplate ##### -->
<para>
The padtemplate object.
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### FUNCTION gst_parse_error_quark ##### -->
<para>
#GstBin
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstPipeline ##### -->
<para>
#GstPluginFeature, #GstType, #GstAutoplug, #GstElementFactory
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### FUNCTION gst_plugin_error_quark ##### -->
<para>
Get the error quark
#GstPlugin
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstPluginFeature ##### -->
<para>
#GstPad, #GstElement
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### ENUM GstQueryType ##### -->
<para>
Standard predefined Query types
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstQueue ##### -->
<para>
#GstPlugin, #GstPluginFeature
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
GstRegistry
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### FUNCTION gst_registry_pool_list ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstStructure ##### -->
<para>
#GstClock
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstSystemClock ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### TYPEDEF GstTagList ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstTagSetter ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstTrace ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstTrashStack ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstTypeFind ##### -->
<para>
<link linkend="gstreamer-Writing-typefind-functions">Writing typefind functions</link>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstTypeFindFactory ##### -->
<para>
Object that stores information about a typefind function
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### ENUM GstElementState ##### -->
<para>
These contants describe the state a #GstElement is in and transition scheduled for the #GstElement (the pending state).
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstURIHandler ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### ENUM GstURIType ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### FUNCTION gst_util_set_value_from_string ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### MACRO GST_MAKE_FOURCC ##### -->
<para>
will transform four characters into a host-endiannness guint32 fourcc:
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### MACRO GST_VERSION_MAJOR ##### -->
<para>
The major version of GStreamer at compile time
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT GstXML ##### -->
<para>
%version-entities;
<!ENTITY GstBytestream SYSTEM "xml/gstbytestream.xml">
<!ENTITY GstController SYSTEM "xml/gstcontroller.xml">
+<!ENTITY GstControllerGObject SYSTEM "xml/gstcontrollergobject.xml">
<!ENTITY GstGetbits SYSTEM "xml/gstgetbits.xml">
<!-- has not yet been written
<!ENTITY GstPutbits SYSTEM "xml/gstputbits.xml">
<chapter id="gstreamer-control">
<title>gstcontrol</title>
&GstController;
- <!--&GstControllerGObject; -->
+ &GstControllerGObject;
</chapter>
</part>
<SUBSECTION Private>
gst_controller_get_type
</SECTION>
+
+<SECTION>
+<FILE>gstcontrollergobject</FILE>
+<TITLE>GstControllerGObject</TITLE>
+<INCLUDE>libs/controller/gstcontroller.h</INCLUDE>
+gst_object_control_properties
+gst_object_uncontrol_properties
+gst_object_get_controller
+gst_object_set_controller
+gst_object_sink_values
+gst_object_get_value_arrays
+gst_object_get_value_array
+<SUBSECTION Standard>
+<SUBSECTION Private>
+</SECTION>
#GstBuffer, #GstCaps, #GstEvent
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### ENUM GstDPHeaderFlag ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### STRUCT gst_getbits_t ##### -->
<para>
* Boston, MA 02111-1307, USA.
*/
+/**
+ * SECTION:gstadapter
+ * @short_description: object to splice and merge buffers to desired size
+ * @see_also: #GstBytestream, #GstFilePad
+ *
+ * This class is for elements that receive buffers in an undesired size.
+ * While for example raw video contains one image per buffer, the same is not
+ * true for a lot of other formats, especially those that come directly from
+ * a file. So if you have undefined buffer sizes and require a specific size,
+ * this object is for you.
+ *
+ * The theory of operation is like this: All buffers received are put
+ * into the adapter using gst_adapter_push() and the data is then read back
+ * in chunks of the desired size using gst_adapter_peek(). After the data is
+ * processed, it is freed using gst_adapter_flush(). An example function that
+ * needs to process data in 10 byte chunks could look like this:
+ * <programlisting>
+ * void
+ * process_buffer (GstAdapter *adapter, GstBuffer *buffer)
+ * {
+ * guint8 *data;
+ * // put buffer into adapter
+ * #gst_adapter_push (adapter, buffer);
+ * // while we can read out 10 bytes, process them
+ * while ((data = #gst_adapter_peek (adapter, 10))) {
+ * // process the 10 bytes here
+ * // after processing the data, flush it
+ * #gst_adapter_flush (adapter, 10);
+ * }
+ * }
+ * </programlisting>
+ * For another example, a simple element inside GStreamer that uses GstAdapter
+ * is the libvisual element.
+ *
+ * A last thing to note is that while GstAdapter is pretty optimized,
+ * merging buffers still might be an operation that requires a memcpy()
+ * operation, and this operation is not the fastest. Because of this, some
+ * functions like gst_adapter_available_fast() are provided to help speed up
+ * such cases should you want to.
+ */
+
#include <string.h>
#include "gstadapter.h"
* Boston, MA 02111-1307, USA.
*/
+/**
+ * SECTION:gstadapter
+ * @short_description: object to splice and merge buffers to desired size
+ * @see_also: #GstBytestream, #GstFilePad
+ *
+ * This class is for elements that receive buffers in an undesired size.
+ * While for example raw video contains one image per buffer, the same is not
+ * true for a lot of other formats, especially those that come directly from
+ * a file. So if you have undefined buffer sizes and require a specific size,
+ * this object is for you.
+ *
+ * The theory of operation is like this: All buffers received are put
+ * into the adapter using gst_adapter_push() and the data is then read back
+ * in chunks of the desired size using gst_adapter_peek(). After the data is
+ * processed, it is freed using gst_adapter_flush(). An example function that
+ * needs to process data in 10 byte chunks could look like this:
+ * <programlisting>
+ * void
+ * process_buffer (GstAdapter *adapter, GstBuffer *buffer)
+ * {
+ * guint8 *data;
+ * // put buffer into adapter
+ * #gst_adapter_push (adapter, buffer);
+ * // while we can read out 10 bytes, process them
+ * while ((data = #gst_adapter_peek (adapter, 10))) {
+ * // process the 10 bytes here
+ * // after processing the data, flush it
+ * #gst_adapter_flush (adapter, 10);
+ * }
+ * }
+ * </programlisting>
+ * For another example, a simple element inside GStreamer that uses GstAdapter
+ * is the libvisual element.
+ *
+ * A last thing to note is that while GstAdapter is pretty optimized,
+ * merging buffers still might be an operation that requires a memcpy()
+ * operation, and this operation is not the fastest. Because of this, some
+ * functions like gst_adapter_available_fast() are provided to help speed up
+ * such cases should you want to.
+ */
+
#include <string.h>
#include "gstadapter.h"
gchar *signal_name;
prop->name = pspec->name; // so we don't use the same mem twice
- prop->object = object;
prop->type = G_PARAM_SPEC_VALUE_TYPE (pspec);
gst_controlled_property_set_interpolation_mode (prop,
GST_INTERPOLATE_NONE);
{
GList *node;
- g_signal_handler_disconnect (prop->object, prop->notify_handler_id);
for (node = prop->values; node; node = g_list_next (node)) {
g_free (node->data);
}
self = g_object_get_qdata (object, controller_key);
// create GstControlledProperty for each property
while ((name = va_arg (var_args, gchar *))) {
- // create GstControlledProperty and add to self->propeties List
- if ((prop = gst_controlled_property_new (object, name))) {
- // if we don't have a controller object yet, now is the time to create one
- if (!self) {
- self = g_object_new (GST_TYPE_CONTROLLER, NULL);
- self->lock = g_mutex_new ();
- // store the controller
- g_object_set_qdata (object, controller_key, self);
+ // test if this property isn't yet controlled
+ if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
+ // create GstControlledProperty and add to self->propeties List
+ if ((prop = gst_controlled_property_new (object, name))) {
+ // if we don't have a controller object yet, now is the time to create one
+ if (!self) {
+ self = g_object_new (GST_TYPE_CONTROLLER, NULL);
+ self->lock = g_mutex_new ();
+ self->object = object;
+ // store the controller
+ g_object_set_qdata (object, controller_key, self);
+ } else {
+ // increment ref-count
+ self = g_object_ref (self);
+ }
+ self->properties = g_list_prepend (self->properties, prop);
}
- self->properties = g_list_prepend (self->properties, prop);
+ } else {
+ GST_WARNING ("trying to control property again");
}
}
va_end (var_args);
g_mutex_lock (self->lock);
if ((prop = gst_controller_find_controlled_property (self, name))) {
self->properties = g_list_remove (self->properties, prop);
+ g_signal_handler_disconnect (self->object, prop->notify_handler_id);
gst_controlled_property_free (prop);
} else {
res = FALSE;
value = prop->get (prop, timestamp);
prop->last_value.timestamp = timestamp;
g_value_copy (value, &prop->last_value.value);
- g_object_set_property (prop->object, prop->name, value);
+ g_object_set_property (self->object, prop->name, value);
}
}
g_mutex_unlock (self->lock);
{
GstController *self = GST_CONTROLLER (object);
GList *node;
+ GstControlledProperty *prop;
- // free list of properties
+ /* free list of properties */
if (self->properties) {
for (node = self->properties; node; node = g_list_next (node)) {
- gst_controlled_property_free (node->data);
+ prop = node->data;
+ g_signal_handler_disconnect (self->object, prop->notify_handler_id);
+ gst_controlled_property_free (prop);
}
g_list_free (self->properties);
self->properties = NULL;
}
g_mutex_free (self->lock);
+ /* remove controller from objects qdata list */
+ g_object_set_qdata (self->object, controller_key, NULL);
if (G_OBJECT_CLASS (parent_class)->finalize)
(G_OBJECT_CLASS (parent_class)->finalize) (object);
typedef struct _GstControlledProperty
{
gchar *name; // name of the property
- GObject *object; // the object we control
GType type; // type of the handled property
GValue default_value; // default value for the handled property
GValue result_value; // result value location for the interpolation method
GList *properties; // List of GstControlledProperty
GMutex *lock; // Secure property access, elements will access from threads
+ GObject *object; // the object we control
};
struct _GstControllerClass
/* GObject convenience functions */
-GstController *g_object_control_properties (GObject * object, ...);
-gboolean g_object_uncontrol_properties (GObject * object, ...);
+GstController *gst_object_control_properties (GObject * object, ...);
+gboolean gst_object_uncontrol_properties (GObject * object, ...);
-GstController *g_object_get_controller (GObject * object);
-gboolean g_object_set_controller (GObject * object, GstController * controller);
+GstController *gst_object_get_controller (GObject * object);
+gboolean gst_object_set_controller (GObject * object, GstController * controller);
-gboolean g_object_sink_values (GObject * object, GstClockTime timestamp);
+gboolean gst_object_sink_values (GObject * object, GstClockTime timestamp);
-gboolean g_object_get_value_arrays (GObject * object,
+gboolean gst_object_get_value_arrays (GObject * object,
GstClockTime timestamp, GSList * value_arrays);
-gboolean g_object_get_value_array (GObject * object,
+gboolean gst_object_get_value_array (GObject * object,
GstClockTime timestamp, GstValueArray * value_array);
/* lib init/done */
extern GQuark controller_key;
/**
- * g_object_control_properties:
+ * gst_object_control_properties:
* @object: the object of which some properties should be controlled
* @var_args: %NULL terminated list of property names that should be controlled
*
* one or more of the given properties aren't available, or cannot be controlled, for the given element.
*/
GstController *
-g_object_control_properties (GObject * object, ...)
+gst_object_control_properties (GObject * object, ...)
{
GstController *ctrl;
}
/**
- * g_object_uncontrol_properties:
+ * gst_object_uncontrol_properties:
* @object: the object of which some properties should not be controlled anymore
* @var_args: %NULL terminated list of property names that should be controlled
*
* controller, %TRUE otherwise
*/
gboolean
-g_object_uncontrol_properties (GObject * object, ...)
+gst_object_uncontrol_properties (GObject * object, ...)
{
gboolean res = FALSE;
GstController *ctrl;
}
/**
- * g_object_get_controller:
+ * gst_object_get_controller:
* @object: the object that has controlled properties
*
* Returns: the controller handling some of the given element's properties,
* %NULL if no controller
*/
GstController *
-g_object_get_controller (GObject * object)
+gst_object_get_controller (GObject * object)
{
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
}
/**
- * g_object_set_controller:
+ * gst_object_set_controller:
* @object: the object that should get the controller
* @controller: the controller object to plug in
*
* Returns: %FALSE if the GObject already has an controller, %TRUE otherwise
*/
gboolean
-g_object_set_controller (GObject * object, GstController * controller)
+gst_object_set_controller (GObject * object, GstController * controller)
{
GstController *ctrl;
}
/**
- * g_object_sink_values:
+ * gst_object_sink_values:
* @object: the object that has controlled properties
* @timestamp: the time that should be processed
*
* Returns: same thing as gst_controller_sink_values()
*/
gboolean
-g_object_sink_values (GObject * object, GstClockTime timestamp)
+gst_object_sink_values (GObject * object, GstClockTime timestamp)
{
GstController *ctrl = NULL;
}
/**
- * g_object_get_value_arrays:
+ * gst_object_get_value_arrays:
* @object: the object that has controlled properties
* @timestamp: the time that should be processed
* @value_arrays: list to return the control-values in
* Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
*/
gboolean
-g_object_get_value_arrays (GObject * object, GstClockTime timestamp,
+gst_object_get_value_arrays (GObject * object, GstClockTime timestamp,
GSList * value_arrays)
{
GstController *ctrl;
}
/**
- * g_object_get_value_array:
+ * gst_object_get_value_array:
* @self: the object that has controlled properties
* @timestamp: the time that should be processed
* @value_array: array to put control-values in
* Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
*/
gboolean
-g_object_get_value_array (GObject * object, GstClockTime timestamp,
+gst_object_get_value_array (GObject * object, GstClockTime timestamp,
GstValueArray * value_array)
{
GstController *ctrl;
gchar *signal_name;
prop->name = pspec->name; // so we don't use the same mem twice
- prop->object = object;
prop->type = G_PARAM_SPEC_VALUE_TYPE (pspec);
gst_controlled_property_set_interpolation_mode (prop,
GST_INTERPOLATE_NONE);
{
GList *node;
- g_signal_handler_disconnect (prop->object, prop->notify_handler_id);
for (node = prop->values; node; node = g_list_next (node)) {
g_free (node->data);
}
self = g_object_get_qdata (object, controller_key);
// create GstControlledProperty for each property
while ((name = va_arg (var_args, gchar *))) {
- // create GstControlledProperty and add to self->propeties List
- if ((prop = gst_controlled_property_new (object, name))) {
- // if we don't have a controller object yet, now is the time to create one
- if (!self) {
- self = g_object_new (GST_TYPE_CONTROLLER, NULL);
- self->lock = g_mutex_new ();
- // store the controller
- g_object_set_qdata (object, controller_key, self);
+ // test if this property isn't yet controlled
+ if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
+ // create GstControlledProperty and add to self->propeties List
+ if ((prop = gst_controlled_property_new (object, name))) {
+ // if we don't have a controller object yet, now is the time to create one
+ if (!self) {
+ self = g_object_new (GST_TYPE_CONTROLLER, NULL);
+ self->lock = g_mutex_new ();
+ self->object = object;
+ // store the controller
+ g_object_set_qdata (object, controller_key, self);
+ } else {
+ // increment ref-count
+ self = g_object_ref (self);
+ }
+ self->properties = g_list_prepend (self->properties, prop);
}
- self->properties = g_list_prepend (self->properties, prop);
+ } else {
+ GST_WARNING ("trying to control property again");
}
}
va_end (var_args);
g_mutex_lock (self->lock);
if ((prop = gst_controller_find_controlled_property (self, name))) {
self->properties = g_list_remove (self->properties, prop);
+ g_signal_handler_disconnect (self->object, prop->notify_handler_id);
gst_controlled_property_free (prop);
} else {
res = FALSE;
value = prop->get (prop, timestamp);
prop->last_value.timestamp = timestamp;
g_value_copy (value, &prop->last_value.value);
- g_object_set_property (prop->object, prop->name, value);
+ g_object_set_property (self->object, prop->name, value);
}
}
g_mutex_unlock (self->lock);
{
GstController *self = GST_CONTROLLER (object);
GList *node;
+ GstControlledProperty *prop;
- // free list of properties
+ /* free list of properties */
if (self->properties) {
for (node = self->properties; node; node = g_list_next (node)) {
- gst_controlled_property_free (node->data);
+ prop = node->data;
+ g_signal_handler_disconnect (self->object, prop->notify_handler_id);
+ gst_controlled_property_free (prop);
}
g_list_free (self->properties);
self->properties = NULL;
}
g_mutex_free (self->lock);
+ /* remove controller from objects qdata list */
+ g_object_set_qdata (self->object, controller_key, NULL);
if (G_OBJECT_CLASS (parent_class)->finalize)
(G_OBJECT_CLASS (parent_class)->finalize) (object);
typedef struct _GstControlledProperty
{
gchar *name; // name of the property
- GObject *object; // the object we control
GType type; // type of the handled property
GValue default_value; // default value for the handled property
GValue result_value; // result value location for the interpolation method
GList *properties; // List of GstControlledProperty
GMutex *lock; // Secure property access, elements will access from threads
+ GObject *object; // the object we control
};
struct _GstControllerClass
/* GObject convenience functions */
-GstController *g_object_control_properties (GObject * object, ...);
-gboolean g_object_uncontrol_properties (GObject * object, ...);
+GstController *gst_object_control_properties (GObject * object, ...);
+gboolean gst_object_uncontrol_properties (GObject * object, ...);
-GstController *g_object_get_controller (GObject * object);
-gboolean g_object_set_controller (GObject * object, GstController * controller);
+GstController *gst_object_get_controller (GObject * object);
+gboolean gst_object_set_controller (GObject * object, GstController * controller);
-gboolean g_object_sink_values (GObject * object, GstClockTime timestamp);
+gboolean gst_object_sink_values (GObject * object, GstClockTime timestamp);
-gboolean g_object_get_value_arrays (GObject * object,
+gboolean gst_object_get_value_arrays (GObject * object,
GstClockTime timestamp, GSList * value_arrays);
-gboolean g_object_get_value_array (GObject * object,
+gboolean gst_object_get_value_array (GObject * object,
GstClockTime timestamp, GstValueArray * value_array);
/* lib init/done */
extern GQuark controller_key;
/**
- * g_object_control_properties:
+ * gst_object_control_properties:
* @object: the object of which some properties should be controlled
* @var_args: %NULL terminated list of property names that should be controlled
*
* one or more of the given properties aren't available, or cannot be controlled, for the given element.
*/
GstController *
-g_object_control_properties (GObject * object, ...)
+gst_object_control_properties (GObject * object, ...)
{
GstController *ctrl;
}
/**
- * g_object_uncontrol_properties:
+ * gst_object_uncontrol_properties:
* @object: the object of which some properties should not be controlled anymore
* @var_args: %NULL terminated list of property names that should be controlled
*
* controller, %TRUE otherwise
*/
gboolean
-g_object_uncontrol_properties (GObject * object, ...)
+gst_object_uncontrol_properties (GObject * object, ...)
{
gboolean res = FALSE;
GstController *ctrl;
}
/**
- * g_object_get_controller:
+ * gst_object_get_controller:
* @object: the object that has controlled properties
*
* Returns: the controller handling some of the given element's properties,
* %NULL if no controller
*/
GstController *
-g_object_get_controller (GObject * object)
+gst_object_get_controller (GObject * object)
{
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
}
/**
- * g_object_set_controller:
+ * gst_object_set_controller:
* @object: the object that should get the controller
* @controller: the controller object to plug in
*
* Returns: %FALSE if the GObject already has an controller, %TRUE otherwise
*/
gboolean
-g_object_set_controller (GObject * object, GstController * controller)
+gst_object_set_controller (GObject * object, GstController * controller)
{
GstController *ctrl;
}
/**
- * g_object_sink_values:
+ * gst_object_sink_values:
* @object: the object that has controlled properties
* @timestamp: the time that should be processed
*
* Returns: same thing as gst_controller_sink_values()
*/
gboolean
-g_object_sink_values (GObject * object, GstClockTime timestamp)
+gst_object_sink_values (GObject * object, GstClockTime timestamp)
{
GstController *ctrl = NULL;
}
/**
- * g_object_get_value_arrays:
+ * gst_object_get_value_arrays:
* @object: the object that has controlled properties
* @timestamp: the time that should be processed
* @value_arrays: list to return the control-values in
* Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
*/
gboolean
-g_object_get_value_arrays (GObject * object, GstClockTime timestamp,
+gst_object_get_value_arrays (GObject * object, GstClockTime timestamp,
GSList * value_arrays)
{
GstController *ctrl;
}
/**
- * g_object_get_value_array:
+ * gst_object_get_value_array:
* @self: the object that has controlled properties
* @timestamp: the time that should be processed
* @value_array: array to put control-values in
* Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
*/
gboolean
-g_object_get_value_array (GObject * object, GstClockTime timestamp,
+gst_object_get_value_array (GObject * object, GstClockTime timestamp,
GstValueArray * value_array)
{
GstController *ctrl;
{
ARG_ULONG = 1,
ARG_DOUBLE,
- ARG_SWITCH,
+ ARG_BOOLEAN,
ARG_COUNT
};
struct _GstTestMonoSource
{
GstElement parent;
+ gulong val_ulong;
+ gdouble val_double;
+ gboolean val_bool;
};
struct _GstTestMonoSourceClass
{
gst_test_mono_source_get_property (GObject * object,
guint property_id, GValue * value, GParamSpec * pspec)
{
- //GstTestMonoSource *self = GST_TEST_MONO_SOURCE(object);
+ GstTestMonoSource *self = GST_TEST_MONO_SOURCE (object);
switch (property_id) {
case ARG_ULONG:
+ g_value_set_ulong (value, self->val_ulong);
break;
- default:{
+ case ARG_DOUBLE:
+ g_value_set_double (value, self->val_double);
+ break;
+ default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
break;
}
}
gst_test_mono_source_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec)
{
- //GstTestMonoSource *self = GST_TEST_MONO_SOURCE(object);
+ GstTestMonoSource *self = GST_TEST_MONO_SOURCE (object);
switch (property_id) {
case ARG_ULONG:
+ self->val_ulong = g_value_get_ulong (value);
+ break;
+ case ARG_DOUBLE:
+ self->val_double = g_value_get_double (value);
break;
- default:{
+ default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
break;
}
}
"ulong prop",
"ulong number parameter for the test_mono_source",
0, G_MAXULONG, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+
+ g_object_class_install_property (gobject_class, ARG_DOUBLE,
+ g_param_spec_double ("double",
+ "double prop",
+ "double number parameter for the test_mono_source",
+ 0.0, 100.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
}
static void
ctrl = gst_controller_new (G_OBJECT (elem), "_schrompf_", NULL);
fail_unless (ctrl == NULL, NULL);
- /* that property exists, but is not controllable */
- ASSERT_CRITICAL (ctrl = gst_controller_new (G_OBJECT (elem), "name", NULL));
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* tests for an element with controlled params */
+GST_START_TEST (controller_new_okay1)
+{
+ GstController *ctrl;
+ GstElement *elem;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+ fail_unless (ctrl != NULL, NULL);
+
+ g_object_unref (ctrl);
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* controlling several params should return the same controller */
+GST_START_TEST (controller_new_okay2)
+{
+ GstController *ctrl1, *ctrl2;
+ GstElement *elem;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl1 = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+ fail_unless (ctrl1 != NULL, NULL);
+
+ /* that property should exist and should be controllable */
+ ctrl2 = gst_controller_new (G_OBJECT (elem), "double", NULL);
+ fail_unless (ctrl2 != NULL, NULL);
+ fail_unless (ctrl1 == ctrl2, NULL);
+
+ g_object_unref (ctrl2);
+ g_object_unref (ctrl1);
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* controlling a params twice should be handled */
+GST_START_TEST (controller_param_twice)
+{
+ GstController *ctrl;
+ GstElement *elem;
+ gboolean res;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl = gst_controller_new (G_OBJECT (elem), "ulong", "ulong", NULL);
+ fail_unless (ctrl != NULL, NULL);
+
+ /* it should have been added at least once, let remove it */
+ res = gst_controller_remove_properties (ctrl, "ulong", NULL);
+ fail_unless (res, NULL);
+
+ /* removing it agian should not work */
+ res = gst_controller_remove_properties (ctrl, "ulong", NULL);
+ fail_unless (!res, NULL);
+
+ g_object_unref (ctrl);
+ g_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* tests if we cleanup properly */
+GST_START_TEST (controller_finalize)
+{
+ GstController *ctrl;
+ GstElement *elem;
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+ fail_unless (ctrl != NULL, NULL);
+
+ /* free the controller */
+ g_object_unref (ctrl);
+
+ /* object shouldn't have a controller anymore */
+ ctrl = gst_object_get_controller (G_OBJECT (elem));
fail_unless (ctrl == NULL, NULL);
g_object_unref (elem);
GST_END_TEST;
-/* tests for an element with controlled params */
-GST_START_TEST (controller_new_okay)
+/* test timed value handling without interpolation */
+GST_START_TEST (controller_interpolate_none)
{
GstController *ctrl;
GstElement *elem;
+ gboolean res;
+ GValue val_ulong = { 0, };
elem = gst_element_factory_make ("testmonosource", "test_source");
ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
fail_unless (ctrl != NULL, NULL);
+ /* set interpolation mode */
+ gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_NONE);
+
+ /* set control values */
+ g_value_init (&val_ulong, G_TYPE_ULONG);
+ g_value_set_ulong (&val_ulong, 0);
+ res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+ fail_unless (res, NULL);
+ g_value_set_ulong (&val_ulong, 100);
+ res = gst_controller_set (ctrl, "ulong", 2 * GST_SECOND, &val_ulong);
+ fail_unless (res, NULL);
+
+ /* now pull in values for some timestamps */
+ gst_controller_sink_values (ctrl, 0 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+ gst_controller_sink_values (ctrl, 1 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+ gst_controller_sink_values (ctrl, 2 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
+
g_object_unref (ctrl);
g_object_unref (elem);
}
suite_add_tcase (s, tc);
tcase_add_test (tc, controller_init);
tcase_add_test (tc, controller_new_fail);
- tcase_add_test (tc, controller_new_okay);
+ tcase_add_test (tc, controller_new_okay1);
+ tcase_add_test (tc, controller_new_okay2);
+ tcase_add_test (tc, controller_param_twice);
+ tcase_add_test (tc, controller_finalize);
+ tcase_add_test (tc, controller_interpolate_none);
return s;
}