2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2004> Jan Schmidt <thaytan@mad.scientist.com>
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 #include <pixbufscale.h>
26 #include <gst/video/video.h>
27 #include <gdk-pixbuf/gdk-pixbuf.h>
29 /* debug variable definition */
30 GST_DEBUG_CATEGORY (pixbufscale_debug);
31 #define GST_CAT_DEFAULT pixbufscale_debug
33 /* elementfactory information */
34 static GstElementDetails pixbufscale_details =
35 GST_ELEMENT_DETAILS ("Gdk Pixbuf scaler",
36 "Filter/Effect/Video",
38 "Jan Schmidt <thaytan@mad.scientist.com>\nWim Taymans <wim.taymans@chello.be>");
40 /* GstPixbufScale signals and args */
54 static GstStaticPadTemplate gst_pixbufscale_src_template =
55 GST_STATIC_PAD_TEMPLATE ("src",
58 GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
61 static GstStaticPadTemplate gst_pixbufscale_sink_template =
62 GST_STATIC_PAD_TEMPLATE ("sink",
65 GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
68 #define GST_TYPE_PIXBUFSCALE_METHOD (gst_pixbufscale_method_get_type())
70 gst_pixbufscale_method_get_type (void)
72 static GType pixbufscale_method_type = 0;
73 static GEnumValue pixbufscale_methods[] = {
74 {GST_PIXBUFSCALE_NEAREST, "0", "Nearest Neighbour"},
75 {GST_PIXBUFSCALE_TILES, "1", "Tiles"},
76 {GST_PIXBUFSCALE_BILINEAR, "2", "Bilinear"},
77 {GST_PIXBUFSCALE_HYPER, "3", "Hyper"},
81 if (!pixbufscale_method_type) {
82 pixbufscale_method_type =
83 g_enum_register_static ("GstPixbufScaleMethod", pixbufscale_methods);
85 return pixbufscale_method_type;
88 static void gst_pixbufscale_base_init (gpointer g_class);
89 static void gst_pixbufscale_class_init (GstPixbufScaleClass * klass);
90 static void gst_pixbufscale_init (GstPixbufScale * pixbufscale);
91 static gboolean gst_pixbufscale_handle_src_event (GstPad * pad,
94 static void gst_pixbufscale_set_property (GObject * object, guint prop_id,
95 const GValue * value, GParamSpec * pspec);
96 static void gst_pixbufscale_get_property (GObject * object, guint prop_id,
97 GValue * value, GParamSpec * pspec);
99 static void gst_pixbufscale_chain (GstPad * pad, GstData * _data);
101 static GstElementClass *parent_class = NULL;
104 gst_pixbufscale_get_type (void)
106 static GType pixbufscale_type = 0;
108 if (!pixbufscale_type) {
109 static const GTypeInfo pixbufscale_info = {
110 sizeof (GstPixbufScaleClass),
111 gst_pixbufscale_base_init,
113 (GClassInitFunc) gst_pixbufscale_class_init,
116 sizeof (GstPixbufScale),
118 (GInstanceInitFunc) gst_pixbufscale_init,
122 g_type_register_static (GST_TYPE_ELEMENT, "GstPixbufScale",
123 &pixbufscale_info, 0);
125 return pixbufscale_type;
129 gst_pixbufscale_base_init (gpointer g_class)
131 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
133 gst_element_class_set_details (element_class, &pixbufscale_details);
135 gst_element_class_add_pad_template (element_class,
136 gst_static_pad_template_get (&gst_pixbufscale_src_template));
137 gst_element_class_add_pad_template (element_class,
138 gst_static_pad_template_get (&gst_pixbufscale_sink_template));
141 gst_pixbufscale_class_init (GstPixbufScaleClass * klass)
143 GObjectClass *gobject_class;
144 GstElementClass *gstelement_class;
146 gobject_class = (GObjectClass *) klass;
147 gstelement_class = (GstElementClass *) klass;
149 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD,
150 g_param_spec_enum ("method", "method", "method",
151 GST_TYPE_PIXBUFSCALE_METHOD, GST_PIXBUFSCALE_BILINEAR,
154 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
156 gobject_class->set_property = gst_pixbufscale_set_property;
157 gobject_class->get_property = gst_pixbufscale_get_property;
161 gst_pixbufscale_getcaps (GstPad * pad)
163 GstPixbufScale *pixbufscale;
169 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
171 otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad :
173 othercaps = gst_pad_get_allowed_caps (otherpad);
175 caps = gst_caps_copy (othercaps);
176 for (i = 0; i < gst_caps_get_size (caps); i++) {
177 GstStructure *structure = gst_caps_get_structure (caps, i);
179 gst_structure_set (structure,
180 "width", GST_TYPE_INT_RANGE, 16, G_MAXINT,
181 "height", GST_TYPE_INT_RANGE, 16, G_MAXINT, NULL);
184 GST_DEBUG ("getcaps are: %" GST_PTR_FORMAT, caps);
188 static GstPadLinkReturn
189 gst_pixbufscale_link (GstPad * pad, const GstCaps * caps)
191 GstPixbufScale *pixbufscale;
192 GstPadLinkReturn ret;
194 GstStructure *structure;
197 GST_DEBUG ("gst_pixbufscale_link %s\n", gst_caps_to_string (caps));
198 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
200 otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad :
203 structure = gst_caps_get_structure (caps, 0);
204 ret = gst_structure_get_int (structure, "width", &width);
205 ret &= gst_structure_get_int (structure, "height", &height);
207 ret = gst_pad_try_set_caps (otherpad, caps);
208 if (ret == GST_PAD_LINK_OK) {
209 /* cool, we can use passthru */
211 pixbufscale->to_width = width;
212 pixbufscale->to_height = height;
213 pixbufscale->from_width = width;
214 pixbufscale->from_height = height;
216 pixbufscale->from_buf_size = width * height * 3;
217 pixbufscale->to_buf_size = width * height * 3;
219 pixbufscale->inited = TRUE;
221 return GST_PAD_LINK_OK;
224 if (gst_pad_is_negotiated (otherpad)) {
225 GstCaps *newcaps = gst_caps_copy (caps);
227 if (pad == pixbufscale->srcpad) {
228 gst_caps_set_simple (newcaps,
229 "width", G_TYPE_INT, pixbufscale->from_width,
230 "height", G_TYPE_INT, pixbufscale->from_height, NULL);
232 gst_caps_set_simple (newcaps,
233 "width", G_TYPE_INT, pixbufscale->to_width,
234 "height", G_TYPE_INT, pixbufscale->to_height, NULL);
236 ret = gst_pad_try_set_caps (otherpad, newcaps);
237 if (GST_PAD_LINK_FAILED (ret)) {
238 return GST_PAD_LINK_REFUSED;
242 pixbufscale->passthru = FALSE;
244 if (pad == pixbufscale->srcpad) {
245 pixbufscale->to_width = width;
246 pixbufscale->to_height = height;
248 pixbufscale->from_width = width;
249 pixbufscale->from_height = height;
252 if (gst_pad_is_negotiated (otherpad)) {
253 pixbufscale->from_buf_size = pixbufscale->from_width *
254 pixbufscale->from_height * 3;
255 pixbufscale->to_buf_size = pixbufscale->to_width *
256 pixbufscale->to_height * 3;
257 pixbufscale->inited = TRUE;
260 return GST_PAD_LINK_OK;
264 gst_pixbufscale_init (GstPixbufScale * pixbufscale)
266 GST_DEBUG_OBJECT (pixbufscale, "_init");
267 pixbufscale->sinkpad =
268 gst_pad_new_from_template (gst_static_pad_template_get
269 (&gst_pixbufscale_sink_template), "sink");
270 gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->sinkpad);
271 gst_pad_set_chain_function (pixbufscale->sinkpad, gst_pixbufscale_chain);
272 gst_pad_set_link_function (pixbufscale->sinkpad, gst_pixbufscale_link);
273 gst_pad_set_getcaps_function (pixbufscale->sinkpad, gst_pixbufscale_getcaps);
275 pixbufscale->srcpad =
276 gst_pad_new_from_template (gst_static_pad_template_get
277 (&gst_pixbufscale_src_template), "src");
278 gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->srcpad);
279 gst_pad_set_event_function (pixbufscale->srcpad,
280 gst_pixbufscale_handle_src_event);
281 gst_pad_set_link_function (pixbufscale->srcpad, gst_pixbufscale_link);
282 gst_pad_set_getcaps_function (pixbufscale->srcpad, gst_pixbufscale_getcaps);
284 pixbufscale->inited = FALSE;
286 pixbufscale->method = GST_PIXBUFSCALE_TILES;
287 pixbufscale->gdk_method = GDK_INTERP_TILES;
291 gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event)
293 GstPixbufScale *pixbufscale;
295 GstStructure *structure;
298 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
300 switch (GST_EVENT_TYPE (event)) {
301 case GST_EVENT_NAVIGATION:
302 structure = gst_structure_copy (event->event_data.structure.structure);
303 if (gst_structure_get_double (event->event_data.structure.structure,
305 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
306 a * pixbufscale->from_width / pixbufscale->to_width, NULL);
308 if (gst_structure_get_double (event->event_data.structure.structure,
310 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
311 a * pixbufscale->from_height / pixbufscale->to_height, NULL);
313 gst_event_unref (event);
314 new_event = gst_event_new (GST_EVENT_NAVIGATION);
315 new_event->event_data.structure.structure = structure;
316 return gst_pad_event_default (pad, new_event);
319 return gst_pad_event_default (pad, event);
325 pixbufscale_scale (GstPixbufScale * scale, unsigned char *dest,
328 GdkPixbuf *src_pixbuf, *dest_pixbuf;
330 src_pixbuf = gdk_pixbuf_new_from_data
331 (src, GDK_COLORSPACE_RGB, FALSE,
332 8, scale->from_width, scale->from_height,
333 3 * scale->from_width, NULL, NULL);
334 dest_pixbuf = gdk_pixbuf_new_from_data
335 (dest, GDK_COLORSPACE_RGB, FALSE,
336 8, scale->to_width, scale->to_height, 3 * scale->to_width, NULL, NULL);
337 gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0, scale->to_width,
338 scale->to_height, 0, 0,
339 (double) scale->to_width / scale->from_width,
340 (double) scale->to_height / scale->from_height, scale->gdk_method);
342 dest_pixbuf = gdk_pixbuf_scale_simple
343 (src_pixbuf, scale->to_width, scale->to_height, scale->gdk_method);
345 g_object_unref (src_pixbuf);
346 g_object_unref (dest_pixbuf);
350 gst_pixbufscale_chain (GstPad * pad, GstData * _data)
352 GstBuffer *buf = GST_BUFFER (_data);
353 GstPixbufScale *pixbufscale;
358 g_return_if_fail (pad != NULL);
359 g_return_if_fail (GST_IS_PAD (pad));
360 g_return_if_fail (buf != NULL);
362 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
363 g_return_if_fail (pixbufscale->inited);
365 data = GST_BUFFER_DATA (buf);
366 size = GST_BUFFER_SIZE (buf);
368 if (pixbufscale->passthru) {
369 GST_LOG_OBJECT (pixbufscale, "passing through buffer of %ld bytes in '%s'",
370 size, GST_OBJECT_NAME (pixbufscale));
371 gst_pad_push (pixbufscale->srcpad, GST_DATA (buf));
375 GST_LOG_OBJECT (pixbufscale, "got buffer of %ld bytes in '%s'", size,
376 GST_OBJECT_NAME (pixbufscale));
377 GST_LOG_OBJECT (pixbufscale,
378 "size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
379 size, pixbufscale->from_width, pixbufscale->from_height,
380 pixbufscale->to_width, pixbufscale->to_height, size,
381 pixbufscale->from_buf_size, pixbufscale->to_buf_size);
383 g_return_if_fail (size == pixbufscale->from_buf_size);
385 outbuf = gst_pad_alloc_buffer (pixbufscale->srcpad,
386 GST_BUFFER_OFFSET_NONE, pixbufscale->to_buf_size);
388 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
390 pixbufscale_scale (pixbufscale, GST_BUFFER_DATA (outbuf), data);
392 GST_DEBUG_OBJECT (pixbufscale, "pushing buffer of %d bytes in '%s'",
393 GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (pixbufscale));
395 gst_pad_push (pixbufscale->srcpad, GST_DATA (outbuf));
397 gst_buffer_unref (buf);
401 gst_pixbufscale_set_property (GObject * object, guint prop_id,
402 const GValue * value, GParamSpec * pspec)
406 g_return_if_fail (GST_IS_PIXBUFSCALE (object));
407 src = GST_PIXBUFSCALE (object);
411 src->method = g_value_get_enum (value);
412 switch (src->method) {
413 case GST_PIXBUFSCALE_NEAREST:
414 src->gdk_method = GDK_INTERP_NEAREST;
416 case GST_PIXBUFSCALE_TILES:
417 src->gdk_method = GDK_INTERP_TILES;
419 case GST_PIXBUFSCALE_BILINEAR:
420 src->gdk_method = GDK_INTERP_BILINEAR;
422 case GST_PIXBUFSCALE_HYPER:
423 src->gdk_method = GDK_INTERP_HYPER;
433 gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value,
438 g_return_if_fail (GST_IS_PIXBUFSCALE (object));
439 src = GST_PIXBUFSCALE (object);
443 g_value_set_enum (value, src->method);
446 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
453 pixbufscale_init (GstPlugin * plugin)
455 if (!gst_element_register (plugin, "gdkpixbufscale", GST_RANK_NONE,
456 GST_TYPE_PIXBUFSCALE))
459 GST_DEBUG_CATEGORY_INIT (pixbufscale_debug, "gdkpixbufscale", 0,
460 "pixbufscale element");