gstreamer/tests/examples/controller/control-sources.c
Matthew Waters 3d887c7f07 gst: don't use volatile to mean atomic
volatile is not sufficient to provide atomic guarantees and real atomics
should be used instead.  GCC 11 has started warning about using volatile
with atomic operations.

https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1719

Discovered in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/868

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/775>
2021-03-19 04:15:19 +00:00

450 lines
13 KiB
C

/*
* control-sources.c
*
* Generates a datafile for various control sources.
*
* Needs gnuplot for plotting.
* plot "ctrl_i1.dat" using 1:2 with points title 'none', "" using 1:3 with points title 'linear', "" using 1:4 with points title 'cubic', "ctrl_i2.dat" using 1:2 with lines title 'none', "" using 1:3 with lines title 'linear', "" using 1:4 with lines title 'cubic'
* plot "ctrl_l1.dat" using 1:2 with points title 'sine', "" using 1:3 with points title 'square', "" using 1:4 with points title 'saw', "" using 1:5 with points title 'revsaw', "" using 1:6 with points title 'triangle', "ctrl_l2.dat" using 1:2 with lines title 'sine', "" using 1:3 with lines title 'square', "" using 1:4 with lines title 'saw', "" using 1:5 with lines title 'revsaw', "" using 1:6 with lines title 'triangle'
* plot "ctrl_cl1.dat" using 1:2 with points title 'sine', "ctrl_cl2.dat" using 1:2 with lines title 'sine'
*/
#include <stdio.h>
#include <stdlib.h>
#include <gst/gst.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/controller/gstlfocontrolsource.h>
#include <gst/controller/gstdirectcontrolbinding.h>
/* local test element */
enum
{
PROP_INT = 1,
PROP_FLOAT,
PROP_DOUBLE,
PROP_BOOLEAN,
PROP_COUNT
};
#define GST_TYPE_TEST_OBJ (gst_test_obj_get_type ())
#define GST_TEST_OBJ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TEST_OBJ, GstTestObj))
#define GST_TEST_OBJ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TEST_OBJ, GstTestObjClass))
#define GST_IS_TEST_OBJ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TEST_OBJ))
#define GST_IS_TEST_OBJ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TEST_OBJ))
#define GST_TEST_OBJ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TEST_OBJ, GstTestObjClass))
typedef struct _GstTestObj GstTestObj;
typedef struct _GstTestObjClass GstTestObjClass;
struct _GstTestObj
{
GstElement parent;
gint val_int;
gfloat val_float;
gdouble val_double;
gboolean val_boolean;
};
struct _GstTestObjClass
{
GstElementClass parent_class;
};
static GType gst_test_obj_get_type (void);
static void
gst_test_obj_get_property (GObject * object,
guint property_id, GValue * value, GParamSpec * pspec)
{
GstTestObj *self = GST_TEST_OBJ (object);
switch (property_id) {
case PROP_INT:
g_value_set_int (value, self->val_int);
break;
case PROP_FLOAT:
g_value_set_float (value, self->val_float);
break;
case PROP_DOUBLE:
g_value_set_double (value, self->val_double);
break;
case PROP_BOOLEAN:
g_value_set_boolean (value, self->val_boolean);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gst_test_obj_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec)
{
GstTestObj *self = GST_TEST_OBJ (object);
switch (property_id) {
case PROP_INT:
self->val_int = g_value_get_int (value);
GST_DEBUG ("test value int=%d", self->val_int);
break;
case PROP_FLOAT:
self->val_float = g_value_get_float (value);
GST_DEBUG ("test value float=%f", self->val_float);
break;
case PROP_DOUBLE:
self->val_double = g_value_get_double (value);
GST_DEBUG ("test value double=%f", self->val_double);
break;
case PROP_BOOLEAN:
self->val_boolean = g_value_get_boolean (value);
GST_DEBUG ("test value boolean=%d", self->val_boolean);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gst_test_obj_class_init (GstTestObjClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gst_test_obj_set_property;
gobject_class->get_property = gst_test_obj_get_property;
g_object_class_install_property (gobject_class, PROP_INT,
g_param_spec_int ("int",
"int prop",
"int number parameter",
0, 100, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_FLOAT,
g_param_spec_float ("float",
"float prop",
"float number parameter",
0.0, 100.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_DOUBLE,
g_param_spec_double ("double",
"double prop",
"double number parameter",
0.0, 100.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_BOOLEAN,
g_param_spec_boolean ("boolean",
"boolean prop",
"boolean parameter",
FALSE, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
}
static void
gst_test_obj_base_init (GstTestObjClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_set_metadata (element_class,
"test object for unit tests",
"Test", "Use in unit tests", "Stefan Sauer <ensonic@users.sf.net>");
}
static GType
gst_test_obj_get_type (void)
{
static gsize TEST_OBJ_type = 0;
if (g_once_init_enter (&TEST_OBJ_type)) {
GType type;
static const GTypeInfo info = {
(guint16) sizeof (GstTestObjClass),
(GBaseInitFunc) gst_test_obj_base_init, // base_init
NULL, // base_finalize
(GClassInitFunc) gst_test_obj_class_init, // class_init
NULL, // class_finalize
NULL, // class_data
(guint16) sizeof (GstTestObj),
0, // n_preallocs
NULL, // instance_init
NULL // value_table
};
type = g_type_register_static (GST_TYPE_ELEMENT, "GstTestObj", &info, 0);
g_once_init_leave (&TEST_OBJ_type, type);
}
return TEST_OBJ_type;
}
static void
test_interpolation (void)
{
GstObject *e;
GstTimedValueControlSource *tvcs;
GstControlSource *cs;
gint t, i1, i2, i3;
GValue *v1, *v2, *v3;
gint n_values;
FILE *f;
e = (GstObject *) gst_element_factory_make ("testobj", NULL);
cs = gst_interpolation_control_source_new ();
tvcs = (GstTimedValueControlSource *) cs;
gst_object_add_control_binding (e, gst_direct_control_binding_new (e, "int",
cs));
gst_timed_value_control_source_set (tvcs, 0 * GST_SECOND, 0.0);
gst_timed_value_control_source_set (tvcs, 10 * GST_SECOND, 1.0);
gst_timed_value_control_source_set (tvcs, 20 * GST_SECOND, 0.5);
gst_timed_value_control_source_set (tvcs, 30 * GST_SECOND, 0.2);
/* test single values */
if (!(f = fopen ("ctrl_i1.dat", "w")))
exit (-1);
fprintf (f, "# Time None Linear Cubic\n");
for (t = 0; t < 40; t++) {
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_NONE, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i1 = GST_TEST_OBJ (e)->val_int;
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i2 = GST_TEST_OBJ (e)->val_int;
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_CUBIC, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i3 = GST_TEST_OBJ (e)->val_int;
fprintf (f, "%4.1f %d %d %d\n", (gfloat) t, i1, i2, i3);
}
fclose (f);
/* test value arrays */
if (!(f = fopen ("ctrl_i2.dat", "w")))
exit (-1);
fprintf (f, "# Time None Linear Cubic\n");
n_values = 40 * 10;
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_NONE, NULL);
v1 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v1);
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
v2 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v2);
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_CUBIC, NULL);
v3 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v3);
for (t = 0; t < n_values; t++) {
i1 = g_value_get_int (&v1[t]);
i2 = g_value_get_int (&v2[t]);
i3 = g_value_get_int (&v3[t]);
fprintf (f, "%4.1f %d %d %d\n", (gfloat) t / 10.0, i1, i2, i3);
g_value_unset (&v1[t]);
g_value_unset (&v2[t]);
g_value_unset (&v3[t]);
}
g_free (v1);
g_free (v2);
g_free (v3);
fclose (f);
gst_object_unref (cs);
gst_object_unref (e);
}
static void
test_lfo (void)
{
GstObject *e;
GstControlSource *cs;
gint t, i1, i2, i3, i4, i5;
GValue *v1, *v2, *v3, *v4, *v5;
gint n_values;
FILE *f;
e = (GstObject *) gst_element_factory_make ("testobj", NULL);
cs = gst_lfo_control_source_new ();
gst_object_add_control_binding (e, gst_direct_control_binding_new (e, "int",
cs));
g_object_set (cs,
"frequency", (gdouble) 0.05,
"timeshift", (GstClockTime) 0,
"amplitude", (gdouble) 0.5, "offset", (gdouble) 0.5, NULL);
/* test single values */
if (!(f = fopen ("ctrl_l1.dat", "w")))
exit (-1);
fprintf (f, "# Time Sine Square Saw RevSaw Triangle\n");
for (t = 0; t < 40; t++) {
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_SINE, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i1 = GST_TEST_OBJ (e)->val_int;
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_SQUARE, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i2 = GST_TEST_OBJ (e)->val_int;
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_SAW, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i3 = GST_TEST_OBJ (e)->val_int;
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_REVERSE_SAW, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i4 = GST_TEST_OBJ (e)->val_int;
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_TRIANGLE, NULL);
gst_object_sync_values (e, t * GST_SECOND);
i5 = GST_TEST_OBJ (e)->val_int;
fprintf (f, "%4.1f %d %d %d %d %d\n", (gfloat) t, i1, i2, i3, i4, i5);
}
fclose (f);
/* test value arrays */
if (!(f = fopen ("ctrl_l2.dat", "w")))
exit (-1);
fprintf (f, "# Time Sine Square Saw RevSaw Triangle\n");
n_values = 40 * 10;
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_SINE, NULL);
v1 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v1);
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_SQUARE, NULL);
v2 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v2);
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_SAW, NULL);
v3 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v3);
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_REVERSE_SAW, NULL);
v4 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v4);
g_object_set (cs, "waveform", GST_LFO_WAVEFORM_TRIANGLE, NULL);
v5 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v5);
for (t = 0; t < n_values; t++) {
i1 = g_value_get_int (&v1[t]);
i2 = g_value_get_int (&v2[t]);
i3 = g_value_get_int (&v3[t]);
i4 = g_value_get_int (&v4[t]);
i5 = g_value_get_int (&v5[t]);
fprintf (f, "%4.1f %d %d %d %d %d\n", (gfloat) t / 10.0, i1, i2, i3, i4,
i5);
g_value_unset (&v1[t]);
g_value_unset (&v2[t]);
g_value_unset (&v3[t]);
g_value_unset (&v4[t]);
g_value_unset (&v5[t]);
}
g_free (v1);
g_free (v2);
g_free (v3);
g_free (v4);
g_free (v5);
fclose (f);
gst_object_unref (cs);
gst_object_unref (e);
}
static void
test_chained_lfo (void)
{
GstObject *e;
GstControlSource *cs1, *cs2;
gint t, i1;
GValue *v1;
gint n_values;
FILE *f;
e = (GstObject *) gst_element_factory_make ("testobj", NULL);
cs1 = gst_lfo_control_source_new ();
gst_object_add_control_binding (e, gst_direct_control_binding_new (e, "int",
cs1));
g_object_set (cs1,
"waveform", GST_LFO_WAVEFORM_SINE,
"frequency", (gdouble) 0.05,
"timeshift", (GstClockTime) 0, "offset", (gdouble) 0.5, NULL);
cs2 = gst_lfo_control_source_new ();
gst_object_add_control_binding ((GstObject *) cs1,
gst_direct_control_binding_new ((GstObject *) cs1, "amplitude", cs2));
g_object_set (cs2,
"waveform", GST_LFO_WAVEFORM_SINE,
"frequency", (gdouble) 0.05,
"timeshift", (GstClockTime) 0,
"amplitude", (gdouble) 0.5, "offset", (gdouble) 0.5, NULL);
/* test single values */
if (!(f = fopen ("ctrl_cl1.dat", "w")))
exit (-1);
fprintf (f, "# Time Sine\n");
for (t = 0; t < 40; t++) {
gst_object_sync_values (e, t * GST_SECOND);
i1 = GST_TEST_OBJ (e)->val_int;
fprintf (f, "%4.1f %d\n", (gfloat) t, i1);
}
fclose (f);
/* test value arrays */
if (!(f = fopen ("ctrl_cl2.dat", "w")))
exit (-1);
fprintf (f, "# Time Sine\n");
n_values = 40 * 10;
v1 = g_new0 (GValue, n_values);
gst_object_get_g_value_array (e, "int", 0, GST_SECOND / 10, n_values, v1);
for (t = 0; t < n_values; t++) {
i1 = g_value_get_int (&v1[t]);
fprintf (f, "%4.1f %d\n", (gfloat) t / 10.0, i1);
g_value_unset (&v1[t]);
}
g_free (v1);
fclose (f);
gst_object_unref (cs1);
gst_object_unref (cs2);
gst_object_unref (e);
}
gint
main (gint argc, gchar ** argv)
{
gst_init (&argc, &argv);
gst_element_register (NULL, "testobj", GST_RANK_NONE, GST_TYPE_TEST_OBJ);
test_interpolation ();
test_lfo ();
test_chained_lfo ();
return 0;
}