1
/* gstchart.c: implementation of chart drawing element
2
* Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Library General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Library General Public License for more details.
14
* You should have received a copy of the GNU Library General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
25
#include <gst/video/video.h>
27
#define GST_TYPE_CHART (gst_chart_get_type())
28
#define GST_CHART(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CHART,GstChart))
29
#define GST_CHART_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CHART,GstChart))
30
#define GST_IS_CHART(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CHART))
31
#define GST_IS_CHART_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CHART))
33
typedef struct _GstChart GstChart;
34
typedef struct _GstChartClass GstChartClass;
41
GstPad *sinkpad, *srcpad;
43
/* the timestamp of the next frame */
53
gdouble framerate; /* desired frame rate */
54
gint samples_between_frames; /* number of samples between start of successive frames */
55
gint samples_since_last_frame; /* number of samples between start of successive frames */
60
GstElementClass parent_class;
63
GType gst_chart_get_type (void);
66
/* elementfactory information */
67
static const GstElementDetails gst_chart_details =
68
GST_ELEMENT_DETAILS ("Chart drawer",
70
"Takes frames of data and outputs video frames of a chart of data",
71
"Richard Boulton <richard@tartarus.org>");
73
/* signals and args */
86
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
89
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB_16)
92
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
95
GST_STATIC_CAPS ("audio/x-raw-int, "
96
"endianness = (int) BYTE_ORDER, "
97
"signed = (boolean) TRUE, "
100
"rate = (int) [ 8000, 96000 ], " "channels = (int) 1")
103
static void gst_chart_base_init (gpointer g_class);
104
static void gst_chart_class_init (GstChartClass * klass);
105
static void gst_chart_init (GstChart * chart);
107
static void gst_chart_set_property (GObject * object, guint prop_id,
108
const GValue * value, GParamSpec * pspec);
109
static void gst_chart_get_property (GObject * object, guint prop_id,
110
GValue * value, GParamSpec * pspec);
112
static void gst_chart_chain (GstPad * pad, GstData * _data);
114
static GstPadLinkReturn
115
gst_chart_sinkconnect (GstPad * pad, const GstCaps * caps);
116
static GstPadLinkReturn
117
gst_chart_srcconnect (GstPad * pad, const GstCaps * caps);
119
static GstElementClass *parent_class = NULL;
122
gst_chart_get_type (void)
124
static GType type = 0;
127
static const GTypeInfo info = {
128
sizeof (GstChartClass),
131
(GClassInitFunc) gst_chart_class_init,
136
(GInstanceInitFunc) gst_chart_init,
139
type = g_type_register_static (GST_TYPE_ELEMENT, "GstChart", &info, 0);
145
gst_chart_base_init (gpointer g_class)
147
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
149
gst_element_class_add_pad_template (element_class,
150
gst_static_pad_template_get (&src_factory));
151
gst_element_class_add_pad_template (element_class,
152
gst_static_pad_template_get (&sink_factory));
153
gst_element_class_set_details (element_class, &gst_chart_details);
157
gst_chart_class_init (GstChartClass * klass)
159
GObjectClass *gobject_class;
160
GstElementClass *gstelement_class;
162
gobject_class = (GObjectClass *) klass;
163
gstelement_class = (GstElementClass *) klass;
165
parent_class = g_type_class_peek_parent (klass);
167
gobject_class->set_property = gst_chart_set_property;
168
gobject_class->get_property = gst_chart_get_property;
172
gst_chart_init (GstChart * chart)
174
/* create the sink and src pads */
175
chart->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
176
chart->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
177
gst_element_add_pad (GST_ELEMENT (chart), chart->sinkpad);
178
gst_element_add_pad (GST_ELEMENT (chart), chart->srcpad);
180
gst_pad_set_chain_function (chart->sinkpad, gst_chart_chain);
181
gst_pad_set_link_function (chart->sinkpad, gst_chart_sinkconnect);
182
gst_pad_set_link_function (chart->srcpad, gst_chart_srcconnect);
184
chart->next_time = 0;
186
/* reset the initial video state */
192
chart->samplerate = -1;
193
chart->framerate = 25; /* desired frame rate */
194
chart->samples_between_frames = 0; /* number of samples between start of successive frames */
195
chart->samples_since_last_frame = 0;
198
static GstPadLinkReturn
199
gst_chart_sinkconnect (GstPad * pad, const GstCaps * caps)
202
GstStructure *structure;
204
chart = GST_CHART (gst_pad_get_parent (pad));
206
structure = gst_caps_get_structure (caps, 0);
208
gst_structure_get_int (structure, "rate", &chart->samplerate);
209
chart->samples_between_frames = chart->samplerate / chart->framerate;
211
GST_DEBUG ("CHART: new sink caps: rate %d", chart->samplerate);
212
/*gst_chart_sync_parms (chart); */
214
return GST_PAD_LINK_OK;
217
static GstPadLinkReturn
218
gst_chart_srcconnect (GstPad * pad, const GstCaps * caps)
221
GstStructure *structure;
223
chart = GST_CHART (gst_pad_get_parent (pad));
225
structure = gst_caps_get_structure (caps, 0);
227
if (!gst_structure_get_double (structure, "framerate", &chart->framerate) ||
228
!gst_structure_get_int (structure, "width", &chart->width) ||
229
!gst_structure_get_int (structure, "height", &chart->height))
230
return GST_PAD_LINK_REFUSED;
232
chart->samples_between_frames = chart->samplerate / chart->framerate;
233
GST_DEBUG ("CHART: new src caps: framerate %f, %dx%d",
234
chart->framerate, chart->width, chart->height);
236
return GST_PAD_LINK_OK;
240
draw_chart_16bpp (guchar * output, gint width, gint height,
241
gint16 * src_data, gint src_size)
248
("CHART: drawing frame to %p, width = %d, height = %d, src_data = %p, src_size = %d",
249
output, width, height, src_data, src_size);
251
for (colstart = (guint16 *) output, in = (gint16 *) src_data, i = 0;
252
i < width; colstart++, in++, i++) {
253
guint16 *pos = colstart;
256
h1 = (((gint) (*in)) * height / (1 << 16)) + height / 2;
260
if (h1 < height / 2) {
261
while (pos < colstart + h1 * width) {
265
while (pos < colstart + height / 2 * width) {
269
while (pos < colstart + height * width) {
274
while (pos < colstart + height / 2 * width) {
278
while (pos < colstart + h1 * width) {
282
while (pos < colstart + height * width) {
291
gst_chart_chain (GstPad * pad, GstData * _data)
293
GstBuffer *bufin = GST_BUFFER (_data);
301
g_return_if_fail (bufin != NULL);
302
g_return_if_fail (pad != NULL);
303
g_return_if_fail (GST_IS_PAD (pad));
304
g_return_if_fail (GST_IS_CHART (GST_OBJECT_PARENT (pad)));
305
chart = GST_CHART (GST_OBJECT_PARENT (pad));
306
g_return_if_fail (chart != NULL);
308
GST_DEBUG ("CHART: chainfunc called");
310
samples_in = GST_BUFFER_SIZE (bufin) / sizeof (gint16);
311
datain = (gint16 *) (GST_BUFFER_DATA (bufin));
312
GST_DEBUG ("input buffer has %d samples", samples_in);
313
if (chart->next_time <= GST_BUFFER_TIMESTAMP (bufin)) {
314
chart->next_time = GST_BUFFER_TIMESTAMP (bufin);
315
GST_DEBUG ("in: %" G_GINT64_FORMAT, GST_BUFFER_TIMESTAMP (bufin));
318
chart->samples_since_last_frame += samples_in;
319
if (chart->samples_between_frames <= chart->samples_since_last_frame) {
320
chart->samples_since_last_frame = 0;
322
/* get data to draw into buffer */
323
if (samples_in >= chart->width) {
324
/* make a new buffer for the output */
325
bufout = gst_buffer_new ();
326
sizeout = chart->bpp / 8 * chart->width * chart->height;
327
dataout = g_malloc (sizeout);
328
GST_BUFFER_SIZE (bufout) = sizeout;
329
GST_BUFFER_DATA (bufout) = dataout;
330
GST_DEBUG ("CHART: made new buffer: size %d, width %d, height %d",
331
sizeout, chart->width, chart->height);
333
/* take data and draw to new buffer */
334
/* FIXME: call different routines for different properties */
335
draw_chart_16bpp (dataout, chart->width, chart->height, (gint16 *) datain,
338
gst_buffer_unref (bufin);
341
GST_BUFFER_TIMESTAMP (bufout) = chart->next_time;
343
GST_DEBUG ("CHART: outputting buffer");
345
GST_BUFFER_FLAG_SET (bufout, GST_BUFFER_READONLY);
346
gst_pad_push (chart->srcpad, GST_DATA (bufout));
349
GST_DEBUG ("CHART: skipping buffer");
350
gst_buffer_unref (bufin);
353
GST_DEBUG ("CHART: exiting chainfunc");
357
gst_chart_set_property (GObject * object, guint prop_id, const GValue * value,
362
g_return_if_fail (GST_IS_CHART (object));
363
chart = GST_CHART (object);
372
gst_chart_get_property (GObject * object, guint prop_id, GValue * value,
377
g_return_if_fail (GST_IS_CHART (object));
378
chart = GST_CHART (object);
387
plugin_init (GstPlugin * plugin)
389
if (!gst_element_register (plugin, "chart", GST_RANK_NONE, GST_TYPE_CHART))
395
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
398
"Takes frames of data and outputs video frames of a chart of data",
399
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)