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>
* 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
@ -7,18 +7,20 @@ libgstefence_la_CFLAGS = $(GST_CFLAGS)
libgstefence_la_LIBADD = $(GST_LIBS)
libgstefence_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
# libgstnavigationtest_la_SOURCES = gstnavigationtest.c
# libgstnavigationtest_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/gst/videofilter
# libgstnavigationtest_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
#
# libgstdebug_la_SOURCES = \
# gstdebug.c \
# breakmydata.c \
# negotiation.c \
# gstnavseek.c \
# progressreport.c \
# tests.c \
# testplugin.c
#
# libgstdebug_la_CFLAGS = $(GST_CFLAGS)
# libgstdebug_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstnavigationtest_la_SOURCES = gstnavigationtest.c
libgstnavigationtest_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/gst/videofilter
libgstnavigationtest_la_LIBADD = $(GST_LIBS) $(top_builddir)/gst/videofilter/libgstvideofilter-@GST_MAJORMINOR@.la
libgstnavigationtest_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstdebug_la_SOURCES = \
gstdebug.c \
breakmydata.c \
progressreport.c \
gstnavseek.c \
tests.c \
testplugin.c
# negotiation.c
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
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
GST_DEBUG_CATEGORY_STATIC (gst_break_my_data_debug);
#define GST_CAT_DEFAULT gst_break_my_data_debug
@ -56,10 +57,7 @@ typedef struct _GstBreakMyDataClass GstBreakMyDataClass;
struct _GstBreakMyData
{
GstElement element;
GstPad *sinkpad;
GstPad *srcpad;
GstBaseTransform basetransform;
GRand *rand;
guint skipped;
@ -72,113 +70,91 @@ struct _GstBreakMyData
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);
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);
static void gst_break_my_data_chain (GstPad * pad, GstData * _data);
static GstStateChangeReturn gst_break_my_data_change_state (GstElement *
element);
static GstFlowReturn gst_break_my_data_transform_ip (GstBaseTransform * trans,
GstBuffer * buf);
static gboolean gst_break_my_data_stop (GstBaseTransform * trans);
static gboolean gst_break_my_data_start (GstBaseTransform * trans);
static GstElementDetails details = GST_ELEMENT_DETAILS ("breakmydata",
"Testing",
"randomly change data in the stream",
"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)
{
static GstElementDetails details = GST_ELEMENT_DETAILS ("breakmydata",
"Testing",
"randomly change data in the stream",
"Benjamin Otte <otte@gnome>");
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);
}
static void
gst_break_my_data_class_init (GstBreakMyDataClass * klass)
{
GObjectClass *object = G_OBJECT_CLASS (klass);
GstElementClass *element = GST_ELEMENT_CLASS (klass);
GstBaseTransformClass *gstbasetrans_class;
GObjectClass *gobject_class;
object->set_property = GST_DEBUG_FUNCPTR (gst_break_my_data_set_property);
object->get_property = GST_DEBUG_FUNCPTR (gst_break_my_data_get_property);
gobject_class = G_OBJECT_CLASS (klass);
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",
"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));
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",
"set changed bytes to this value (-1 means random value",
-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",
"amount of bytes skipped at the beginning of stream",
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",
"probability that a buffer is changed", 0.0, 1.0, 0.0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
"probability for each byte in the buffer to be changed", 0.0, 1.0,
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
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_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));
gst_base_transform_set_in_place (GST_BASE_TRANSFORM (bmd), TRUE);
}
static void
@ -187,6 +163,8 @@ gst_break_my_data_set_property (GObject * object, guint prop_id,
{
GstBreakMyData *bmd = GST_BREAK_MY_DATA (object);
GST_LOCK (bmd);
switch (prop_id) {
case ARG_SEED:
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);
break;
}
GST_UNLOCK (bmd);
}
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);
GST_LOCK (bmd);
switch (prop_id) {
case ARG_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);
break;
}
GST_UNLOCK (bmd);
}
static GstStateChangeReturn
gst_break_my_data_change_state (GstElement * element, GstStateChange transition)
static GstFlowReturn
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) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
bmd->rand = g_rand_new_with_seed (bmd->seed);
bmd->skipped = 0;
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
g_rand_free (bmd->rand);
break;
default:
break;
g_return_val_if_fail (gst_buffer_is_writable (buf), GST_FLOW_ERROR);
GST_LOCK (bmd);
if (bmd->skipped < bmd->skip) {
i = bmd->skip - bmd->skipped;
} else {
i = 0;
}
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
(element), GST_STATE_CHANGE_SUCCESS);
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->skipped = 0;
GST_UNLOCK (bmd);
return TRUE;
}
static gboolean
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

View file

@ -23,20 +23,20 @@
#include <gst/gst.h>
gboolean gst_break_my_data_plugin_init (GstPlugin * plugin);
gboolean gst_negotiation_plugin_init (GstPlugin * plugin);
gboolean gst_progress_report_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_break_my_data_plugin_init (GstPlugin * plugin);
/* gboolean gst_negotiation_plugin_init (GstPlugin * plugin); */
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_break_my_data_plugin_init (plugin) ||
!gst_negotiation_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))
return FALSE;

View file

@ -27,24 +27,10 @@
#include "config.h"
#endif
/*#define DEBUG_ENABLED */
#include <gstnavigationtest.h>
#include <string.h>
#include <math.h>
/* GstNavigationtest signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0
/* FILL ME */
};
typedef struct
{
double x;
@ -61,10 +47,6 @@ static void gst_navigationtest_init (GTypeInstance * instance,
static gboolean gst_navigationtest_handle_src_event (GstPad * pad,
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
gst_navigationtest_change_state (GstElement * element,
@ -74,7 +56,7 @@ static void gst_navigationtest_planar411 (GstVideofilter * videofilter,
void *dest, void *src);
static void gst_navigationtest_setup (GstVideofilter * videofilter);
static GstVideofilterClass *parent_class = NULL;
static GstVideofilterClass *parent_class; /* NULL */
GType
gst_navigationtest_get_type (void)
@ -130,15 +112,11 @@ gst_navigationtest_base_init (gpointer g_class)
static void
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);
GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (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;
videofilter_class->setup = gst_navigationtest_setup;
@ -147,67 +125,58 @@ gst_navigationtest_class_init (gpointer g_class, gpointer class_data)
static void
gst_navigationtest_init (GTypeInstance * instance, gpointer g_class)
{
GstNavigationtest *navigationtest = GST_NAVIGATIONTEST (instance);
GstVideofilter *videofilter;
GST_DEBUG ("gst_navigationtest_init");
videofilter = GST_VIDEOFILTER (navigationtest);
GstNavigationtest *navtest = GST_NAVIGATIONTEST (instance);
GstVideofilter *videofilter = GST_VIDEOFILTER (navtest);
gst_pad_set_event_function (videofilter->srcpad,
gst_navigationtest_handle_src_event);
GST_DEBUG_FUNCPTR (gst_navigationtest_handle_src_event));
navigationtest->x = -1;
navigationtest->y = -1;
navtest->x = -1;
navtest->y = -1;
}
static gboolean
gst_navigationtest_handle_src_event (GstPad * pad, GstEvent * event)
{
GstNavigationtest *navigationtest;
GstNavigationtest *navtest;
const gchar *type;
navigationtest = GST_NAVIGATIONTEST (gst_pad_get_parent (pad));
navtest = GST_NAVIGATIONTEST (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
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")) {
gst_structure_get_double (event->event_data.structure.structure,
"pointer_x", &navigationtest->x);
gst_structure_get_double (event->event_data.structure.structure,
"pointer_y", &navigationtest->y);
gst_structure_get_double (s, "pointer_x", &navtest->x);
gst_structure_get_double (s, "pointer_y", &navtest->y);
} else if (g_str_equal (type, "mouse-button-press")) {
ButtonClick *click = g_new (ButtonClick, 1);
gst_structure_get_double (event->event_data.structure.structure,
"pointer_x", &click->x);
gst_structure_get_double (event->event_data.structure.structure,
"pointer_y", &click->y);
click->images_left = ceil (GST_VIDEOFILTER (navigationtest)->framerate);
gst_structure_get_double (s, "pointer_x", &click->x);
gst_structure_get_double (s, "pointer_y", &click->y);
click->images_left = ceil (GST_VIDEOFILTER (navtest)->framerate);
/* green */
click->cy = 150;
click->cu = 46;
click->cv = 21;
navigationtest->clicks =
g_slist_prepend (navigationtest->clicks, click);
navtest->clicks = g_slist_prepend (navtest->clicks, click);
} else if (g_str_equal (type, "mouse-button-release")) {
ButtonClick *click = g_new (ButtonClick, 1);
gst_structure_get_double (event->event_data.structure.structure,
"pointer_x", &click->x);
gst_structure_get_double (event->event_data.structure.structure,
"pointer_y", &click->y);
click->images_left = ceil (GST_VIDEOFILTER (navigationtest)->framerate);
gst_structure_get_double (s, "pointer_x", &click->x);
gst_structure_get_double (s, "pointer_y", &click->y);
click->images_left = ceil (GST_VIDEOFILTER (navtest)->framerate);
/* red */
click->cy = 76;
click->cu = 85;
click->cv = 255;
navigationtest->clicks =
g_slist_prepend (navigationtest->clicks, click);
navtest->clicks = g_slist_prepend (navtest->clicks, click);
}
break;
}
default:
break;
}
@ -215,64 +184,7 @@ gst_navigationtest_handle_src_event (GstPad * pad, GstEvent * event)
}
static void
gst_navigationtest_set_property (GObject * object, guint prop_id,
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)
gst_navigationtest_setup (GstVideofilter * videofilter)
{
GstNavigationtest *navigationtest;
@ -328,19 +240,20 @@ static void
gst_navigationtest_planar411 (GstVideofilter * videofilter,
void *dest, void *src)
{
GstNavigationtest *navigationtest;
int width = gst_videofilter_get_input_width (videofilter);
int height = gst_videofilter_get_input_height (videofilter);
GstNavigationtest *navtest = (GstNavigationtest *) videofilter;
gint width, height;
GSList *walk;
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
* to the destination. */
memcpy (dest, src, width * height + (width / 2) * (height / 2) * 2);
walk = navigationtest->clicks;
walk = navtest->clicks;
while (walk) {
ButtonClick *click = walk->data;
@ -348,32 +261,55 @@ gst_navigationtest_planar411 (GstVideofilter * videofilter,
draw_box_planar411 (dest, width, height, rint (click->x),
rint (click->y), click->cy, click->cu, click->cv);
if (--click->images_left < 1) {
navigationtest->clicks = g_slist_remove (navigationtest->clicks, click);
navtest->clicks = g_slist_remove (navtest->clicks, click);
g_free (click);
}
}
draw_box_planar411 (dest, width, height, rint (navigationtest->x),
rint (navigationtest->y), 0, 128, 128);
draw_box_planar411 (dest, width, height, rint (navtest->x),
rint (navtest->y), 0, 128, 128);
}
static GstStateChangeReturn
gst_navigationtest_change_state (GstElement * element,
GstStateChange transition)
{
GstNavigationtest *navigation = GST_NAVIGATIONTEST (element);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstNavigationtest *navtest = GST_NAVIGATIONTEST (element);
/* upwards state changes */
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
while (navigation->clicks) {
g_free (navigation->clicks->data);
navigation->clicks =
g_slist_remove (navigation->clicks, navigation->clicks->data);
}
default:
break;
}
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"
#endif
#include <gstnavseek.h>
#include "gstnavseek.h"
#include <string.h>
#include <math.h>
/* GstNavSeek signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_SEEKOFFSET
/* FILL ME */
};
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_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 GstElementDetails navseek_details =
GST_ELEMENT_DETAILS ("Seek based on left-right arrows",
"Filter/Video",
"Seek based on navigation keys left-right",
"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);
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;
}
GST_BOILERPLATE (GstNavSeek, gst_navseek, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM);
static void
gst_navseek_base_init (gpointer g_class)
{
static GstElementDetails navseek_details =
GST_ELEMENT_DETAILS ("Seek based on left-right arrows",
"Filter/Video",
"Seek based on navigation keys left-right",
"Jan Schmidt <thaytan@mad.scientist.com>");
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
@ -109,43 +82,36 @@ gst_navseek_base_init (gpointer g_class)
}
static void
gst_navseek_class_init (gpointer g_class, gpointer class_data)
gst_navseek_class_init (GstNavSeekClass * klass)
{
GstBaseTransformClass *gstbasetrans_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",
"Time in seconds to seek by", 0.0, G_MAXDOUBLE, 5.0,
G_PARAM_READWRITE));
gobject_class->set_property = gst_navseek_set_property;
gobject_class->get_property = gst_navseek_get_property;
gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_navseek_event);
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
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_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);
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (navseek), TRUE);
navseek->seek_offset = 5.0;
navseek->loop = FALSE;
@ -158,74 +124,90 @@ gst_navseek_init (GTypeInstance * instance, gpointer g_class)
static void
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;
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)) {
if (peer_format != GST_FORMAT_TIME)
return;
/* Query for the current time then attempt to set to time + offset */
peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
ret = gst_pad_query_position (peer_pad, &peer_format, &peer_value, NULL);
if (ret && peer_format == GST_FORMAT_TIME) {
GstEvent *event;
peer_value += offset;
if (peer_value < 0)
peer_value = 0;
gst_element_seek (GST_ELEMENT (navseek),
GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_ACCURATE |
GST_SEEK_FLAG_FLUSH, peer_value);
event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH,
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
gst_navseek_segseek (GstNavSeek * navseek)
{
GstEvent *event;
GstPad *peer_pad;
if ((navseek->segment_start == 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;
}
if (navseek->loop) {
event =
gst_event_new_segment_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME |
GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT_LOOP,
navseek->segment_start, navseek->segment_end);
gst_event_new_seek (1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT,
GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
navseek->segment_end);
} else {
event =
gst_event_new_segment_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME |
GST_SEEK_FLAG_ACCURATE, navseek->segment_start, navseek->segment_end);
gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE,
GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
navseek->segment_end);
}
g_return_if_fail (event != NULL);
gst_pad_send_event (gst_pad_get_peer (navseek->sinkpad), event);
peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
gst_pad_send_event (peer_pad, event);
gst_object_unref (peer_pad);
}
static gboolean
gst_navseek_handle_src_event (GstPad * pad, GstEvent * event)
{
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)) {
case GST_EVENT_NAVIGATION:
/* Check for a keyup and convert left/right to a seek event */
{
GstStructure *structure;
const GstStructure *structure;
const gchar *event_type;
structure = event->event_data.structure.structure;
event_type = gst_structure_get_string (structure, "event");
structure = gst_event_get_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) {
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) {
/* Seek backward by 5 secs */
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:
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
gst_navseek_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstNavSeek *src;
g_return_if_fail (GST_IS_NAVSEEK (object));
src = GST_NAVSEEK (object);
GstNavSeek *navseek = GST_NAVSEEK (object);
switch (prop_id) {
case ARG_SEEKOFFSET:
src->seek_offset = g_value_get_double (value);
break;
default:
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);
GST_LOCK (navseek);
navseek->seek_offset = g_value_get_double (value);
GST_UNLOCK (navseek);
break;
default:
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
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) &&
GST_BUFFER_TIMESTAMP_IS_VALID (GST_BUFFER (_data))) {
static gboolean
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) {
navseek->segment_start = GST_BUFFER_TIMESTAMP (GST_BUFFER (_data));
navseek->segment_start = GST_BUFFER_TIMESTAMP (buf);
navseek->segment_end = GST_CLOCK_TIME_NONE;
navseek->grab_seg_start = FALSE;
}
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;
gst_navseek_segseek (navseek);
}
}
if (GST_IS_EVENT (_data) &&
(GST_EVENT_TYPE (GST_EVENT (_data)) == GST_EVENT_SEGMENT_DONE) &&
navseek->loop) {
gst_navseek_segseek (navseek);
}
GST_UNLOCK (navseek);
gst_pad_push (navseek->srcpad, _data);
return GST_FLOW_OK;
}
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

View file

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

View file

@ -24,211 +24,320 @@
#endif
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define GST_TYPE_PROGRESSREPORT \
(gst_progressreport_get_type())
#define GST_PROGRESSREPORT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PROGRESSREPORT,GstProgressReport))
#define GST_PROGRESSREPORT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PROGRESSREPORT,GstProgressReportClass))
#define GST_IS_PROGRESSREPORT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PROGRESSREPORT))
#define GST_IS_PROGRESSREPORT_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PROGRESSREPORT))
#define GST_TYPE_PROGRESS_REPORT \
(gst_progress_report_get_type())
#define GST_PROGRESS_REPORT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PROGRESS_REPORT,GstProgressReport))
#define GST_PROGRESS_REPORT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PROGRESS_REPORT,GstProgressReportClass))
#define GST_IS_PROGRESS_REPORT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PROGRESS_REPORT))
#define GST_IS_PROGRESS_REPORT_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PROGRESS_REPORT))
typedef struct _GstProgressReport GstProgressReport;
typedef struct _GstProgressReportClass GstProgressReportClass;
struct _GstProgressReport
{
GstElement element;
GstPad *sinkpad;
GstPad *srcpad;
GstBaseTransform basetransform;
gint update_freq;
gboolean silent;
GTimeVal start_time;
GTimeVal last_report;
};
struct _GstProgressReportClass
{
GstElementClass parent_class;
};
/* GstProgressReport signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
GstBaseTransformClass parent_class;
};
enum
{
ARG_0,
ARG_UPDATE_FREQ
/* FILL ME */
ARG_UPDATE_FREQ,
ARG_SILENT
};
GstStaticPadTemplate progressreport_src_template =
GstStaticPadTemplate progress_report_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GstStaticPadTemplate progressreport_sink_template =
GstStaticPadTemplate progress_report_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static void gst_progressreport_set_property (GObject * object, guint prop_id,
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);
static GstElementDetails progress_report_details =
GST_ELEMENT_DETAILS ("Progress Report",
"Testing",
"Periodically query and report on processing progress",
"Jan Schmidt <thaytan@mad.scientist.com>");
GST_BOILERPLATE (GstProgressReport, gst_progressreport, GstElement,
GST_TYPE_ELEMENT);
#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_progressreport_base_init (gpointer g_class)
gst_progress_report_base_init (gpointer g_class)
{
static GstElementDetails progressreport_details =
GST_ELEMENT_DETAILS ("Progress Report",
"Testing",
"Periodically query and report on processing progress",
"Jan Schmidt <thaytan@mad.scientist.com>");
GstElementClass *element_class = GST_ELEMENT_CLASS (g_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_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
gst_progressreport_class_init (GstProgressReportClass * g_class)
gst_progress_report_class_init (GstProgressReportClass * g_class)
{
GstBaseTransformClass *gstbasetrans_class;
GObjectClass *gobject_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),
ARG_UPDATE_FREQ, g_param_spec_int ("update-freq", "Update Frequency",
"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;
gobject_class->get_property = gst_progressreport_get_property;
g_object_class_install_property (G_OBJECT_CLASS (g_class),
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
gst_progressreport_init (GstProgressReport * instance,
gst_progress_report_init (GstProgressReport * report,
GstProgressReportClass * g_class)
{
GstProgressReport *progressreport = GST_PROGRESSREPORT (instance);
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (report), TRUE);
progressreport->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&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;
report->update_freq = DEFAULT_UPDATE_FREQ;
report->silent = DEFAULT_SILENT;
}
static void
gst_progressreport_report (GstProgressReport * progressreport,
GTimeVal cur_time)
gst_progress_report_report (GstProgressReport * filter, 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 total_progress;
GstFormat peer_format = GST_FORMAT_DEFAULT;
gint hh, mm, ss;
glong run_time = cur_time.tv_sec - progressreport->start_time.tv_sec;
gint hh, mm, ss, i;
glong run_time;
GST_LOCK (filter);
run_time = cur_time.tv_sec - filter->start_time.tv_sec;
hh = (run_time / 3600) % 100;
mm = (run_time / 60) % 60;
ss = (run_time % 60);
if (gst_pad_query (gst_pad_get_peer (progressreport->sinkpad),
GST_QUERY_POSITION, &peer_format, &cur_progress)) {
GstFormat peer_format2 = peer_format;
gchar *format_name = NULL;
gboolean got_total = FALSE;
peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (filter)->sinkpad);
/* Query for the current time then attempt to set to time + offset */
for (i = 0; i < G_N_ELEMENTS (try_formats); ++i) {
const gchar *format_name = NULL;
GstFormat format;
if ((gst_pad_query (gst_pad_get_peer (progressreport->sinkpad),
GST_QUERY_TOTAL, &peer_format2, &total_progress)) &&
(peer_format == peer_format2))
got_total = TRUE;
format = try_formats[i];
switch (peer_format) {
case GST_FORMAT_BYTES:
format_name = "bytes";
break;
case GST_FORMAT_TIME:
format_name = "seconds";
cur_progress /= GST_SECOND;
total_progress /= GST_SECOND;
break;
case GST_FORMAT_BUFFERS:
format_name = "buffers";
break;
case GST_FORMAT_PERCENT:
format_name = "percent";
break;
default:
format_name = "unknown";
break;
if (gst_pad_query_position (peer_pad, &format, &cur_progress,
&total_progress)) {
switch (format) {
case GST_FORMAT_BYTES:
format_name = "bytes";
break;
case GST_FORMAT_BUFFERS:
format_name = "buffers";
break;
case GST_FORMAT_PERCENT:
format_name = "percent";
break;
case GST_FORMAT_TIME:
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;
}
default:
{
const GstFormatDefinition *details;
details = gst_format_get_details (format);
if (details) {
format_name = details->nick;
} else {
format_name = "unknown";
}
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 {
g_print ("%s (%02d:%02d:%02d): %" G_GINT64_FORMAT " %s\n",
GST_OBJECT_NAME (filter), hh, mm, ss, cur_progress, format_name);
}
}
break;
}
if (got_total == TRUE) {
g_print ("%s (%2d:%2d:%2d): %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT
" %s (%3.2g %%)\n",
gst_object_get_name (GST_OBJECT (progressreport)), hh, mm, ss,
cur_progress, total_progress, format_name,
((gdouble) (cur_progress)) / total_progress * 100);
} else {
g_print ("%s (%2d:%2d:%2d): %" G_GINT64_FORMAT " %s\n",
gst_object_get_name (GST_OBJECT (progressreport)), hh, mm, ss,
cur_progress, format_name);
}
} else {
g_print ("%s (%2d:%2d:%2d): Could not query current position.\n",
gst_object_get_name (GST_OBJECT (progressreport)), hh, mm, ss);
}
if (i == G_N_ELEMENTS (try_formats)) {
g_print ("%s (%2d:%2d:%2d): Could not query current position.\n",
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
gst_progressreport_set_property (GObject * object, guint prop_id,
gst_progress_report_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstProgressReport *src;
GstProgressReport *filter;
g_return_if_fail (GST_IS_PROGRESSREPORT (object));
src = GST_PROGRESSREPORT (object);
filter = GST_PROGRESS_REPORT (object);
switch (prop_id) {
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;
default:
break;
@ -236,17 +345,23 @@ gst_progressreport_set_property (GObject * object, guint prop_id,
}
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)
{
GstProgressReport *src;
GstProgressReport *filter;
g_return_if_fail (GST_IS_PROGRESSREPORT (object));
src = GST_PROGRESSREPORT (object);
filter = GST_PROGRESS_REPORT (object);
switch (prop_id) {
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;
default:
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
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,
GST_TYPE_PROGRESSREPORT);
GST_TYPE_PROGRESS_REPORT);
}

View file

@ -22,6 +22,7 @@
#endif
#include <gst/gst.h>
#include <gst/base/gstbasesink.h>
#include "tests.h"
GST_DEBUG_CATEGORY_STATIC (gst_test_debug);
@ -48,9 +49,7 @@ typedef struct _GstTestClass GstTestClass;
struct _GstTest
{
GstElement element;
GstPad *sinkpad;
GstBaseSink basesink;
gpointer tests[TESTS_COUNT];
GValue values[TESTS_COUNT];
@ -58,50 +57,71 @@ struct _GstTest
struct _GstTestClass
{
GstElementClass parent_class;
GstBaseSinkClass parent_class;
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,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_test_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_test_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_test_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_test_chain (GstPad * pad, GstData * _data);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstElementDetails details = GST_ELEMENT_DETAILS ("gsttestsink",
"Testing",
"perform a number of tests",
"Benjamin Otte <otte@gnome>");
GST_BOILERPLATE (GstTest, gst_test, GstBaseSink, GST_TYPE_BASE_SINK)
static void gst_test_base_init (gpointer g_class)
{
static GstElementDetails details = GST_ELEMENT_DETAILS ("gsttestsink",
"Testing",
"perform a number of tests",
"Benjamin Otte <otte@gnome>");
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);
}
static void
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;
object->set_property = GST_DEBUG_FUNCPTR (gst_test_set_property);
object->get_property = GST_DEBUG_FUNCPTR (gst_test_get_property);
object_class->set_property = GST_DEBUG_FUNCPTR (gst_test_set_property);
object_class->get_property = GST_DEBUG_FUNCPTR (gst_test_get_property);
for (i = 0; i < TESTS_COUNT; i++) {
GParamSpec *spec;
spec = tests[i].get_spec (&tests[i], FALSE);
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);
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
@ -110,13 +130,6 @@ gst_test_init (GstTest * test, GstTestClass * g_class)
GstTestClass *klass;
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);
for (i = 0; i < TESTS_COUNT; i++) {
GParamSpec *spec = g_object_class_find_property (G_OBJECT_CLASS (klass),
@ -150,61 +163,88 @@ tests_set (GstTest * test)
}
}
static void
gst_test_chain (GstPad * pad, GstData * data)
static gboolean
gst_test_sink_event (GstBaseSink * basesink, GstEvent * event)
{
guint i;
GstTest *test = GST_TEST (gst_pad_get_parent (pad));
GstTestClass *klass = GST_TEST_GET_CLASS (test);
GstTestClass *klass = GST_TEST_GET_CLASS (basesink);
GstTest *test = GST_TEST (basesink);
gboolean ret = FALSE;
if (GST_IS_EVENT (data)) {
GstEvent *event = GST_EVENT (data);
switch (GST_EVENT_TYPE (event)) {
/*
case GST_EVENT_NEWSEGMENT:
if (GST_EVENT_DISCONT_NEW_MEDIA (event)) {
tests_unset (test);
tests_set (test);
}
break;
*/
case GST_EVENT_EOS:{
gint i;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
if (GST_EVENT_DISCONT_NEW_MEDIA (event)) {
tests_unset (test);
tests_set (test);
}
break;
case GST_EVENT_EOS:
g_object_freeze_notify (G_OBJECT (test));
for (i = 0; i < TESTS_COUNT; i++) {
if (test->tests[i]) {
if (!tests[i].finish (test->tests[i], &test->values[i])) {
GValue v = { 0, };
gchar *real, *expected;
g_object_freeze_notify (G_OBJECT (test));
for (i = 0; i < TESTS_COUNT; i++) {
if (test->tests[i]) {
if (!tests[i].finish (test->tests[i], &test->values[i])) {
GValue v = { 0, };
gchar *real, *expected;
expected = gst_value_serialize (&test->values[i]);
g_value_init (&v, G_VALUE_TYPE (&test->values[i]));
g_object_get_property (G_OBJECT (test), klass->param_names[2 * i],
&v);
real = gst_value_serialize (&v);
g_value_unset (&v);
GST_ELEMENT_ERROR (test, STREAM, FORMAT, (NULL),
("test %s returned value \"%s\" and not expected value \"%s\"",
klass->param_names[2 * i], real, expected));
g_free (real);
g_free (expected);
}
g_object_notify (G_OBJECT (test), klass->param_names[2 * i]);
expected = gst_value_serialize (&test->values[i]);
g_value_init (&v, G_VALUE_TYPE (&test->values[i]));
g_object_get_property (G_OBJECT (test), klass->param_names[2 * i],
&v);
real = gst_value_serialize (&v);
g_value_unset (&v);
GST_ELEMENT_ERROR (test, STREAM, FORMAT, (NULL),
("test %s returned value \"%s\" and not expected value \"%s\"",
klass->param_names[2 * i], real, expected));
g_free (real);
g_free (expected);
}
g_object_notify (G_OBJECT (test), klass->param_names[2 * i]);
}
g_object_thaw_notify (G_OBJECT (test));
break;
default:
break;
}
g_object_thaw_notify (G_OBJECT (test));
ret = TRUE;
break;
}
gst_pad_event_default (pad, event);
return;
default:
break;
}
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++) {
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
@ -223,7 +263,9 @@ gst_test_set_property (GObject * object, guint prop_id,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
/* expected values */
GST_LOCK (test);
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;
}
GST_LOCK (test);
if (prop_id % 2) {
/* real values */
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 */
g_value_copy (&test->values[id], value);
}
GST_UNLOCK (test);
}
gboolean