gst/debug/: Port progressreport, navseek, navigationtest, testsink and breakmydata.

Original commit message from CVS:
* gst/debug/Makefile.am:
* gst/debug/breakmydata.c:
* gst/debug/gstdebug.c:
* gst/debug/gstnavigationtest.c:
* gst/debug/gstnavseek.c:
* gst/debug/gstnavseek.h:
* gst/debug/progressreport.c:
* gst/debug/testplugin.c:
Port progressreport, navseek, navigationtest, testsink and
breakmydata.
This commit is contained in:
Tim-Philipp Müller 2005-10-05 11:38:29 +00:00
parent 76620459d5
commit 2fa12d1a6d
9 changed files with 736 additions and 596 deletions

View file

@ -1,3 +1,16 @@
2005-10-05 Tim-Philipp Müller <tim at centricular dot net>
* gst/debug/Makefile.am:
* gst/debug/breakmydata.c:
* gst/debug/gstdebug.c:
* gst/debug/gstnavigationtest.c:
* gst/debug/gstnavseek.c:
* gst/debug/gstnavseek.h:
* gst/debug/progressreport.c:
* gst/debug/testplugin.c:
Port progressreport, navseek, navigationtest, testsink and
breakmydata.
2005-10-05 Edward Hervey <edward@fluendo.com> 2005-10-05 Edward Hervey <edward@fluendo.com>
* ext/dv/gstdvdemux.c: (gst_dvdemux_src_convert), * ext/dv/gstdvdemux.c: (gst_dvdemux_src_convert),

View file

@ -1,4 +1,4 @@
plugin_LTLIBRARIES = libgstefence.la # libgstnavigationtest.la libgstdebug.la plugin_LTLIBRARIES = libgstefence.la libgstdebug.la libgstnavigationtest.la
noinst_HEADERS = efence.h gstnavigationtest.h gstnavseek.h tests.h noinst_HEADERS = efence.h gstnavigationtest.h gstnavseek.h tests.h
@ -7,18 +7,20 @@ libgstefence_la_CFLAGS = $(GST_CFLAGS)
libgstefence_la_LIBADD = $(GST_LIBS) libgstefence_la_LIBADD = $(GST_LIBS)
libgstefence_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstefence_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
# libgstnavigationtest_la_SOURCES = gstnavigationtest.c libgstnavigationtest_la_SOURCES = gstnavigationtest.c
# libgstnavigationtest_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/gst/videofilter libgstnavigationtest_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/gst/videofilter
# libgstnavigationtest_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstnavigationtest_la_LIBADD = $(GST_LIBS) $(top_builddir)/gst/videofilter/libgstvideofilter-@GST_MAJORMINOR@.la
# libgstnavigationtest_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
# libgstdebug_la_SOURCES = \
# gstdebug.c \ libgstdebug_la_SOURCES = \
# breakmydata.c \ gstdebug.c \
# negotiation.c \ breakmydata.c \
# gstnavseek.c \ progressreport.c \
# progressreport.c \ gstnavseek.c \
# tests.c \ tests.c \
# testplugin.c testplugin.c
# # negotiation.c
# libgstdebug_la_CFLAGS = $(GST_CFLAGS)
# libgstdebug_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstdebug_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
libgstdebug_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
libgstdebug_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)

View file

@ -22,6 +22,7 @@
#endif #endif
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
GST_DEBUG_CATEGORY_STATIC (gst_break_my_data_debug); GST_DEBUG_CATEGORY_STATIC (gst_break_my_data_debug);
#define GST_CAT_DEFAULT gst_break_my_data_debug #define GST_CAT_DEFAULT gst_break_my_data_debug
@ -56,10 +57,7 @@ typedef struct _GstBreakMyDataClass GstBreakMyDataClass;
struct _GstBreakMyData struct _GstBreakMyData
{ {
GstElement element; GstBaseTransform basetransform;
GstPad *sinkpad;
GstPad *srcpad;
GRand *rand; GRand *rand;
guint skipped; guint skipped;
@ -72,113 +70,91 @@ struct _GstBreakMyData
struct _GstBreakMyDataClass struct _GstBreakMyDataClass
{ {
GstElementClass parent_class; GstBaseTransformClass parent_class;
}; };
GST_BOILERPLATE (GstBreakMyData, gst_break_my_data, GstElement,
GST_TYPE_ELEMENT)
static void gst_break_my_data_set_property (GObject * object, static void gst_break_my_data_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec); guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_break_my_data_get_property (GObject * object, static void gst_break_my_data_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec); guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_break_my_data_chain (GstPad * pad, GstData * _data); static GstFlowReturn gst_break_my_data_transform_ip (GstBaseTransform * trans,
static GstStateChangeReturn gst_break_my_data_change_state (GstElement * GstBuffer * buf);
element); static gboolean gst_break_my_data_stop (GstBaseTransform * trans);
static gboolean gst_break_my_data_start (GstBaseTransform * trans);
static void gst_break_my_data_base_init (gpointer g_class)
{
static GstElementDetails details = GST_ELEMENT_DETAILS ("breakmydata", static GstElementDetails details = GST_ELEMENT_DETAILS ("breakmydata",
"Testing", "Testing",
"randomly change data in the stream", "randomly change data in the stream",
"Benjamin Otte <otte@gnome>"); "Benjamin Otte <otte@gnome>");
GstStaticPadTemplate bmd_src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GstStaticPadTemplate bmd_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_BOILERPLATE (GstBreakMyData, gst_break_my_data, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM)
static void gst_break_my_data_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&bmd_sink_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&bmd_src_template));
gst_element_class_set_details (gstelement_class, &details); gst_element_class_set_details (gstelement_class, &details);
} }
static void static void
gst_break_my_data_class_init (GstBreakMyDataClass * klass) gst_break_my_data_class_init (GstBreakMyDataClass * klass)
{ {
GObjectClass *object = G_OBJECT_CLASS (klass); GstBaseTransformClass *gstbasetrans_class;
GstElementClass *element = GST_ELEMENT_CLASS (klass); GObjectClass *gobject_class;
object->set_property = GST_DEBUG_FUNCPTR (gst_break_my_data_set_property); gobject_class = G_OBJECT_CLASS (klass);
object->get_property = GST_DEBUG_FUNCPTR (gst_break_my_data_get_property); gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
g_object_class_install_property (object, ARG_SEED, gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_break_my_data_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_break_my_data_get_property);
g_object_class_install_property (gobject_class, ARG_SEED,
g_param_spec_uint ("seed", "seed", g_param_spec_uint ("seed", "seed",
"seed for randomness (initialized when goint from READY to PAUSED)", "seed for randomness (initialized when going from READY to PAUSED)",
0, 0xFFFFFFFF, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object, ARG_SET_TO, g_object_class_install_property (gobject_class, ARG_SET_TO,
g_param_spec_int ("set-to", "set-to", g_param_spec_int ("set-to", "set-to",
"set changed bytes to this value (-1 means random value", "set changed bytes to this value (-1 means random value",
-1, 255, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -1, 255, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object, ARG_SKIP, g_object_class_install_property (gobject_class, ARG_SKIP,
g_param_spec_uint ("skip", "skip", g_param_spec_uint ("skip", "skip",
"amount of bytes skipped at the beginning of stream", "amount of bytes skipped at the beginning of stream",
0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object, ARG_PROBABILITY, g_object_class_install_property (gobject_class, ARG_PROBABILITY,
g_param_spec_double ("probability", "probability", g_param_spec_double ("probability", "probability",
"probability that a buffer is changed", 0.0, 1.0, 0.0, "probability for each byte in the buffer to be changed", 0.0, 1.0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); 0.0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
element->change_state = gst_break_my_data_change_state; gstbasetrans_class->transform_ip =
GST_DEBUG_FUNCPTR (gst_break_my_data_transform_ip);
gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_break_my_data_start);
gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_break_my_data_stop);
gstbasetrans_class->passthrough_on_same_caps = TRUE;
} }
static void static void
gst_break_my_data_init (GstBreakMyData * break_my_data) gst_break_my_data_init (GstBreakMyData * bmd, GstBreakMyDataClass * g_class)
{ {
break_my_data->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); gst_base_transform_set_in_place (GST_BASE_TRANSFORM (bmd), TRUE);
gst_element_add_pad (GST_ELEMENT (break_my_data), break_my_data->sinkpad);
gst_pad_set_chain_function (break_my_data->sinkpad,
GST_DEBUG_FUNCPTR (gst_break_my_data_chain));
gst_pad_set_link_function (break_my_data->sinkpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (break_my_data->sinkpad, gst_pad_proxy_getcaps);
break_my_data->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_element_add_pad (GST_ELEMENT (break_my_data), break_my_data->srcpad);
gst_pad_set_link_function (break_my_data->srcpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (break_my_data->srcpad, gst_pad_proxy_getcaps);
}
static void
gst_break_my_data_chain (GstPad * pad, GstData * data)
{
GstBuffer *copy = NULL, *buf = GST_BUFFER (data);
GstBreakMyData *bmd = GST_BREAK_MY_DATA (gst_pad_get_parent (pad));
guint i, size;
if (bmd->skipped < bmd->skip) {
i = bmd->skip - bmd->skipped;
} else {
i = 0;
}
size = GST_BUFFER_SIZE (buf);
GST_LOG_OBJECT (bmd,
"got buffer %p (size %u, timestamp %" G_GUINT64_FORMAT ", offset %"
G_GUINT64_FORMAT "", buf, size, GST_BUFFER_TIMESTAMP (buf),
GST_BUFFER_OFFSET (buf));
for (; i < size; i++) {
if (g_rand_double_range (bmd->rand, 0, 1) < bmd->probability) {
guint8 new;
if (!copy)
copy = gst_buffer_copy_on_write (buf);
if (bmd->set < 0) {
new = g_rand_int_range (bmd->rand, 0, 256);
} else {
new = bmd->set;
}
GST_INFO_OBJECT (bmd, "changing byte %u from 0x%2X to 0x%2X", i,
(gint) GST_BUFFER_DATA (copy)[i], (gint) new);
GST_BUFFER_DATA (copy)[i] = new;
}
}
/* don't overflow */
bmd->skipped += MIN (G_MAXUINT - bmd->skipped, GST_BUFFER_SIZE (buf));
gst_pad_push (bmd->srcpad, GST_DATA (copy ? copy : buf));
} }
static void static void
@ -187,6 +163,8 @@ gst_break_my_data_set_property (GObject * object, guint prop_id,
{ {
GstBreakMyData *bmd = GST_BREAK_MY_DATA (object); GstBreakMyData *bmd = GST_BREAK_MY_DATA (object);
GST_LOCK (bmd);
switch (prop_id) { switch (prop_id) {
case ARG_SEED: case ARG_SEED:
bmd->seed = g_value_get_uint (value); bmd->seed = g_value_get_uint (value);
@ -204,6 +182,8 @@ gst_break_my_data_set_property (GObject * object, guint prop_id,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
GST_UNLOCK (bmd);
} }
static void static void
@ -212,6 +192,8 @@ gst_break_my_data_get_property (GObject * object, guint prop_id, GValue * value,
{ {
GstBreakMyData *bmd = GST_BREAK_MY_DATA (object); GstBreakMyData *bmd = GST_BREAK_MY_DATA (object);
GST_LOCK (bmd);
switch (prop_id) { switch (prop_id) {
case ARG_SEED: case ARG_SEED:
g_value_set_uint (value, bmd->seed); g_value_set_uint (value, bmd->seed);
@ -229,27 +211,80 @@ gst_break_my_data_get_property (GObject * object, guint prop_id, GValue * value,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
GST_UNLOCK (bmd);
} }
static GstStateChangeReturn static GstFlowReturn
gst_break_my_data_change_state (GstElement * element, GstStateChange transition) gst_break_my_data_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{ {
GstBreakMyData *bmd = GST_BREAK_MY_DATA (element); GstBreakMyData *bmd = GST_BREAK_MY_DATA (trans);
guint i, size;
switch (transition) { g_return_val_if_fail (gst_buffer_is_writable (buf), GST_FLOW_ERROR);
case GST_STATE_CHANGE_READY_TO_PAUSED:
GST_LOCK (bmd);
if (bmd->skipped < bmd->skip) {
i = bmd->skip - bmd->skipped;
} else {
i = 0;
}
size = GST_BUFFER_SIZE (buf);
GST_LOG_OBJECT (bmd,
"got buffer %p (size %u, timestamp %" G_GUINT64_FORMAT ", offset %"
G_GUINT64_FORMAT "", buf, size, GST_BUFFER_TIMESTAMP (buf),
GST_BUFFER_OFFSET (buf));
for (; i < size; i++) {
if (g_rand_double_range (bmd->rand, 0, 1.0) <= bmd->probability) {
guint8 new;
if (bmd->set < 0) {
new = g_rand_int_range (bmd->rand, 0, 256);
} else {
new = bmd->set;
}
GST_INFO_OBJECT (bmd, "changing byte %u from 0x%02X to 0x%02X", i,
(guint) GST_READ_UINT8 (GST_BUFFER_DATA (buf) + i),
(guint) ((guint8) new));
GST_BUFFER_DATA (buf)[i] = new;
}
}
/* don't overflow */
bmd->skipped += MIN (G_MAXUINT - bmd->skipped, GST_BUFFER_SIZE (buf));
GST_UNLOCK (bmd);
return GST_FLOW_OK;
}
static gboolean
gst_break_my_data_start (GstBaseTransform * trans)
{
GstBreakMyData *bmd = GST_BREAK_MY_DATA (trans);
GST_LOCK (bmd);
bmd->rand = g_rand_new_with_seed (bmd->seed); bmd->rand = g_rand_new_with_seed (bmd->seed);
bmd->skipped = 0; bmd->skipped = 0;
break; GST_UNLOCK (bmd);
case GST_STATE_CHANGE_PAUSED_TO_READY:
g_rand_free (bmd->rand); return TRUE;
break;
default:
break;
} }
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, static gboolean
(element), GST_STATE_CHANGE_SUCCESS); gst_break_my_data_stop (GstBaseTransform * trans)
{
GstBreakMyData *bmd = GST_BREAK_MY_DATA (trans);
GST_LOCK (bmd);
g_rand_free (bmd->rand);
bmd->rand = NULL;
GST_UNLOCK (bmd);
return TRUE;
} }
gboolean gboolean

View file

@ -23,20 +23,20 @@
#include <gst/gst.h> #include <gst/gst.h>
gboolean gst_progress_report_plugin_init (GstPlugin * plugin);
gboolean gst_break_my_data_plugin_init (GstPlugin * plugin);
gboolean gst_negotiation_plugin_init (GstPlugin * plugin);
gboolean gst_navseek_plugin_init (GstPlugin * plugin); gboolean gst_navseek_plugin_init (GstPlugin * plugin);
gboolean gst_progressreport_plugin_init (GstPlugin * plugin);
gboolean gst_test_plugin_init (GstPlugin * plugin); gboolean gst_test_plugin_init (GstPlugin * plugin);
gboolean gst_break_my_data_plugin_init (GstPlugin * plugin);
/* gboolean gst_negotiation_plugin_init (GstPlugin * plugin); */
static gboolean static gboolean
plugin_init (GstPlugin * plugin) plugin_init (GstPlugin * plugin)
{ {
if (!gst_break_my_data_plugin_init (plugin) || if (!gst_break_my_data_plugin_init (plugin) ||
!gst_negotiation_plugin_init (plugin) ||
!gst_navseek_plugin_init (plugin) || !gst_navseek_plugin_init (plugin) ||
!gst_progressreport_plugin_init (plugin) || /* !gst_negotiation_plugin_init (plugin) || */
!gst_progress_report_plugin_init (plugin) ||
!gst_test_plugin_init (plugin)) !gst_test_plugin_init (plugin))
return FALSE; return FALSE;

View file

@ -27,24 +27,10 @@
#include "config.h" #include "config.h"
#endif #endif
/*#define DEBUG_ENABLED */
#include <gstnavigationtest.h> #include <gstnavigationtest.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
/* GstNavigationtest signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0
/* FILL ME */
};
typedef struct typedef struct
{ {
double x; double x;
@ -61,10 +47,6 @@ static void gst_navigationtest_init (GTypeInstance * instance,
static gboolean gst_navigationtest_handle_src_event (GstPad * pad, static gboolean gst_navigationtest_handle_src_event (GstPad * pad,
GstEvent * event); GstEvent * event);
static void gst_navigationtest_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_navigationtest_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstStateChangeReturn static GstStateChangeReturn
gst_navigationtest_change_state (GstElement * element, gst_navigationtest_change_state (GstElement * element,
@ -74,7 +56,7 @@ static void gst_navigationtest_planar411 (GstVideofilter * videofilter,
void *dest, void *src); void *dest, void *src);
static void gst_navigationtest_setup (GstVideofilter * videofilter); static void gst_navigationtest_setup (GstVideofilter * videofilter);
static GstVideofilterClass *parent_class = NULL; static GstVideofilterClass *parent_class; /* NULL */
GType GType
gst_navigationtest_get_type (void) gst_navigationtest_get_type (void)
@ -130,15 +112,11 @@ gst_navigationtest_base_init (gpointer g_class)
static void static void
gst_navigationtest_class_init (gpointer g_class, gpointer class_data) gst_navigationtest_class_init (gpointer g_class, gpointer class_data)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class); GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_class); parent_class = g_type_class_peek_parent (g_class);
gobject_class->set_property = gst_navigationtest_set_property;
gobject_class->get_property = gst_navigationtest_get_property;
element_class->change_state = gst_navigationtest_change_state; element_class->change_state = gst_navigationtest_change_state;
videofilter_class->setup = gst_navigationtest_setup; videofilter_class->setup = gst_navigationtest_setup;
@ -147,67 +125,58 @@ gst_navigationtest_class_init (gpointer g_class, gpointer class_data)
static void static void
gst_navigationtest_init (GTypeInstance * instance, gpointer g_class) gst_navigationtest_init (GTypeInstance * instance, gpointer g_class)
{ {
GstNavigationtest *navigationtest = GST_NAVIGATIONTEST (instance); GstNavigationtest *navtest = GST_NAVIGATIONTEST (instance);
GstVideofilter *videofilter; GstVideofilter *videofilter = GST_VIDEOFILTER (navtest);
GST_DEBUG ("gst_navigationtest_init");
videofilter = GST_VIDEOFILTER (navigationtest);
gst_pad_set_event_function (videofilter->srcpad, gst_pad_set_event_function (videofilter->srcpad,
gst_navigationtest_handle_src_event); GST_DEBUG_FUNCPTR (gst_navigationtest_handle_src_event));
navigationtest->x = -1; navtest->x = -1;
navigationtest->y = -1; navtest->y = -1;
} }
static gboolean static gboolean
gst_navigationtest_handle_src_event (GstPad * pad, GstEvent * event) gst_navigationtest_handle_src_event (GstPad * pad, GstEvent * event)
{ {
GstNavigationtest *navigationtest; GstNavigationtest *navtest;
const gchar *type; const gchar *type;
navigationtest = GST_NAVIGATIONTEST (gst_pad_get_parent (pad)); navtest = GST_NAVIGATIONTEST (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NAVIGATION: case GST_EVENT_NAVIGATION:
type = gst_structure_get_string (event->event_data.structure.structure, {
"event"); const GstStructure *s = gst_event_get_structure (event);
type = gst_structure_get_string (s, "event");
if (g_str_equal (type, "mouse-move")) { if (g_str_equal (type, "mouse-move")) {
gst_structure_get_double (event->event_data.structure.structure, gst_structure_get_double (s, "pointer_x", &navtest->x);
"pointer_x", &navigationtest->x); gst_structure_get_double (s, "pointer_y", &navtest->y);
gst_structure_get_double (event->event_data.structure.structure,
"pointer_y", &navigationtest->y);
} else if (g_str_equal (type, "mouse-button-press")) { } else if (g_str_equal (type, "mouse-button-press")) {
ButtonClick *click = g_new (ButtonClick, 1); ButtonClick *click = g_new (ButtonClick, 1);
gst_structure_get_double (event->event_data.structure.structure, gst_structure_get_double (s, "pointer_x", &click->x);
"pointer_x", &click->x); gst_structure_get_double (s, "pointer_y", &click->y);
gst_structure_get_double (event->event_data.structure.structure, click->images_left = ceil (GST_VIDEOFILTER (navtest)->framerate);
"pointer_y", &click->y);
click->images_left = ceil (GST_VIDEOFILTER (navigationtest)->framerate);
/* green */ /* green */
click->cy = 150; click->cy = 150;
click->cu = 46; click->cu = 46;
click->cv = 21; click->cv = 21;
navigationtest->clicks = navtest->clicks = g_slist_prepend (navtest->clicks, click);
g_slist_prepend (navigationtest->clicks, click);
} else if (g_str_equal (type, "mouse-button-release")) { } else if (g_str_equal (type, "mouse-button-release")) {
ButtonClick *click = g_new (ButtonClick, 1); ButtonClick *click = g_new (ButtonClick, 1);
gst_structure_get_double (event->event_data.structure.structure, gst_structure_get_double (s, "pointer_x", &click->x);
"pointer_x", &click->x); gst_structure_get_double (s, "pointer_y", &click->y);
gst_structure_get_double (event->event_data.structure.structure, click->images_left = ceil (GST_VIDEOFILTER (navtest)->framerate);
"pointer_y", &click->y);
click->images_left = ceil (GST_VIDEOFILTER (navigationtest)->framerate);
/* red */ /* red */
click->cy = 76; click->cy = 76;
click->cu = 85; click->cu = 85;
click->cv = 255; click->cv = 255;
navigationtest->clicks = navtest->clicks = g_slist_prepend (navtest->clicks, click);
g_slist_prepend (navigationtest->clicks, click);
} }
break; break;
}
default: default:
break; break;
} }
@ -215,64 +184,7 @@ gst_navigationtest_handle_src_event (GstPad * pad, GstEvent * event)
} }
static void static void
gst_navigationtest_set_property (GObject * object, guint prop_id, gst_navigationtest_setup (GstVideofilter * videofilter)
const GValue * value, GParamSpec * pspec)
{
GstNavigationtest *src;
g_return_if_fail (GST_IS_NAVIGATIONTEST (object));
src = GST_NAVIGATIONTEST (object);
GST_DEBUG ("gst_navigationtest_set_property");
switch (prop_id) {
#if 0
case ARG_METHOD:
src->method = g_value_get_enum (value);
break;
#endif
default:
break;
}
}
static void
gst_navigationtest_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstNavigationtest *src;
g_return_if_fail (GST_IS_NAVIGATIONTEST (object));
src = GST_NAVIGATIONTEST (object);
switch (prop_id) {
#if 0
case ARG_METHOD:
g_value_set_enum (value, src->method);
break;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_library_load ("gstvideofilter"))
return FALSE;
return gst_element_register (plugin, "navigationtest", GST_RANK_NONE,
GST_TYPE_NAVIGATIONTEST);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"navigationtest",
"Template for a video filter",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
static void gst_navigationtest_setup (GstVideofilter * videofilter)
{ {
GstNavigationtest *navigationtest; GstNavigationtest *navigationtest;
@ -328,19 +240,20 @@ static void
gst_navigationtest_planar411 (GstVideofilter * videofilter, gst_navigationtest_planar411 (GstVideofilter * videofilter,
void *dest, void *src) void *dest, void *src)
{ {
GstNavigationtest *navigationtest; GstNavigationtest *navtest = (GstNavigationtest *) videofilter;
int width = gst_videofilter_get_input_width (videofilter); gint width, height;
int height = gst_videofilter_get_input_height (videofilter);
GSList *walk; GSList *walk;
g_return_if_fail (GST_IS_NAVIGATIONTEST (videofilter)); g_return_if_fail (GST_IS_NAVIGATIONTEST (videofilter));
navigationtest = GST_NAVIGATIONTEST (videofilter);
width = gst_videofilter_get_input_width (videofilter);
height = gst_videofilter_get_input_height (videofilter);
/* do something interesting here. This simply copies the source /* do something interesting here. This simply copies the source
* to the destination. */ * to the destination. */
memcpy (dest, src, width * height + (width / 2) * (height / 2) * 2); memcpy (dest, src, width * height + (width / 2) * (height / 2) * 2);
walk = navigationtest->clicks; walk = navtest->clicks;
while (walk) { while (walk) {
ButtonClick *click = walk->data; ButtonClick *click = walk->data;
@ -348,32 +261,55 @@ gst_navigationtest_planar411 (GstVideofilter * videofilter,
draw_box_planar411 (dest, width, height, rint (click->x), draw_box_planar411 (dest, width, height, rint (click->x),
rint (click->y), click->cy, click->cu, click->cv); rint (click->y), click->cy, click->cu, click->cv);
if (--click->images_left < 1) { if (--click->images_left < 1) {
navigationtest->clicks = g_slist_remove (navigationtest->clicks, click); navtest->clicks = g_slist_remove (navtest->clicks, click);
g_free (click); g_free (click);
} }
} }
draw_box_planar411 (dest, width, height, rint (navigationtest->x), draw_box_planar411 (dest, width, height, rint (navtest->x),
rint (navigationtest->y), 0, 128, 128); rint (navtest->y), 0, 128, 128);
} }
static GstStateChangeReturn static GstStateChangeReturn
gst_navigationtest_change_state (GstElement * element, gst_navigationtest_change_state (GstElement * element,
GstStateChange transition) GstStateChange transition)
{ {
GstNavigationtest *navigation = GST_NAVIGATIONTEST (element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstNavigationtest *navtest = GST_NAVIGATIONTEST (element);
/* upwards state changes */
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY: default:
while (navigation->clicks) {
g_free (navigation->clicks->data);
navigation->clicks =
g_slist_remove (navigation->clicks, navigation->clicks->data);
}
break; break;
} }
if (GST_ELEMENT_CLASS (parent_class)->change_state) if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
return GST_STATE_CHANGE_SUCCESS; /* downwards state changes */
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
{
g_slist_foreach (navtest->clicks, (GFunc) g_free, NULL);
g_slist_free (navtest->clicks);
navtest->clicks = NULL;
break;
} }
default:
break;
}
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "navigationtest", GST_RANK_NONE,
GST_TYPE_NAVIGATIONTEST);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"navigationtest",
"Template for a video filter",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)

View file

@ -27,22 +27,14 @@
#include "config.h" #include "config.h"
#endif #endif
#include <gstnavseek.h> #include "gstnavseek.h"
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
/* GstNavSeek signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum enum
{ {
ARG_0, ARG_0,
ARG_SEEKOFFSET ARG_SEEKOFFSET
/* FILL ME */
}; };
GstStaticPadTemplate navseek_src_template = GST_STATIC_PAD_TEMPLATE ("src", GstStaticPadTemplate navseek_src_template = GST_STATIC_PAD_TEMPLATE ("src",
@ -55,49 +47,30 @@ GstStaticPadTemplate navseek_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY); GST_STATIC_CAPS_ANY);
static void gst_navseek_base_init (gpointer g_class);
static void gst_navseek_class_init (gpointer g_class, gpointer class_data);
static void gst_navseek_init (GTypeInstance * instance, gpointer g_class);
static gboolean gst_navseek_handle_src_event (GstPad * pad, GstEvent * event);
static void gst_navseek_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_navseek_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_navseek_chain (GstPad * pad, GstData * _data);
static GType
gst_navseek_get_type (void)
{
static GType navseek_type = 0;
if (!navseek_type) {
static const GTypeInfo navseek_info = {
sizeof (GstNavSeekClass),
gst_navseek_base_init,
NULL,
gst_navseek_class_init,
NULL,
NULL,
sizeof (GstNavSeek),
0,
gst_navseek_init,
};
navseek_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstNavSeek", &navseek_info, 0);
}
return navseek_type;
}
static void
gst_navseek_base_init (gpointer g_class)
{
static GstElementDetails navseek_details = static GstElementDetails navseek_details =
GST_ELEMENT_DETAILS ("Seek based on left-right arrows", GST_ELEMENT_DETAILS ("Seek based on left-right arrows",
"Filter/Video", "Filter/Video",
"Seek based on navigation keys left-right", "Seek based on navigation keys left-right",
"Jan Schmidt <thaytan@mad.scientist.com>"); "Jan Schmidt <thaytan@mad.scientist.com>");
static gboolean gst_navseek_event (GstBaseTransform * trans, GstEvent * event);
static GstFlowReturn gst_navseek_transform_ip (GstBaseTransform * basetrans,
GstBuffer * buf);
static gboolean gst_navseek_handle_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_navseek_stop (GstBaseTransform * trans);
static gboolean gst_navseek_start (GstBaseTransform * trans);
static void gst_navseek_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_navseek_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
GST_BOILERPLATE (GstNavSeek, gst_navseek, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM);
static void
gst_navseek_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
@ -109,43 +82,36 @@ gst_navseek_base_init (gpointer g_class)
} }
static void static void
gst_navseek_class_init (gpointer g_class, gpointer class_data) gst_navseek_class_init (GstNavSeekClass * klass)
{ {
GstBaseTransformClass *gstbasetrans_class;
GObjectClass *gobject_class; GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (g_class); gobject_class = G_OBJECT_CLASS (klass);
gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
g_object_class_install_property (G_OBJECT_CLASS (g_class), gobject_class->set_property = gst_navseek_set_property;
gobject_class->get_property = gst_navseek_get_property;
g_object_class_install_property (gobject_class,
ARG_SEEKOFFSET, g_param_spec_double ("seek-offset", "Seek Offset", ARG_SEEKOFFSET, g_param_spec_double ("seek-offset", "Seek Offset",
"Time in seconds to seek by", 0.0, G_MAXDOUBLE, 5.0, "Time in seconds to seek by", 0.0, G_MAXDOUBLE, 5.0,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
gobject_class->set_property = gst_navseek_set_property; gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_navseek_event);
gobject_class->get_property = gst_navseek_get_property; gstbasetrans_class->transform_ip =
GST_DEBUG_FUNCPTR (gst_navseek_transform_ip);
gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_navseek_start);
gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_navseek_stop);
} }
static void static void
gst_navseek_init (GTypeInstance * instance, gpointer g_class) gst_navseek_init (GstNavSeek * navseek, GstNavSeekClass * g_class)
{ {
GstNavSeek *navseek = GST_NAVSEEK (instance); gst_pad_set_event_function (GST_BASE_TRANSFORM (navseek)->srcpad,
GST_DEBUG_FUNCPTR (gst_navseek_handle_src_event));
navseek->sinkpad = gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (navseek), TRUE);
gst_pad_new_from_template (gst_static_pad_template_get
(&navseek_sink_template), "sink");
gst_element_add_pad (GST_ELEMENT (navseek), navseek->sinkpad);
gst_pad_set_chain_function (navseek->sinkpad, gst_navseek_chain);
gst_pad_set_link_function (navseek->sinkpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (navseek->sinkpad, gst_pad_proxy_getcaps);
navseek->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&navseek_src_template), "src");
gst_element_add_pad (GST_ELEMENT (navseek), navseek->srcpad);
gst_pad_set_link_function (navseek->srcpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (navseek->srcpad, gst_pad_proxy_getcaps);
gst_pad_set_event_function (navseek->srcpad, gst_navseek_handle_src_event);
GST_FLAG_SET (GST_ELEMENT (navseek), GST_ELEMENT_EVENT_AWARE);
navseek->seek_offset = 5.0; navseek->seek_offset = 5.0;
navseek->loop = FALSE; navseek->loop = FALSE;
@ -158,74 +124,90 @@ gst_navseek_init (GTypeInstance * instance, gpointer g_class)
static void static void
gst_navseek_seek (GstNavSeek * navseek, gint64 offset) gst_navseek_seek (GstNavSeek * navseek, gint64 offset)
{ {
/* Query for the current time then attempt to set to time + offset */
gint64 peer_value;
GstFormat peer_format = GST_FORMAT_TIME; GstFormat peer_format = GST_FORMAT_TIME;
gboolean ret;
GstPad *peer_pad;
gint64 peer_value;
if (gst_pad_query (gst_pad_get_peer (navseek->sinkpad),
GST_QUERY_POSITION, &peer_format, &peer_value)) { /* Query for the current time then attempt to set to time + offset */
if (peer_format != GST_FORMAT_TIME) peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
return; ret = gst_pad_query_position (peer_pad, &peer_format, &peer_value, NULL);
if (ret && peer_format == GST_FORMAT_TIME) {
GstEvent *event;
peer_value += offset; peer_value += offset;
if (peer_value < 0) if (peer_value < 0)
peer_value = 0; peer_value = 0;
gst_element_seek (GST_ELEMENT (navseek), event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH,
GST_SEEK_FLAG_FLUSH, peer_value); GST_SEEK_TYPE_SET, peer_value, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
gst_pad_send_event (peer_pad, event);
} }
gst_object_unref (peer_pad);
} }
static void static void
gst_navseek_segseek (GstNavSeek * navseek) gst_navseek_segseek (GstNavSeek * navseek)
{ {
GstEvent *event; GstEvent *event;
GstPad *peer_pad;
if ((navseek->segment_start == GST_CLOCK_TIME_NONE) || if ((navseek->segment_start == GST_CLOCK_TIME_NONE) ||
(navseek->segment_end == GST_CLOCK_TIME_NONE) || (navseek->segment_end == GST_CLOCK_TIME_NONE) ||
(!GST_PAD_IS_LINKED (navseek->sinkpad))) { (!GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad))) {
return; return;
} }
if (navseek->loop) { if (navseek->loop) {
event = event =
gst_event_new_segment_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME | gst_event_new_seek (1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT_LOOP, GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT,
navseek->segment_start, navseek->segment_end); GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
navseek->segment_end);
} else { } else {
event = event =
gst_event_new_segment_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME | gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE,
GST_SEEK_FLAG_ACCURATE, navseek->segment_start, navseek->segment_end); GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
navseek->segment_end);
} }
g_return_if_fail (event != NULL); peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
gst_pad_send_event (gst_pad_get_peer (navseek->sinkpad), event); gst_pad_send_event (peer_pad, event);
gst_object_unref (peer_pad);
} }
static gboolean static gboolean
gst_navseek_handle_src_event (GstPad * pad, GstEvent * event) gst_navseek_handle_src_event (GstPad * pad, GstEvent * event)
{ {
GstNavSeek *navseek; GstNavSeek *navseek;
gboolean ret = TRUE;
navseek = GST_NAVSEEK (gst_pad_get_parent (pad)); navseek = GST_NAVSEEK (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NAVIGATION: case GST_EVENT_NAVIGATION:
/* Check for a keyup and convert left/right to a seek event */ /* Check for a keyup and convert left/right to a seek event */
{ {
GstStructure *structure; const GstStructure *structure;
const gchar *event_type; const gchar *event_type;
structure = event->event_data.structure.structure; structure = gst_event_get_structure (event);
event_type = gst_structure_get_string (structure, "event"); g_return_val_if_fail (structure != NULL, FALSE);
g_return_val_if_fail (event != NULL, FALSE); event_type = gst_structure_get_string (structure, "event");
g_return_val_if_fail (event_type != NULL, FALSE);
if (strcmp (event_type, "key-press") == 0) { if (strcmp (event_type, "key-press") == 0) {
const char *key = gst_structure_get_string (structure, "key"); const gchar *key;
key = gst_structure_get_string (structure, "key");
g_return_val_if_fail (key != NULL, FALSE);
g_assert (key != NULL);
if (strcmp (key, "Left") == 0) { if (strcmp (key, "Left") == 0) {
/* Seek backward by 5 secs */ /* Seek backward by 5 secs */
gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND); gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND);
@ -253,42 +235,28 @@ gst_navseek_handle_src_event (GstPad * pad, GstEvent * event)
default: default:
break; break;
} }
if ((event) && GST_PAD_IS_LINKED (navseek->sinkpad)) {
return gst_pad_send_event (gst_pad_get_peer (navseek->sinkpad), event); if (event && GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad)) {
GstPad *peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
ret = gst_pad_send_event (peer_pad, event);
gst_object_unref (peer_pad);
} }
return TRUE;
return ret;
} }
static void static void
gst_navseek_set_property (GObject * object, guint prop_id, gst_navseek_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
{ {
GstNavSeek *src; GstNavSeek *navseek = GST_NAVSEEK (object);
g_return_if_fail (GST_IS_NAVSEEK (object));
src = GST_NAVSEEK (object);
switch (prop_id) { switch (prop_id) {
case ARG_SEEKOFFSET: case ARG_SEEKOFFSET:
src->seek_offset = g_value_get_double (value); GST_LOCK (navseek);
break; navseek->seek_offset = g_value_get_double (value);
default: GST_UNLOCK (navseek);
break;
}
}
static void
gst_navseek_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstNavSeek *src;
g_return_if_fail (GST_IS_NAVSEEK (object));
src = GST_NAVSEEK (object);
switch (prop_id) {
case ARG_SEEKOFFSET:
g_value_set_double (value, src->seek_offset);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -297,34 +265,79 @@ gst_navseek_get_property (GObject * object, guint prop_id,
} }
static void static void
gst_navseek_chain (GstPad * pad, GstData * _data) gst_navseek_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{ {
GstNavSeek *navseek; GstNavSeek *navseek = GST_NAVSEEK (object);
navseek = GST_NAVSEEK (gst_pad_get_parent (pad)); switch (prop_id) {
case ARG_SEEKOFFSET:
GST_LOCK (navseek);
g_value_set_double (value, navseek->seek_offset);
GST_UNLOCK (navseek);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
if (GST_IS_BUFFER (_data) && static gboolean
GST_BUFFER_TIMESTAMP_IS_VALID (GST_BUFFER (_data))) { gst_navseek_event (GstBaseTransform * trans, GstEvent * event)
{
GstNavSeek *navseek = GST_NAVSEEK (trans);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
GST_LOCK (navseek);
if (navseek->loop)
gst_navseek_segseek (navseek);
GST_UNLOCK (navseek);
break;
default:
break;
}
return TRUE;
}
static GstFlowReturn
gst_navseek_transform_ip (GstBaseTransform * basetrans, GstBuffer * buf)
{
GstNavSeek *navseek = GST_NAVSEEK (basetrans);
GST_LOCK (navseek);
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
if (navseek->grab_seg_start) { if (navseek->grab_seg_start) {
navseek->segment_start = GST_BUFFER_TIMESTAMP (GST_BUFFER (_data)); navseek->segment_start = GST_BUFFER_TIMESTAMP (buf);
navseek->segment_end = GST_CLOCK_TIME_NONE; navseek->segment_end = GST_CLOCK_TIME_NONE;
navseek->grab_seg_start = FALSE; navseek->grab_seg_start = FALSE;
} }
if (navseek->grab_seg_end) { if (navseek->grab_seg_end) {
navseek->segment_end = GST_BUFFER_TIMESTAMP (GST_BUFFER (_data)); navseek->segment_end = GST_BUFFER_TIMESTAMP (buf);
navseek->grab_seg_end = FALSE; navseek->grab_seg_end = FALSE;
gst_navseek_segseek (navseek); gst_navseek_segseek (navseek);
} }
} }
if (GST_IS_EVENT (_data) && GST_UNLOCK (navseek);
(GST_EVENT_TYPE (GST_EVENT (_data)) == GST_EVENT_SEGMENT_DONE) &&
navseek->loop) { return GST_FLOW_OK;
gst_navseek_segseek (navseek);
} }
gst_pad_push (navseek->srcpad, _data); static gboolean
gst_navseek_start (GstBaseTransform * trans)
{
/* anything we should be doing here? */
return TRUE;
}
static gboolean
gst_navseek_stop (GstBaseTransform * trans)
{
/* anything we should be doing here? */
return TRUE;
} }
gboolean gboolean

View file

@ -23,6 +23,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -41,9 +42,7 @@ typedef struct _GstNavSeek GstNavSeek;
typedef struct _GstNavSeekClass GstNavSeekClass; typedef struct _GstNavSeekClass GstNavSeekClass;
struct _GstNavSeek { struct _GstNavSeek {
GstElement element; GstBaseTransform basetransform;
GstPad *sinkpad;
GstPad *srcpad;
gdouble seek_offset; gdouble seek_offset;
gboolean loop; gboolean loop;
@ -54,7 +53,7 @@ struct _GstNavSeek {
}; };
struct _GstNavSeekClass { struct _GstNavSeekClass {
GstElementClass parent_class; GstBaseTransformClass parent_class;
}; };
G_END_DECLS G_END_DECLS

View file

@ -24,211 +24,320 @@
#endif #endif
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#define GST_TYPE_PROGRESSREPORT \ #define GST_TYPE_PROGRESS_REPORT \
(gst_progressreport_get_type()) (gst_progress_report_get_type())
#define GST_PROGRESSREPORT(obj) \ #define GST_PROGRESS_REPORT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PROGRESSREPORT,GstProgressReport)) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PROGRESS_REPORT,GstProgressReport))
#define GST_PROGRESSREPORT_CLASS(klass) \ #define GST_PROGRESS_REPORT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PROGRESSREPORT,GstProgressReportClass)) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PROGRESS_REPORT,GstProgressReportClass))
#define GST_IS_PROGRESSREPORT(obj) \ #define GST_IS_PROGRESS_REPORT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PROGRESSREPORT)) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PROGRESS_REPORT))
#define GST_IS_PROGRESSREPORT_CLASS(obj) \ #define GST_IS_PROGRESS_REPORT_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PROGRESSREPORT)) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PROGRESS_REPORT))
typedef struct _GstProgressReport GstProgressReport; typedef struct _GstProgressReport GstProgressReport;
typedef struct _GstProgressReportClass GstProgressReportClass; typedef struct _GstProgressReportClass GstProgressReportClass;
struct _GstProgressReport struct _GstProgressReport
{ {
GstElement element; GstBaseTransform basetransform;
GstPad *sinkpad;
GstPad *srcpad;
gint update_freq; gint update_freq;
gboolean silent;
GTimeVal start_time; GTimeVal start_time;
GTimeVal last_report; GTimeVal last_report;
}; };
struct _GstProgressReportClass struct _GstProgressReportClass
{ {
GstElementClass parent_class; GstBaseTransformClass parent_class;
};
/* GstProgressReport signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
}; };
enum enum
{ {
ARG_0, ARG_0,
ARG_UPDATE_FREQ ARG_UPDATE_FREQ,
/* FILL ME */ ARG_SILENT
}; };
GstStaticPadTemplate progressreport_src_template = GstStaticPadTemplate progress_report_src_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY); GST_STATIC_CAPS_ANY);
GstStaticPadTemplate progressreport_sink_template = GstStaticPadTemplate progress_report_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY); GST_STATIC_CAPS_ANY);
static void gst_progressreport_set_property (GObject * object, guint prop_id, static GstElementDetails progress_report_details =
const GValue * value, GParamSpec * pspec);
static void gst_progressreport_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_progressreport_chain (GstPad * pad, GstData * _data);
GST_BOILERPLATE (GstProgressReport, gst_progressreport, GstElement,
GST_TYPE_ELEMENT);
static void
gst_progressreport_base_init (gpointer g_class)
{
static GstElementDetails progressreport_details =
GST_ELEMENT_DETAILS ("Progress Report", GST_ELEMENT_DETAILS ("Progress Report",
"Testing", "Testing",
"Periodically query and report on processing progress", "Periodically query and report on processing progress",
"Jan Schmidt <thaytan@mad.scientist.com>"); "Jan Schmidt <thaytan@mad.scientist.com>");
#define DEFAULT_UPDATE_FREQ 5
#define DEFAULT_SILENT FALSE
static void gst_progress_report_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_progress_report_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_progress_report_event (GstBaseTransform * trans,
GstEvent * event);
static GstFlowReturn gst_progress_report_transform_ip (GstBaseTransform * trans,
GstBuffer * buf);
static gboolean gst_progress_report_start (GstBaseTransform * trans);
static gboolean gst_progress_report_stop (GstBaseTransform * trans);
GST_BOILERPLATE (GstProgressReport, gst_progress_report, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM);
static void
gst_progress_report_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&progressreport_sink_template)); gst_static_pad_template_get (&progress_report_sink_template));
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&progressreport_src_template)); gst_static_pad_template_get (&progress_report_src_template));
gst_element_class_set_details (element_class, &progressreport_details); gst_element_class_set_details (element_class, &progress_report_details);
} }
static void static void
gst_progressreport_class_init (GstProgressReportClass * g_class) gst_progress_report_class_init (GstProgressReportClass * g_class)
{ {
GstBaseTransformClass *gstbasetrans_class;
GObjectClass *gobject_class; GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (g_class); gobject_class = G_OBJECT_CLASS (g_class);
gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (g_class);
gobject_class->set_property = gst_progress_report_set_property;
gobject_class->get_property = gst_progress_report_get_property;
g_object_class_install_property (G_OBJECT_CLASS (g_class), g_object_class_install_property (G_OBJECT_CLASS (g_class),
ARG_UPDATE_FREQ, g_param_spec_int ("update-freq", "Update Frequency", ARG_UPDATE_FREQ, g_param_spec_int ("update-freq", "Update Frequency",
"Number of seconds between reports when data is flowing", 1, G_MAXINT, "Number of seconds between reports when data is flowing", 1, G_MAXINT,
5, G_PARAM_READWRITE)); DEFAULT_UPDATE_FREQ, G_PARAM_READWRITE));
gobject_class->set_property = gst_progressreport_set_property; g_object_class_install_property (G_OBJECT_CLASS (g_class),
gobject_class->get_property = gst_progressreport_get_property; ARG_SILENT, g_param_spec_boolean ("silent",
"Do not print output to stdout", "Do not print output to stdout",
DEFAULT_SILENT, G_PARAM_READWRITE));
gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_progress_report_event);
gstbasetrans_class->transform_ip =
GST_DEBUG_FUNCPTR (gst_progress_report_transform_ip);
gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_progress_report_start);
gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_progress_report_stop);
} }
static void static void
gst_progressreport_init (GstProgressReport * instance, gst_progress_report_init (GstProgressReport * report,
GstProgressReportClass * g_class) GstProgressReportClass * g_class)
{ {
GstProgressReport *progressreport = GST_PROGRESSREPORT (instance); gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (report), TRUE);
progressreport->sinkpad = report->update_freq = DEFAULT_UPDATE_FREQ;
gst_pad_new_from_template (gst_static_pad_template_get report->silent = DEFAULT_SILENT;
(&progressreport_sink_template), "sink");
gst_element_add_pad (GST_ELEMENT (progressreport), progressreport->sinkpad);
gst_pad_set_chain_function (progressreport->sinkpad,
gst_progressreport_chain);
gst_pad_set_link_function (progressreport->sinkpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (progressreport->sinkpad, gst_pad_proxy_getcaps);
progressreport->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&progressreport_src_template), "src");
gst_element_add_pad (GST_ELEMENT (progressreport), progressreport->srcpad);
gst_pad_set_link_function (progressreport->srcpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (progressreport->srcpad, gst_pad_proxy_getcaps);
g_get_current_time (&(progressreport->last_report));
progressreport->start_time = progressreport->last_report;
progressreport->update_freq = 5;
} }
static void static void
gst_progressreport_report (GstProgressReport * progressreport, gst_progress_report_report (GstProgressReport * filter, GTimeVal cur_time)
GTimeVal cur_time)
{ {
/* Query for the current time then attempt to set to time + offset */ GstFormat try_formats[] = { GST_FORMAT_TIME, GST_FORMAT_BYTES,
GST_FORMAT_PERCENT, GST_FORMAT_BUFFERS,
GST_FORMAT_DEFAULT
};
GstPad *peer_pad;
gint64 cur_progress; gint64 cur_progress;
gint64 total_progress; gint64 total_progress;
GstFormat peer_format = GST_FORMAT_DEFAULT; gint hh, mm, ss, i;
gint hh, mm, ss; glong run_time;
glong run_time = cur_time.tv_sec - progressreport->start_time.tv_sec;
GST_LOCK (filter);
run_time = cur_time.tv_sec - filter->start_time.tv_sec;
hh = (run_time / 3600) % 100; hh = (run_time / 3600) % 100;
mm = (run_time / 60) % 60; mm = (run_time / 60) % 60;
ss = (run_time % 60); ss = (run_time % 60);
if (gst_pad_query (gst_pad_get_peer (progressreport->sinkpad), peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (filter)->sinkpad);
GST_QUERY_POSITION, &peer_format, &cur_progress)) { /* Query for the current time then attempt to set to time + offset */
GstFormat peer_format2 = peer_format; for (i = 0; i < G_N_ELEMENTS (try_formats); ++i) {
gchar *format_name = NULL; const gchar *format_name = NULL;
gboolean got_total = FALSE; GstFormat format;
if ((gst_pad_query (gst_pad_get_peer (progressreport->sinkpad), format = try_formats[i];
GST_QUERY_TOTAL, &peer_format2, &total_progress)) &&
(peer_format == peer_format2))
got_total = TRUE;
switch (peer_format) { if (gst_pad_query_position (peer_pad, &format, &cur_progress,
&total_progress)) {
switch (format) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
format_name = "bytes"; format_name = "bytes";
break; break;
case GST_FORMAT_TIME:
format_name = "seconds";
cur_progress /= GST_SECOND;
total_progress /= GST_SECOND;
break;
case GST_FORMAT_BUFFERS: case GST_FORMAT_BUFFERS:
format_name = "buffers"; format_name = "buffers";
break; break;
case GST_FORMAT_PERCENT: case GST_FORMAT_PERCENT:
format_name = "percent"; format_name = "percent";
break; break;
default: case GST_FORMAT_TIME:
format_name = "unknown"; format_name = "seconds";
cur_progress /= GST_SECOND;
total_progress /= GST_SECOND;
break;
case GST_FORMAT_DEFAULT:
{
GstCaps *caps;
format_name = "bogounits";
caps = GST_PAD_CAPS (GST_BASE_TRANSFORM (filter)->sinkpad);
if (caps && gst_caps_is_fixed (caps) && !gst_caps_is_any (caps)) {
GstStructure *s = gst_caps_get_structure (caps, 0);
const gchar *mime_type = gst_structure_get_name (s);
if (g_str_has_prefix (mime_type, "video/")
|| g_str_has_prefix (mime_type, "image/")) {
format_name = "frames";
} else if (g_str_has_prefix (mime_type, "audio/")) {
format_name = "samples";
}
}
break; break;
} }
default:
{
const GstFormatDefinition *details;
if (got_total == TRUE) { details = gst_format_get_details (format);
g_print ("%s (%2d:%2d:%2d): %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT if (details) {
" %s (%3.2g %%)\n", format_name = details->nick;
gst_object_get_name (GST_OBJECT (progressreport)), hh, mm, ss,
cur_progress, total_progress, format_name,
((gdouble) (cur_progress)) / total_progress * 100);
} else { } else {
g_print ("%s (%2d:%2d:%2d): %" G_GINT64_FORMAT " %s\n", format_name = "unknown";
gst_object_get_name (GST_OBJECT (progressreport)), hh, mm, ss,
cur_progress, format_name);
} }
break;
}
}
if (!filter->silent) {
if (total_progress > 0) {
g_print ("%s (%02d:%02d:%02d): %" G_GINT64_FORMAT " / %"
G_GINT64_FORMAT " %s (%4.1f %%)\n", GST_OBJECT_NAME (filter), hh,
mm, ss, cur_progress, total_progress, format_name,
(gdouble) cur_progress / total_progress * 100.0);
} else { } else {
g_print ("%s (%02d:%02d:%02d): %" G_GINT64_FORMAT " %s\n",
GST_OBJECT_NAME (filter), hh, mm, ss, cur_progress, format_name);
}
}
break;
}
}
if (i == G_N_ELEMENTS (try_formats)) {
g_print ("%s (%2d:%2d:%2d): Could not query current position.\n", g_print ("%s (%2d:%2d:%2d): Could not query current position.\n",
gst_object_get_name (GST_OBJECT (progressreport)), hh, mm, ss); GST_OBJECT_NAME (filter), hh, mm, ss);
} }
GST_UNLOCK (filter);
gst_object_unref (peer_pad);
}
static gboolean
gst_progress_report_event (GstBaseTransform * trans, GstEvent * event)
{
GstProgressReport *filter;
filter = GST_PROGRESS_REPORT (trans);
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
GTimeVal cur_time;
g_get_current_time (&cur_time);
gst_progress_report_report (filter, cur_time);
}
return TRUE;
}
static GstFlowReturn
gst_progress_report_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{
GstProgressReport *filter;
gboolean need_update;
GTimeVal cur_time;
g_get_current_time (&cur_time);
filter = GST_PROGRESS_REPORT (trans);
/* Check if update_freq seconds have passed since the last update */
GST_LOCK (filter);
need_update =
((cur_time.tv_sec - filter->last_report.tv_sec) >= filter->update_freq);
GST_UNLOCK (filter);
if (need_update) {
gst_progress_report_report (filter, cur_time);
GST_LOCK (filter);
filter->last_report = cur_time;
GST_UNLOCK (filter);
}
return GST_FLOW_OK;
}
static gboolean
gst_progress_report_start (GstBaseTransform * trans)
{
GstProgressReport *filter;
filter = GST_PROGRESS_REPORT (trans);
g_get_current_time (&filter->last_report);
filter->start_time = filter->last_report;
return TRUE;
}
static gboolean
gst_progress_report_stop (GstBaseTransform * trans)
{
/* anything we should be doing here? */
return TRUE;
} }
static void static void
gst_progressreport_set_property (GObject * object, guint prop_id, gst_progress_report_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
{ {
GstProgressReport *src; GstProgressReport *filter;
g_return_if_fail (GST_IS_PROGRESSREPORT (object)); filter = GST_PROGRESS_REPORT (object);
src = GST_PROGRESSREPORT (object);
switch (prop_id) { switch (prop_id) {
case ARG_UPDATE_FREQ: case ARG_UPDATE_FREQ:
src->update_freq = g_value_get_int (value); GST_LOCK (filter);
filter->update_freq = g_value_get_int (value);
GST_UNLOCK (filter);
break;
case ARG_SILENT:
GST_LOCK (filter);
filter->silent = g_value_get_boolean (value);
GST_UNLOCK (filter);
break; break;
default: default:
break; break;
@ -236,17 +345,23 @@ gst_progressreport_set_property (GObject * object, guint prop_id,
} }
static void static void
gst_progressreport_get_property (GObject * object, guint prop_id, gst_progress_report_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec) GValue * value, GParamSpec * pspec)
{ {
GstProgressReport *src; GstProgressReport *filter;
g_return_if_fail (GST_IS_PROGRESSREPORT (object)); filter = GST_PROGRESS_REPORT (object);
src = GST_PROGRESSREPORT (object);
switch (prop_id) { switch (prop_id) {
case ARG_UPDATE_FREQ: case ARG_UPDATE_FREQ:
g_value_set_int (value, src->update_freq); GST_LOCK (filter);
g_value_set_int (value, filter->update_freq);
GST_UNLOCK (filter);
break;
case ARG_SILENT:
GST_LOCK (filter);
g_value_set_boolean (value, filter->silent);
GST_UNLOCK (filter);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -254,29 +369,10 @@ gst_progressreport_get_property (GObject * object, guint prop_id,
} }
} }
static void
gst_progressreport_chain (GstPad * pad, GstData * _data)
{
GstProgressReport *progressreport;
GTimeVal cur_time;
g_get_current_time (&cur_time);
progressreport = GST_PROGRESSREPORT (gst_pad_get_parent (pad));
/* Check if update_freq seconds have passed since the last update */
if ((cur_time.tv_sec - progressreport->last_report.tv_sec) >=
progressreport->update_freq) {
gst_progressreport_report (progressreport, cur_time);
progressreport->last_report = cur_time;
}
gst_pad_push (progressreport->srcpad, _data);
}
gboolean gboolean
gst_progressreport_plugin_init (GstPlugin * plugin, GstPluginClass * g_class) gst_progress_report_plugin_init (GstPlugin * plugin, GstPluginClass * g_class)
{ {
return gst_element_register (plugin, "progressreport", GST_RANK_NONE, return gst_element_register (plugin, "progressreport", GST_RANK_NONE,
GST_TYPE_PROGRESSREPORT); GST_TYPE_PROGRESS_REPORT);
} }

View file

@ -22,6 +22,7 @@
#endif #endif
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasesink.h>
#include "tests.h" #include "tests.h"
GST_DEBUG_CATEGORY_STATIC (gst_test_debug); GST_DEBUG_CATEGORY_STATIC (gst_test_debug);
@ -48,9 +49,7 @@ typedef struct _GstTestClass GstTestClass;
struct _GstTest struct _GstTest
{ {
GstElement element; GstBaseSink basesink;
GstPad *sinkpad;
gpointer tests[TESTS_COUNT]; gpointer tests[TESTS_COUNT];
GValue values[TESTS_COUNT]; GValue values[TESTS_COUNT];
@ -58,50 +57,71 @@ struct _GstTest
struct _GstTestClass struct _GstTestClass
{ {
GstElementClass parent_class; GstBaseSinkClass parent_class;
gchar *param_names[2 * TESTS_COUNT]; gchar *param_names[2 * TESTS_COUNT];
}; };
GST_BOILERPLATE (GstTest, gst_test, GstElement, GST_TYPE_ELEMENT) static gboolean gst_test_start (GstBaseSink * trans);
static gboolean gst_test_stop (GstBaseSink * trans);
static gboolean gst_test_sink_event (GstBaseSink * basesink, GstEvent * event);
static GstFlowReturn gst_test_render_buffer (GstBaseSink * basesink,
GstBuffer * buf);
static void gst_test_set_property (GObject * object, static void gst_test_set_property (GObject * object, guint prop_id,
guint prop_id, const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
static void gst_test_get_property (GObject * object, static void gst_test_get_property (GObject * object, guint prop_id,
guint prop_id, GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static void gst_test_chain (GstPad * pad, GstData * _data);
static void gst_test_base_init (gpointer g_class)
{
static GstElementDetails details = GST_ELEMENT_DETAILS ("gsttestsink", static GstElementDetails details = GST_ELEMENT_DETAILS ("gsttestsink",
"Testing", "Testing",
"perform a number of tests", "perform a number of tests",
"Benjamin Otte <otte@gnome>"); "Benjamin Otte <otte@gnome>");
GST_BOILERPLATE (GstTest, gst_test, GstBaseSink, GST_TYPE_BASE_SINK)
static void gst_test_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sinktemplate));
gst_element_class_set_details (gstelement_class, &details); gst_element_class_set_details (gstelement_class, &details);
} }
static void static void
gst_test_class_init (GstTestClass * klass) gst_test_class_init (GstTestClass * klass)
{ {
GObjectClass *object = G_OBJECT_CLASS (klass); GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
guint i; guint i;
object->set_property = GST_DEBUG_FUNCPTR (gst_test_set_property); object_class->set_property = GST_DEBUG_FUNCPTR (gst_test_set_property);
object->get_property = GST_DEBUG_FUNCPTR (gst_test_get_property); object_class->get_property = GST_DEBUG_FUNCPTR (gst_test_get_property);
for (i = 0; i < TESTS_COUNT; i++) { for (i = 0; i < TESTS_COUNT; i++) {
GParamSpec *spec; GParamSpec *spec;
spec = tests[i].get_spec (&tests[i], FALSE); spec = tests[i].get_spec (&tests[i], FALSE);
klass->param_names[2 * i] = g_strdup (g_param_spec_get_name (spec)); klass->param_names[2 * i] = g_strdup (g_param_spec_get_name (spec));
g_object_class_install_property (object, 2 * i + 1, spec); g_object_class_install_property (object_class, 2 * i + 1, spec);
spec = tests[i].get_spec (&tests[i], TRUE); spec = tests[i].get_spec (&tests[i], TRUE);
klass->param_names[2 * i + 1] = g_strdup (g_param_spec_get_name (spec)); klass->param_names[2 * i + 1] = g_strdup (g_param_spec_get_name (spec));
g_object_class_install_property (object, 2 * i + 2, spec); g_object_class_install_property (object_class, 2 * i + 2, spec);
} }
basesink_class->preroll = GST_DEBUG_FUNCPTR (gst_test_render_buffer);
basesink_class->render = GST_DEBUG_FUNCPTR (gst_test_render_buffer);
basesink_class->event = GST_DEBUG_FUNCPTR (gst_test_sink_event);
basesink_class->start = GST_DEBUG_FUNCPTR (gst_test_start);
basesink_class->stop = GST_DEBUG_FUNCPTR (gst_test_stop);
} }
static void static void
@ -110,13 +130,6 @@ gst_test_init (GstTest * test, GstTestClass * g_class)
GstTestClass *klass; GstTestClass *klass;
guint i; guint i;
GST_FLAG_SET (test, GST_ELEMENT_EVENT_AWARE);
test->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
gst_element_add_pad (GST_ELEMENT (test), test->sinkpad);
gst_pad_set_chain_function (test->sinkpad,
GST_DEBUG_FUNCPTR (gst_test_chain));
klass = GST_TEST_GET_CLASS (test); klass = GST_TEST_GET_CLASS (test);
for (i = 0; i < TESTS_COUNT; i++) { for (i = 0; i < TESTS_COUNT; i++) {
GParamSpec *spec = g_object_class_find_property (G_OBJECT_CLASS (klass), GParamSpec *spec = g_object_class_find_property (G_OBJECT_CLASS (klass),
@ -150,24 +163,25 @@ tests_set (GstTest * test)
} }
} }
static void static gboolean
gst_test_chain (GstPad * pad, GstData * data) gst_test_sink_event (GstBaseSink * basesink, GstEvent * event)
{ {
guint i; GstTestClass *klass = GST_TEST_GET_CLASS (basesink);
GstTest *test = GST_TEST (gst_pad_get_parent (pad)); GstTest *test = GST_TEST (basesink);
GstTestClass *klass = GST_TEST_GET_CLASS (test); gboolean ret = FALSE;
if (GST_IS_EVENT (data)) {
GstEvent *event = GST_EVENT (data);
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS: /*
case GST_EVENT_NEWSEGMENT:
if (GST_EVENT_DISCONT_NEW_MEDIA (event)) { if (GST_EVENT_DISCONT_NEW_MEDIA (event)) {
tests_unset (test); tests_unset (test);
tests_set (test); tests_set (test);
} }
break; break;
case GST_EVENT_EOS: */
case GST_EVENT_EOS:{
gint i;
g_object_freeze_notify (G_OBJECT (test)); g_object_freeze_notify (G_OBJECT (test));
for (i = 0; i < TESTS_COUNT; i++) { for (i = 0; i < TESTS_COUNT; i++) {
if (test->tests[i]) { if (test->tests[i]) {
@ -191,20 +205,46 @@ gst_test_chain (GstPad * pad, GstData * data)
} }
} }
g_object_thaw_notify (G_OBJECT (test)); g_object_thaw_notify (G_OBJECT (test));
ret = TRUE;
break; break;
}
default: default:
break; break;
} }
gst_pad_event_default (pad, event);
return; return ret;
} }
static GstFlowReturn
gst_test_render_buffer (GstBaseSink * basesink, GstBuffer * buf)
{
GstTest *test = GST_TEST (basesink);
guint i;
for (i = 0; i < TESTS_COUNT; i++) { for (i = 0; i < TESTS_COUNT; i++) {
if (test->tests[i]) { if (test->tests[i]) {
tests[i].add (test->tests[i], GST_BUFFER (data)); tests[i].add (test->tests[i], buf);
} }
} }
gst_data_unref (data); return GST_FLOW_OK;
}
static gboolean
gst_test_start (GstBaseSink * sink)
{
GstTest *test = GST_TEST (sink);
tests_set (test);
return TRUE;
}
static gboolean
gst_test_stop (GstBaseSink * sink)
{
GstTest *test = GST_TEST (sink);
tests_unset (test);
return TRUE;
} }
static void static void
@ -223,7 +263,9 @@ gst_test_set_property (GObject * object, guint prop_id,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else { } else {
/* expected values */ /* expected values */
GST_LOCK (test);
g_value_copy (value, &test->values[prop_id / 2 - 1]); g_value_copy (value, &test->values[prop_id / 2 - 1]);
GST_UNLOCK (test);
} }
} }
@ -239,6 +281,8 @@ gst_test_get_property (GObject * object, guint prop_id, GValue * value,
return; return;
} }
GST_LOCK (test);
if (prop_id % 2) { if (prop_id % 2) {
/* real values */ /* real values */
tests[id].get_value (test->tests[id], value); tests[id].get_value (test->tests[id], value);
@ -246,6 +290,8 @@ gst_test_get_property (GObject * object, guint prop_id, GValue * value,
/* expected values */ /* expected values */
g_value_copy (&test->values[id], value); g_value_copy (&test->values[id], value);
} }
GST_UNLOCK (test);
} }
gboolean gboolean