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_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
176 gst_caps_free (othercaps);
178 for (i = 0; i < gst_caps_get_size (caps); i++) {
179 GstStructure *structure = gst_caps_get_structure (caps, i);
181 gst_structure_set (structure,
182 "width", GST_TYPE_INT_RANGE, 16, 4096,
183 "height", GST_TYPE_INT_RANGE, 16, 4096, NULL);
184 gst_structure_remove_field (structure, "pixel-aspect-ratio");
187 GST_DEBUG ("getcaps are: %" GST_PTR_FORMAT, caps);
191 static GstPadLinkReturn
192 gst_pixbufscale_link (GstPad * pad, const GstCaps * caps)
194 GstPixbufScale *pixbufscale;
195 GstPadLinkReturn ret;
197 GstStructure *structure;
200 GST_DEBUG ("gst_pixbufscale_link %s\n", gst_caps_to_string (caps));
201 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
203 otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad :
206 structure = gst_caps_get_structure (caps, 0);
207 ret = gst_structure_get_int (structure, "width", &width);
208 ret &= gst_structure_get_int (structure, "height", &height);
210 ret = gst_pad_try_set_caps (otherpad, caps);
211 if (ret == GST_PAD_LINK_OK) {
212 /* cool, we can use passthru */
214 pixbufscale->to_width = width;
215 pixbufscale->to_height = height;
216 pixbufscale->from_width = width;
217 pixbufscale->from_height = height;
219 pixbufscale->from_buf_size = width * height * 3;
220 pixbufscale->to_buf_size = width * height * 3;
222 pixbufscale->inited = TRUE;
224 return GST_PAD_LINK_OK;
227 if (gst_pad_is_negotiated (otherpad)) {
228 GstCaps *newcaps = gst_caps_copy (caps);
230 if (pad == pixbufscale->srcpad) {
231 gst_caps_set_simple (newcaps,
232 "width", G_TYPE_INT, pixbufscale->from_width,
233 "height", G_TYPE_INT, pixbufscale->from_height, NULL);
235 gst_caps_set_simple (newcaps,
236 "width", G_TYPE_INT, pixbufscale->to_width,
237 "height", G_TYPE_INT, pixbufscale->to_height, NULL);
239 ret = gst_pad_try_set_caps (otherpad, newcaps);
240 if (GST_PAD_LINK_FAILED (ret)) {
241 return GST_PAD_LINK_REFUSED;
245 pixbufscale->passthru = FALSE;
247 if (pad == pixbufscale->srcpad) {
248 pixbufscale->to_width = width;
249 pixbufscale->to_height = height;
251 pixbufscale->from_width = width;
252 pixbufscale->from_height = height;
255 if (gst_pad_is_negotiated (otherpad)) {
256 pixbufscale->from_buf_size = pixbufscale->from_width *
257 pixbufscale->from_height * 3;
258 pixbufscale->to_buf_size = pixbufscale->to_width *
259 pixbufscale->to_height * 3;
260 pixbufscale->inited = TRUE;
263 return GST_PAD_LINK_OK;
267 gst_pixbufscale_init (GstPixbufScale * pixbufscale)
269 GST_DEBUG_OBJECT (pixbufscale, "_init");
270 pixbufscale->sinkpad =
271 gst_pad_new_from_template (gst_static_pad_template_get
272 (&gst_pixbufscale_sink_template), "sink");
273 gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->sinkpad);
274 gst_pad_set_chain_function (pixbufscale->sinkpad, gst_pixbufscale_chain);
275 gst_pad_set_link_function (pixbufscale->sinkpad, gst_pixbufscale_link);
276 gst_pad_set_getcaps_function (pixbufscale->sinkpad, gst_pixbufscale_getcaps);
278 pixbufscale->srcpad =
279 gst_pad_new_from_template (gst_static_pad_template_get
280 (&gst_pixbufscale_src_template), "src");
281 gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->srcpad);
282 gst_pad_set_event_function (pixbufscale->srcpad,
283 gst_pixbufscale_handle_src_event);
284 gst_pad_set_link_function (pixbufscale->srcpad, gst_pixbufscale_link);
285 gst_pad_set_getcaps_function (pixbufscale->srcpad, gst_pixbufscale_getcaps);
287 pixbufscale->inited = FALSE;
289 pixbufscale->method = GST_PIXBUFSCALE_TILES;
290 pixbufscale->gdk_method = GDK_INTERP_TILES;
294 gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event)
296 GstPixbufScale *pixbufscale;
298 GstStructure *structure;
301 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
303 switch (GST_EVENT_TYPE (event)) {
304 case GST_EVENT_NAVIGATION:
305 structure = gst_structure_copy (event->event_data.structure.structure);
306 if (gst_structure_get_double (event->event_data.structure.structure,
308 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
309 a * pixbufscale->from_width / pixbufscale->to_width, NULL);
311 if (gst_structure_get_double (event->event_data.structure.structure,
313 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
314 a * pixbufscale->from_height / pixbufscale->to_height, NULL);
316 gst_event_unref (event);
317 new_event = gst_event_new (GST_EVENT_NAVIGATION);
318 new_event->event_data.structure.structure = structure;
319 return gst_pad_event_default (pad, new_event);
322 return gst_pad_event_default (pad, event);
328 pixbufscale_scale (GstPixbufScale * scale, unsigned char *dest,
331 GdkPixbuf *src_pixbuf, *dest_pixbuf;
333 src_pixbuf = gdk_pixbuf_new_from_data
334 (src, GDK_COLORSPACE_RGB, FALSE,
335 8, scale->from_width, scale->from_height,
336 3 * scale->from_width, NULL, NULL);
337 dest_pixbuf = gdk_pixbuf_new_from_data
338 (dest, GDK_COLORSPACE_RGB, FALSE,
339 8, scale->to_width, scale->to_height, 3 * scale->to_width, NULL, NULL);
340 gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0, scale->to_width,
341 scale->to_height, 0, 0,
342 (double) scale->to_width / scale->from_width,
343 (double) scale->to_height / scale->from_height, scale->gdk_method);
345 dest_pixbuf = gdk_pixbuf_scale_simple
346 (src_pixbuf, scale->to_width, scale->to_height, scale->gdk_method);
348 g_object_unref (src_pixbuf);
349 g_object_unref (dest_pixbuf);
353 gst_pixbufscale_chain (GstPad * pad, GstData * _data)
355 GstBuffer *buf = GST_BUFFER (_data);
356 GstPixbufScale *pixbufscale;
361 g_return_if_fail (pad != NULL);
362 g_return_if_fail (GST_IS_PAD (pad));
363 g_return_if_fail (buf != NULL);
365 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
366 g_return_if_fail (pixbufscale->inited);
368 data = GST_BUFFER_DATA (buf);
369 size = GST_BUFFER_SIZE (buf);
371 if (pixbufscale->passthru) {
372 GST_LOG_OBJECT (pixbufscale, "passing through buffer of %ld bytes in '%s'",
373 size, GST_OBJECT_NAME (pixbufscale));
374 gst_pad_push (pixbufscale->srcpad, GST_DATA (buf));
378 GST_LOG_OBJECT (pixbufscale, "got buffer of %ld bytes in '%s'", size,
379 GST_OBJECT_NAME (pixbufscale));
380 GST_LOG_OBJECT (pixbufscale,
381 "size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
382 size, pixbufscale->from_width, pixbufscale->from_height,
383 pixbufscale->to_width, pixbufscale->to_height, size,
384 pixbufscale->from_buf_size, pixbufscale->to_buf_size);
386 g_return_if_fail (size == pixbufscale->from_buf_size);
388 outbuf = gst_pad_alloc_buffer (pixbufscale->srcpad,
389 GST_BUFFER_OFFSET_NONE, pixbufscale->to_buf_size);
391 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
393 pixbufscale_scale (pixbufscale, GST_BUFFER_DATA (outbuf), data);
395 GST_DEBUG_OBJECT (pixbufscale, "pushing buffer of %d bytes in '%s'",
396 GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (pixbufscale));
398 gst_pad_push (pixbufscale->srcpad, GST_DATA (outbuf));
400 gst_buffer_unref (buf);
404 gst_pixbufscale_set_property (GObject * object, guint prop_id,
405 const GValue * value, GParamSpec * pspec)
409 g_return_if_fail (GST_IS_PIXBUFSCALE (object));
410 src = GST_PIXBUFSCALE (object);
414 src->method = g_value_get_enum (value);
415 switch (src->method) {
416 case GST_PIXBUFSCALE_NEAREST:
417 src->gdk_method = GDK_INTERP_NEAREST;
419 case GST_PIXBUFSCALE_TILES:
420 src->gdk_method = GDK_INTERP_TILES;
422 case GST_PIXBUFSCALE_BILINEAR:
423 src->gdk_method = GDK_INTERP_BILINEAR;
425 case GST_PIXBUFSCALE_HYPER:
426 src->gdk_method = GDK_INTERP_HYPER;
436 gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value,
441 g_return_if_fail (GST_IS_PIXBUFSCALE (object));
442 src = GST_PIXBUFSCALE (object);
446 g_value_set_enum (value, src->method);
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
456 pixbufscale_init (GstPlugin * plugin)
458 if (!gst_element_register (plugin, "gdkpixbufscale", GST_RANK_NONE,
459 GST_TYPE_PIXBUFSCALE))
462 GST_DEBUG_CATEGORY_INIT (pixbufscale_debug, "gdkpixbufscale", 0,
463 "pixbufscale element");