2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David Schleef <ds@schleef.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
25 /*#define DEBUG_ENABLED */
26 #include <gstvideofilter.h>
30 /* GstVideofilter signals and args */
42 static void gst_videofilter_base_init (gpointer g_class);
43 static void gst_videofilter_class_init (gpointer g_class, gpointer class_data);
44 static void gst_videofilter_init (GTypeInstance *instance, gpointer g_class);
46 static void gst_videofilter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
47 static void gst_videofilter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
49 static void gst_videofilter_chain (GstPad *pad, GstData *_data);
50 GstCaps * gst_videofilter_class_get_capslist(GstVideofilterClass *klass);
51 static void gst_videofilter_setup(GstVideofilter *videofilter);
53 static GstElementClass *parent_class = NULL;
56 gst_videofilter_get_type (void)
58 static GType videofilter_type = 0;
60 if (!videofilter_type) {
61 static const GTypeInfo videofilter_info = {
62 sizeof(GstVideofilterClass),
63 gst_videofilter_base_init,
65 gst_videofilter_class_init,
68 sizeof(GstVideofilter),
72 videofilter_type = g_type_register_static(GST_TYPE_ELEMENT,
73 "GstVideofilter", &videofilter_info, G_TYPE_FLAG_ABSTRACT);
75 return videofilter_type;
78 static void gst_videofilter_base_init (gpointer g_class)
80 static GstElementDetails videofilter_details = {
82 "Filter/Effect/Video",
84 "David Schleef <ds@schleef.org>"
86 GstVideofilterClass *klass = (GstVideofilterClass *) g_class;
87 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
89 klass->formats = g_ptr_array_new();
91 gst_element_class_set_details (element_class, &videofilter_details);
94 static void gst_videofilter_class_init (gpointer g_class, gpointer class_data)
96 GObjectClass *gobject_class;
97 GstElementClass *gstelement_class;
98 GstVideofilterClass *klass;
100 klass = (GstVideofilterClass *)g_class;
101 gobject_class = (GObjectClass*)klass;
102 gstelement_class = (GstElementClass*)klass;
104 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
106 gobject_class->set_property = gst_videofilter_set_property;
107 gobject_class->get_property = gst_videofilter_get_property;
110 static GstCaps *gst_videofilter_format_get_caps(GstVideofilterFormat *format)
115 if(format->filter_func==NULL)
118 fourcc = GST_MAKE_FOURCC(format->fourcc[0],format->fourcc[1],format->fourcc[2],format->fourcc[3]);
121 caps = GST_CAPS_NEW ("videofilter", "video/x-raw-rgb",
122 "format", GST_PROPS_FOURCC (fourcc),
123 "depth", GST_PROPS_INT(format->bpp),
124 "bpp", GST_PROPS_INT(format->depth),
125 "endianness", GST_PROPS_INT(format->endianness),
126 "red_mask", GST_PROPS_INT(format->red_mask),
127 "green_mask", GST_PROPS_INT(format->green_mask),
128 "blue_mask", GST_PROPS_INT(format->blue_mask));
130 caps = GST_CAPS_NEW ("videoflip", "video/x-raw-yuv",
131 "format", GST_PROPS_FOURCC (fourcc),
132 "height", GST_PROPS_INT_RANGE (1,G_MAXINT),
133 "width", GST_PROPS_INT_RANGE (1,G_MAXINT),
134 "framerate", GST_PROPS_FLOAT_RANGE (0,G_MAXFLOAT)
141 GstCaps * gst_videofilter_class_get_capslist(GstVideofilterClass *klass)
143 static GstCaps *capslist = NULL;
148 gst_caps_ref(capslist);
152 for(i=0;i<klass->formats->len;i++){
153 caps = gst_videofilter_format_get_caps(g_ptr_array_index(klass->formats,i));
154 capslist = gst_caps_append(capslist, caps);
157 gst_caps_ref(capslist);
162 gst_videofilter_sink_getcaps (GstPad *pad, GstCaps *caps)
164 GstVideofilter *videofilter;
165 GstVideofilterClass *klass;
166 GstCaps *capslist = NULL;
171 GST_DEBUG("gst_videofilter_sink_getcaps");
172 videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
174 klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
176 /* get list of peer's caps */
177 peercaps = gst_pad_get_allowed_caps (videofilter->srcpad);
179 /* FIXME videofilter doesn't allow passthru of video formats it
180 * doesn't understand. */
181 /* Look through our list of caps and find those that match with
182 * the peer's formats. Create a list of them. */
183 /* FIXME optimize if peercaps == NULL */
184 for(i=0;i<klass->formats->len;i++){
186 GstCaps *fromcaps = gst_videofilter_format_get_caps(g_ptr_array_index(
189 icaps = gst_caps_intersect(fromcaps, peercaps);
190 //if(gst_caps_is_always_compatible(fromcaps, peercaps)){
192 capslist = gst_caps_append(capslist, fromcaps);
194 //gst_caps_unref (fromcaps);
195 if(icaps) gst_caps_unref (icaps);
197 gst_caps_unref (peercaps);
199 sizecaps = GST_CAPS_NEW("videofilter_size","video/x-raw-yuv",
200 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
201 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
202 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
204 caps = gst_caps_intersect(capslist, sizecaps);
205 gst_caps_unref (sizecaps);
210 static GstPadLinkReturn
211 gst_videofilter_src_link (GstPad *pad, GstCaps *caps)
213 GstVideofilter *videofilter;
214 GstPadLinkReturn ret;
217 GST_DEBUG("gst_videofilter_src_link");
218 videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
220 if (!GST_CAPS_IS_FIXED (caps)) {
221 return GST_PAD_LINK_DELAYED;
224 gst_caps_debug(caps,"ack");
226 videofilter->format = gst_videofilter_find_format_by_caps (videofilter,caps);
227 g_return_val_if_fail(videofilter->format, GST_PAD_LINK_REFUSED);
229 gst_caps_get_int (caps, "width", &videofilter->to_width);
230 gst_caps_get_int (caps, "height", &videofilter->to_height);
232 GST_DEBUG("width %d height %d",videofilter->to_width,videofilter->to_height);
234 peercaps = gst_caps_copy(caps);
236 gst_caps_set(peercaps, "width", GST_PROPS_INT_RANGE (0, G_MAXINT));
237 gst_caps_set(peercaps, "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
239 ret = gst_pad_try_set_caps (videofilter->srcpad, peercaps);
241 gst_caps_unref(peercaps);
243 if(ret==GST_PAD_LINK_OK){
244 caps = gst_pad_get_caps (videofilter->srcpad);
246 gst_caps_get_int (caps, "width", &videofilter->from_width);
247 gst_caps_get_int (caps, "height", &videofilter->from_height);
248 //gst_videofilter_setup(videofilter);
254 static GstPadLinkReturn
255 gst_videofilter_sink_link (GstPad *pad, GstCaps *caps)
257 GstVideofilter *videofilter;
258 GstPadLinkReturn ret;
261 GST_DEBUG("gst_videofilter_sink_link");
262 videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
264 if (!GST_CAPS_IS_FIXED (caps)) {
265 return GST_PAD_LINK_DELAYED;
268 videofilter->format = gst_videofilter_find_format_by_caps (videofilter,caps);
269 GST_DEBUG("sink_link: %s\n",gst_caps_to_string(caps));
270 g_return_val_if_fail(videofilter->format, GST_PAD_LINK_REFUSED);
272 gst_caps_get_int (caps, "width", &videofilter->from_width);
273 gst_caps_get_int (caps, "height", &videofilter->from_height);
274 gst_caps_get_float (caps, "framerate", &videofilter->framerate);
276 gst_videofilter_setup(videofilter);
278 peercaps = gst_caps_copy(caps);
280 gst_caps_set(peercaps, "width", GST_PROPS_INT (videofilter->to_width));
281 gst_caps_set(peercaps, "height", GST_PROPS_INT (videofilter->to_height));
282 gst_caps_set(peercaps, "framerate", GST_PROPS_FLOAT (videofilter->framerate));
284 GST_DEBUG("setting %s\n",gst_caps_to_string(peercaps));
286 ret = gst_pad_try_set_caps (videofilter->srcpad, peercaps);
288 //gst_caps_unref(peercaps);
290 if(ret==GST_PAD_LINK_OK || ret==GST_PAD_LINK_DONE){
291 caps = gst_pad_get_caps (videofilter->srcpad);
293 //gst_caps_get_int (caps, "width", &videofilter->to_width);
294 //gst_caps_get_int (caps, "height", &videofilter->to_height);
295 //gst_videofilter_setup(videofilter);
302 gst_videofilter_init (GTypeInstance *instance, gpointer g_class)
304 GstVideofilter *videofilter = GST_VIDEOFILTER (instance);
305 GstPadTemplate *pad_template;
307 GST_DEBUG("gst_videofilter_init");
309 pad_template = gst_element_class_get_pad_template(GST_ELEMENT_CLASS(g_class),
311 g_return_if_fail(pad_template != NULL);
312 videofilter->sinkpad = gst_pad_new_from_template(pad_template, "sink");
313 gst_element_add_pad(GST_ELEMENT(videofilter),videofilter->sinkpad);
314 gst_pad_set_chain_function(videofilter->sinkpad,gst_videofilter_chain);
315 gst_pad_set_link_function(videofilter->sinkpad,gst_videofilter_sink_link);
316 gst_pad_set_getcaps_function(videofilter->sinkpad,gst_videofilter_sink_getcaps);
318 pad_template = gst_element_class_get_pad_template(GST_ELEMENT_CLASS(g_class),
320 g_return_if_fail(pad_template != NULL);
321 videofilter->srcpad = gst_pad_new_from_template(pad_template, "src");
322 gst_element_add_pad(GST_ELEMENT(videofilter),videofilter->srcpad);
323 gst_pad_set_link_function(videofilter->srcpad,gst_videofilter_src_link);
324 //gst_pad_set_getcaps_function(videofilter->srcpad,gst_videofilter_src_getcaps);
326 videofilter->inited = FALSE;
330 gst_videofilter_chain (GstPad *pad, GstData *_data)
332 GstBuffer *buf = GST_BUFFER (_data);
333 GstVideofilter *videofilter;
338 GST_DEBUG ("gst_videofilter_chain");
340 g_return_if_fail (pad != NULL);
341 g_return_if_fail (GST_IS_PAD (pad));
342 g_return_if_fail (buf != NULL);
344 videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
345 //g_return_if_fail (videofilter->inited);
347 data = GST_BUFFER_DATA(buf);
348 size = GST_BUFFER_SIZE(buf);
350 if(videofilter->passthru){
351 gst_pad_push(videofilter->srcpad, GST_DATA (buf));
355 GST_DEBUG ("gst_videofilter_chain: got buffer of %ld bytes in '%s'",size,
356 GST_OBJECT_NAME (videofilter));
358 GST_DEBUG("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
360 videofilter->from_width, videofilter->from_height,
361 videofilter->to_width, videofilter->to_height,
362 size, videofilter->from_buf_size,
363 videofilter->to_buf_size);
365 g_return_if_fail (size == videofilter->from_buf_size);
367 outbuf = gst_buffer_new();
368 /* FIXME: handle bufferpools */
369 GST_BUFFER_SIZE(outbuf) = videofilter->to_buf_size;
370 GST_BUFFER_DATA(outbuf) = g_malloc (videofilter->to_buf_size);
371 GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
373 g_return_if_fail(videofilter->format);
374 GST_DEBUG ("format %s",videofilter->format->fourcc);
376 videofilter->in_buf = buf;
377 videofilter->out_buf = outbuf;
379 videofilter->format->filter_func(videofilter, GST_BUFFER_DATA(outbuf), data);
381 GST_DEBUG ("gst_videofilter_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf),
382 GST_OBJECT_NAME (videofilter));
384 gst_pad_push(videofilter->srcpad, GST_DATA (outbuf));
386 gst_buffer_unref(buf);
390 gst_videofilter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
394 /* it's not null if we got it, but it might not be ours */
395 g_return_if_fail(GST_IS_VIDEOFILTER(object));
396 src = GST_VIDEOFILTER(object);
398 GST_DEBUG("gst_videofilter_set_property");
406 gst_videofilter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
410 /* it's not null if we got it, but it might not be ours */
411 g_return_if_fail(GST_IS_VIDEOFILTER(object));
412 src = GST_VIDEOFILTER(object);
416 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
421 int gst_videofilter_get_input_width(GstVideofilter *videofilter)
423 g_return_val_if_fail(GST_IS_VIDEOFILTER(videofilter),0);
425 return videofilter->from_width;
428 int gst_videofilter_get_input_height(GstVideofilter *videofilter)
430 g_return_val_if_fail(GST_IS_VIDEOFILTER(videofilter),0);
432 return videofilter->from_height;
435 void gst_videofilter_set_output_size(GstVideofilter *videofilter,
436 int width, int height)
441 g_return_if_fail(GST_IS_VIDEOFILTER(videofilter));
443 videofilter->to_width = width;
444 videofilter->to_height = height;
446 videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height
447 * videofilter->format->depth)/8;
449 srccaps = gst_caps_copy(gst_pad_get_caps(videofilter->srcpad));
451 if(!GST_CAPS_IS_FIXED(srccaps)){
455 gst_caps_set(srccaps, "width", GST_PROPS_INT (videofilter->to_width));
456 gst_caps_set(srccaps, "height", GST_PROPS_INT (videofilter->to_height));
458 ret = gst_pad_try_set_caps (videofilter->srcpad, srccaps);
460 g_return_if_fail(ret<0);
463 static void gst_videofilter_setup(GstVideofilter *videofilter)
465 GstVideofilterClass *klass;
467 klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
470 klass->setup(videofilter);
473 if(videofilter->to_width == 0){
474 videofilter->to_width = videofilter->from_width;
476 if(videofilter->to_height == 0){
477 videofilter->to_height = videofilter->from_height;
480 g_return_if_fail(videofilter->format != NULL);
481 g_return_if_fail(videofilter->from_width > 0);
482 g_return_if_fail(videofilter->from_height > 0);
483 g_return_if_fail(videofilter->to_width > 0);
484 g_return_if_fail(videofilter->to_height > 0);
486 videofilter->from_buf_size = (videofilter->from_width * videofilter->from_height *
487 videofilter->format->depth) / 8;
488 videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height *
489 videofilter->format->depth) / 8;
491 videofilter->inited = TRUE;
494 GstVideofilterFormat *gst_videofilter_find_format_by_caps(GstVideofilter *videofilter,
499 GstVideofilterClass *klass;
500 GstVideofilterFormat *format;
502 klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
504 g_return_val_if_fail(caps != NULL, NULL);
506 for(i=0;i<klass->formats->len;i++){
507 format = g_ptr_array_index(klass->formats,i);
508 c = gst_videofilter_format_get_caps(format);
511 if(gst_caps_is_always_compatible(caps, c)){
522 void gst_videofilter_class_add_format(GstVideofilterClass *videofilterclass,
523 GstVideofilterFormat *format)
525 g_ptr_array_add(videofilterclass->formats, format);
528 void gst_videofilter_class_add_pad_templates (GstVideofilterClass *videofilter_class)
531 GstElementClass *element_class = GST_ELEMENT_CLASS (videofilter_class);
533 caps = GST_CAPS_NEW("src","video/x-raw-yuv",
534 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
535 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
536 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
538 gst_element_class_add_pad_template (element_class,
539 GST_PAD_TEMPLATE_NEW("src", GST_PAD_SRC, GST_PAD_ALWAYS,
540 gst_caps_intersect(caps,
541 gst_videofilter_class_get_capslist (videofilter_class))));
543 gst_element_class_add_pad_template (element_class,
544 GST_PAD_TEMPLATE_NEW("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
545 gst_caps_intersect(caps,
546 gst_videofilter_class_get_capslist (videofilter_class))));
550 plugin_init (GstPlugin *plugin)
559 "Video filter parent class",