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.
26 /*#define DEBUG_ENABLED */
27 #include <gstvideofilter.h>
31 /* GstVideofilter signals and args */
43 static void gst_videofilter_base_init (gpointer g_class);
44 static void gst_videofilter_class_init (gpointer g_class, gpointer class_data);
45 static void gst_videofilter_init (GTypeInstance *instance, gpointer g_class);
47 static void gst_videofilter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
48 static void gst_videofilter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
50 static void gst_videofilter_chain (GstPad *pad, GstData *_data);
51 GstCaps * gst_videofilter_class_get_capslist(GstVideofilterClass *klass);
52 static void gst_videofilter_setup(GstVideofilter *videofilter);
54 static GstElementClass *parent_class = NULL;
57 gst_videofilter_get_type (void)
59 static GType videofilter_type = 0;
61 if (!videofilter_type) {
62 static const GTypeInfo videofilter_info = {
63 sizeof(GstVideofilterClass),
64 gst_videofilter_base_init,
66 gst_videofilter_class_init,
69 sizeof(GstVideofilter),
73 videofilter_type = g_type_register_static(GST_TYPE_ELEMENT,
74 "GstVideofilter", &videofilter_info, G_TYPE_FLAG_ABSTRACT);
76 return videofilter_type;
79 static void gst_videofilter_base_init (gpointer g_class)
81 static GstElementDetails videofilter_details = {
83 "Filter/Effect/Video",
85 "David Schleef <ds@schleef.org>"
87 GstVideofilterClass *klass = (GstVideofilterClass *) g_class;
88 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
90 klass->formats = g_ptr_array_new();
92 gst_element_class_set_details (element_class, &videofilter_details);
95 static void gst_videofilter_class_init (gpointer g_class, gpointer class_data)
97 GObjectClass *gobject_class;
98 GstElementClass *gstelement_class;
99 GstVideofilterClass *klass;
101 klass = (GstVideofilterClass *)g_class;
102 gobject_class = (GObjectClass*)klass;
103 gstelement_class = (GstElementClass*)klass;
105 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
107 gobject_class->set_property = gst_videofilter_set_property;
108 gobject_class->get_property = gst_videofilter_get_property;
111 static GstStructure *gst_videofilter_format_get_structure(GstVideofilterFormat *format)
114 GstStructure *structure;
116 if(format->filter_func==NULL)
119 fourcc = GST_MAKE_FOURCC(format->fourcc[0],format->fourcc[1],format->fourcc[2],format->fourcc[3]);
122 structure = gst_structure_new ("video/x-raw-rgb",
123 "depth", G_TYPE_INT, format->depth,
124 "bpp", G_TYPE_INT, format->bpp,
125 "endianness", G_TYPE_INT, format->endianness,
126 "red_mask", G_TYPE_INT, format->red_mask,
127 "green_mask", G_TYPE_INT, format->green_mask,
128 "blue_mask", G_TYPE_INT, format->blue_mask, NULL);
130 structure = gst_structure_new ("video/x-raw-yuv",
131 "format", GST_TYPE_FOURCC, fourcc, NULL);
134 gst_structure_set(structure,
135 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
136 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
137 "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE,
143 GstCaps * gst_videofilter_class_get_capslist(GstVideofilterClass *klass)
146 GstStructure *structure;
149 caps = gst_caps_new_empty();
150 for(i=0;i<klass->formats->len;i++){
151 structure = gst_videofilter_format_get_structure(g_ptr_array_index(klass->formats,i));
152 gst_caps_append_structure (caps, structure);
159 gst_videofilter_getcaps (GstPad *pad)
161 GstVideofilter *videofilter;
162 GstVideofilterClass *klass;
168 GST_DEBUG("gst_videofilter_getcaps");
169 videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
171 klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
173 otherpad = (pad == videofilter->srcpad) ? videofilter->sinkpad :
176 othercaps = gst_pad_get_allowed_caps (otherpad);
180 /* FIXME videofilter doesn't allow passthru of video formats it
181 * doesn't understand. */
182 /* Look through our list of caps and find those that match with
183 * the peer's formats. Create a list of them. */
184 /* FIXME optimize if peercaps == NULL */
185 caps = gst_caps_new_empty ();
186 for(i=0;i<klass->formats->len;i++){
190 fromcaps = gst_caps_new_full (gst_videofilter_format_get_structure (
191 g_ptr_array_index (klass->formats,i)), NULL);
193 icaps = gst_caps_intersect (fromcaps, peercaps);
195 gst_caps_append (caps, fromcaps);
197 gst_caps_free (fromcaps);
199 if(icaps) gst_caps_free (icaps);
201 gst_caps_free (peercaps);
207 static GstPadLinkReturn
208 gst_videofilter_link (GstPad *pad, const GstCaps *caps)
210 GstVideofilter *videofilter;
211 GstStructure *structure;
215 GstPadLinkReturn lret;
218 GST_DEBUG("gst_videofilter_src_link");
219 videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
221 otherpad = (pad == videofilter->srcpad) ? videofilter->sinkpad :
224 structure = gst_caps_get_structure (caps, 0);
226 videofilter->format = gst_videofilter_find_format_by_structure (
227 videofilter, structure);
228 g_return_val_if_fail(videofilter->format, GST_PAD_LINK_REFUSED);
230 ret = gst_structure_get_int (structure, "width", &width);
231 ret &= gst_structure_get_int (structure, "height", &height);
232 ret &= gst_structure_get_double (structure, "framerate", &framerate);
234 if (!ret) return GST_PAD_LINK_REFUSED;
236 lret = gst_pad_try_set_caps (otherpad, caps);
237 if (GST_PAD_LINK_FAILED (lret)) return lret;
239 GST_DEBUG("width %d height %d",width,height);
242 if (pad == videofilter->srcpad) {
243 videofilter->to_width = width;
244 videofilter->to_height = height;
246 videofilter->from_width = width;
247 videofilter->from_height = height;
250 videofilter->to_width = width;
251 videofilter->to_height = height;
252 videofilter->from_width = width;
253 videofilter->from_height = height;
254 videofilter->framerate = framerate;
256 gst_videofilter_setup(videofilter);
258 return GST_PAD_LINK_OK;
262 gst_videofilter_init (GTypeInstance *instance, gpointer g_class)
264 GstVideofilter *videofilter = GST_VIDEOFILTER (instance);
265 GstPadTemplate *pad_template;
267 GST_DEBUG("gst_videofilter_init");
269 pad_template = gst_element_class_get_pad_template(GST_ELEMENT_CLASS(g_class),
271 g_return_if_fail(pad_template != NULL);
272 videofilter->sinkpad = gst_pad_new_from_template(pad_template, "sink");
273 gst_element_add_pad(GST_ELEMENT(videofilter),videofilter->sinkpad);
274 gst_pad_set_chain_function(videofilter->sinkpad,gst_videofilter_chain);
275 gst_pad_set_link_function(videofilter->sinkpad,gst_videofilter_link);
276 gst_pad_set_getcaps_function(videofilter->sinkpad,gst_videofilter_getcaps);
278 pad_template = gst_element_class_get_pad_template(GST_ELEMENT_CLASS(g_class),
280 g_return_if_fail(pad_template != NULL);
281 videofilter->srcpad = gst_pad_new_from_template(pad_template, "src");
282 gst_element_add_pad(GST_ELEMENT(videofilter),videofilter->srcpad);
283 gst_pad_set_link_function(videofilter->srcpad,gst_videofilter_link);
284 gst_pad_set_getcaps_function(videofilter->srcpad,gst_videofilter_getcaps);
286 videofilter->inited = FALSE;
290 gst_videofilter_chain (GstPad *pad, GstData *_data)
292 GstBuffer *buf = GST_BUFFER (_data);
293 GstVideofilter *videofilter;
298 GST_DEBUG ("gst_videofilter_chain");
300 g_return_if_fail (pad != NULL);
301 g_return_if_fail (GST_IS_PAD (pad));
302 g_return_if_fail (buf != NULL);
304 videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
305 //g_return_if_fail (videofilter->inited);
307 data = GST_BUFFER_DATA(buf);
308 size = GST_BUFFER_SIZE(buf);
310 if(videofilter->passthru){
311 gst_pad_push(videofilter->srcpad, GST_DATA (buf));
315 GST_DEBUG ("gst_videofilter_chain: got buffer of %ld bytes in '%s'",size,
316 GST_OBJECT_NAME (videofilter));
318 GST_DEBUG("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
320 videofilter->from_width, videofilter->from_height,
321 videofilter->to_width, videofilter->to_height,
322 size, videofilter->from_buf_size,
323 videofilter->to_buf_size);
325 g_return_if_fail (size >= videofilter->from_buf_size);
327 if (size > videofilter->from_buf_size) {
328 GST_INFO("buffer size %ld larger than expected (%d)",
329 size, videofilter->from_buf_size);
332 outbuf = gst_pad_alloc_buffer(videofilter->srcpad, GST_BUFFER_OFFSET_NONE,
333 videofilter->to_buf_size);
334 GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
335 GST_BUFFER_DURATION(outbuf) = GST_BUFFER_DURATION(buf);
337 g_return_if_fail(videofilter->format);
338 GST_DEBUG ("format %s",videofilter->format->fourcc);
340 videofilter->in_buf = buf;
341 videofilter->out_buf = outbuf;
343 videofilter->format->filter_func(videofilter, GST_BUFFER_DATA(outbuf), data);
345 GST_DEBUG ("gst_videofilter_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf),
346 GST_OBJECT_NAME (videofilter));
348 gst_pad_push(videofilter->srcpad, GST_DATA (outbuf));
350 gst_buffer_unref(buf);
354 gst_videofilter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
358 /* it's not null if we got it, but it might not be ours */
359 g_return_if_fail(GST_IS_VIDEOFILTER(object));
360 src = GST_VIDEOFILTER(object);
362 GST_DEBUG("gst_videofilter_set_property");
370 gst_videofilter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
374 /* it's not null if we got it, but it might not be ours */
375 g_return_if_fail(GST_IS_VIDEOFILTER(object));
376 src = GST_VIDEOFILTER(object);
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
385 int gst_videofilter_get_input_width(GstVideofilter *videofilter)
387 g_return_val_if_fail(GST_IS_VIDEOFILTER(videofilter),0);
389 return videofilter->from_width;
392 int gst_videofilter_get_input_height(GstVideofilter *videofilter)
394 g_return_val_if_fail(GST_IS_VIDEOFILTER(videofilter),0);
396 return videofilter->from_height;
399 void gst_videofilter_set_output_size(GstVideofilter *videofilter,
400 int width, int height)
404 GstStructure *structure;
406 g_return_if_fail(GST_IS_VIDEOFILTER(videofilter));
408 videofilter->to_width = width;
409 videofilter->to_height = height;
411 videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height
412 * videofilter->format->bpp)/8;
414 srccaps = gst_caps_copy (gst_pad_get_negotiated_caps(videofilter->srcpad));
415 structure = gst_caps_get_structure (srccaps, 0);
417 gst_structure_set (structure, "width", G_TYPE_INT, width,
418 "height", G_TYPE_INT, height, NULL);
420 ret = gst_pad_try_set_caps (videofilter->srcpad, srccaps);
423 g_critical ("could not set output size");
427 static void gst_videofilter_setup(GstVideofilter *videofilter)
429 GstVideofilterClass *klass;
431 klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
434 klass->setup(videofilter);
437 if(videofilter->to_width == 0){
438 videofilter->to_width = videofilter->from_width;
440 if(videofilter->to_height == 0){
441 videofilter->to_height = videofilter->from_height;
444 g_return_if_fail(videofilter->format != NULL);
445 g_return_if_fail(videofilter->from_width > 0);
446 g_return_if_fail(videofilter->from_height > 0);
447 g_return_if_fail(videofilter->to_width > 0);
448 g_return_if_fail(videofilter->to_height > 0);
450 videofilter->from_buf_size = (videofilter->from_width * videofilter->from_height *
451 videofilter->format->bpp) / 8;
452 videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height *
453 videofilter->format->bpp) / 8;
455 videofilter->inited = TRUE;
458 GstVideofilterFormat *gst_videofilter_find_format_by_structure (
459 GstVideofilter *videofilter, const GstStructure *structure)
462 GstVideofilterClass *klass;
463 GstVideofilterFormat *format;
466 klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
468 g_return_val_if_fail(structure != NULL, NULL);
470 if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) {
473 ret = gst_structure_get_fourcc (structure, "format", &fourcc);
474 if (!ret) return NULL;
475 for(i=0;i<klass->formats->len;i++){
476 guint32 format_fourcc;
477 format = g_ptr_array_index(klass->formats,i);
478 format_fourcc = GST_STR_FOURCC (format->fourcc);
479 if (format->depth == 0 && format_fourcc == fourcc) {
483 } else if (strcmp (gst_structure_get_name (structure), "video/x-raw-rgb")
492 ret = gst_structure_get_int (structure, "bpp", &bpp);
493 ret &= gst_structure_get_int (structure, "depth", &depth);
494 ret &= gst_structure_get_int (structure, "endianness", &endianness);
495 ret &= gst_structure_get_int (structure, "red_mask", &red_mask);
496 ret &= gst_structure_get_int (structure, "green_mask", &green_mask);
497 ret &= gst_structure_get_int (structure, "blue_mask", &blue_mask);
498 if (!ret) return NULL;
499 for(i=0;i<klass->formats->len;i++){
500 format = g_ptr_array_index(klass->formats,i);
501 if (format->bpp == bpp && format->depth == depth &&
502 format->endianness == endianness && format->red_mask == red_mask &&
503 format->green_mask == green_mask && format->blue_mask == blue_mask) {
512 void gst_videofilter_class_add_format(GstVideofilterClass *videofilterclass,
513 GstVideofilterFormat *format)
515 g_ptr_array_add(videofilterclass->formats, format);
518 void gst_videofilter_class_add_pad_templates (GstVideofilterClass *videofilter_class)
520 GstElementClass *element_class = GST_ELEMENT_CLASS (videofilter_class);
522 gst_element_class_add_pad_template (element_class,
523 gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS,
524 gst_videofilter_class_get_capslist (videofilter_class)));
526 gst_element_class_add_pad_template (element_class,
527 gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
528 gst_videofilter_class_get_capslist (videofilter_class)));
532 plugin_init (GstPlugin *plugin)
541 "Video filter parent class",