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;
168 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
170 otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad :
172 othercaps = gst_pad_get_allowed_caps (otherpad);
174 caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
175 gst_caps_free (othercaps);
177 GST_DEBUG ("getcaps are: %" GST_PTR_FORMAT, caps);
181 static GstPadLinkReturn
182 gst_pixbufscale_link (GstPad * pad, const GstCaps * caps)
184 GstPixbufScale *pixbufscale;
185 GstPadLinkReturn ret;
187 GstStructure *structure;
190 GST_DEBUG ("gst_pixbufscale_link %s\n", gst_caps_to_string (caps));
191 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
193 otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad :
196 structure = gst_caps_get_structure (caps, 0);
197 ret = gst_structure_get_int (structure, "width", &width);
198 ret &= gst_structure_get_int (structure, "height", &height);
200 ret = gst_pad_try_set_caps (otherpad, caps);
201 if (ret == GST_PAD_LINK_OK) {
202 /* cool, we can use passthru */
204 pixbufscale->to_width = width;
205 pixbufscale->to_height = height;
206 pixbufscale->from_width = width;
207 pixbufscale->from_height = height;
209 pixbufscale->from_buf_size = width * height * 3;
210 pixbufscale->to_buf_size = width * height * 3;
212 pixbufscale->inited = TRUE;
214 return GST_PAD_LINK_OK;
217 if (gst_pad_is_negotiated (otherpad)) {
218 GstCaps *newcaps = gst_caps_copy (caps);
220 if (pad == pixbufscale->srcpad) {
221 gst_caps_set_simple (newcaps,
222 "width", G_TYPE_INT, pixbufscale->from_width,
223 "height", G_TYPE_INT, pixbufscale->from_height, NULL);
225 gst_caps_set_simple (newcaps,
226 "width", G_TYPE_INT, pixbufscale->to_width,
227 "height", G_TYPE_INT, pixbufscale->to_height, NULL);
229 ret = gst_pad_try_set_caps (otherpad, newcaps);
230 if (GST_PAD_LINK_FAILED (ret)) {
231 return GST_PAD_LINK_REFUSED;
235 pixbufscale->passthru = FALSE;
237 if (pad == pixbufscale->srcpad) {
238 pixbufscale->to_width = width;
239 pixbufscale->to_height = height;
241 pixbufscale->from_width = width;
242 pixbufscale->from_height = height;
245 if (gst_pad_is_negotiated (otherpad)) {
246 pixbufscale->from_buf_size = pixbufscale->from_width *
247 pixbufscale->from_height * 3;
248 pixbufscale->to_buf_size = pixbufscale->to_width *
249 pixbufscale->to_height * 3;
250 pixbufscale->inited = TRUE;
253 return GST_PAD_LINK_OK;
257 gst_pixbufscale_init (GstPixbufScale * pixbufscale)
259 GST_DEBUG_OBJECT (pixbufscale, "_init");
260 pixbufscale->sinkpad =
261 gst_pad_new_from_template (gst_static_pad_template_get
262 (&gst_pixbufscale_sink_template), "sink");
263 gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->sinkpad);
264 gst_pad_set_chain_function (pixbufscale->sinkpad, gst_pixbufscale_chain);
265 gst_pad_set_link_function (pixbufscale->sinkpad, gst_pixbufscale_link);
266 gst_pad_set_getcaps_function (pixbufscale->sinkpad, gst_pixbufscale_getcaps);
268 pixbufscale->srcpad =
269 gst_pad_new_from_template (gst_static_pad_template_get
270 (&gst_pixbufscale_src_template), "src");
271 gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->srcpad);
272 gst_pad_set_event_function (pixbufscale->srcpad,
273 gst_pixbufscale_handle_src_event);
274 gst_pad_set_link_function (pixbufscale->srcpad, gst_pixbufscale_link);
275 gst_pad_set_getcaps_function (pixbufscale->srcpad, gst_pixbufscale_getcaps);
277 pixbufscale->inited = FALSE;
279 pixbufscale->method = GST_PIXBUFSCALE_TILES;
280 pixbufscale->gdk_method = GDK_INTERP_TILES;
284 gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event)
286 GstPixbufScale *pixbufscale;
288 GstStructure *structure;
291 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
293 switch (GST_EVENT_TYPE (event)) {
294 case GST_EVENT_NAVIGATION:
295 structure = gst_structure_copy (event->event_data.structure.structure);
296 if (gst_structure_get_double (event->event_data.structure.structure,
298 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
299 a * pixbufscale->from_width / pixbufscale->to_width, NULL);
301 if (gst_structure_get_double (event->event_data.structure.structure,
303 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
304 a * pixbufscale->from_height / pixbufscale->to_height, NULL);
306 gst_event_unref (event);
307 new_event = gst_event_new (GST_EVENT_NAVIGATION);
308 new_event->event_data.structure.structure = structure;
309 return gst_pad_event_default (pad, new_event);
312 return gst_pad_event_default (pad, event);
318 pixbufscale_scale (GstPixbufScale * scale, unsigned char *dest,
321 GdkPixbuf *src_pixbuf, *dest_pixbuf;
323 src_pixbuf = gdk_pixbuf_new_from_data
324 (src, GDK_COLORSPACE_RGB, FALSE,
325 8, scale->from_width, scale->from_height,
326 3 * scale->from_width, NULL, NULL);
327 dest_pixbuf = gdk_pixbuf_new_from_data
328 (dest, GDK_COLORSPACE_RGB, FALSE,
329 8, scale->to_width, scale->to_height, 3 * scale->to_width, NULL, NULL);
330 gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0, scale->to_width,
331 scale->to_height, 0, 0,
332 (double) scale->to_width / scale->from_width,
333 (double) scale->to_height / scale->from_height, scale->gdk_method);
335 dest_pixbuf = gdk_pixbuf_scale_simple
336 (src_pixbuf, scale->to_width, scale->to_height, scale->gdk_method);
338 g_object_unref (src_pixbuf);
339 g_object_unref (dest_pixbuf);
343 gst_pixbufscale_chain (GstPad * pad, GstData * _data)
345 GstBuffer *buf = GST_BUFFER (_data);
346 GstPixbufScale *pixbufscale;
351 g_return_if_fail (pad != NULL);
352 g_return_if_fail (GST_IS_PAD (pad));
353 g_return_if_fail (buf != NULL);
355 pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
356 g_return_if_fail (pixbufscale->inited);
358 data = GST_BUFFER_DATA (buf);
359 size = GST_BUFFER_SIZE (buf);
361 if (pixbufscale->passthru) {
362 GST_LOG_OBJECT (pixbufscale, "passing through buffer of %ld bytes in '%s'",
363 size, GST_OBJECT_NAME (pixbufscale));
364 gst_pad_push (pixbufscale->srcpad, GST_DATA (buf));
368 GST_LOG_OBJECT (pixbufscale, "got buffer of %ld bytes in '%s'", size,
369 GST_OBJECT_NAME (pixbufscale));
370 GST_LOG_OBJECT (pixbufscale,
371 "size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
372 size, pixbufscale->from_width, pixbufscale->from_height,
373 pixbufscale->to_width, pixbufscale->to_height, size,
374 pixbufscale->from_buf_size, pixbufscale->to_buf_size);
376 g_return_if_fail (size == pixbufscale->from_buf_size);
378 outbuf = gst_pad_alloc_buffer (pixbufscale->srcpad,
379 GST_BUFFER_OFFSET_NONE, pixbufscale->to_buf_size);
381 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
383 pixbufscale_scale (pixbufscale, GST_BUFFER_DATA (outbuf), data);
385 GST_DEBUG_OBJECT (pixbufscale, "pushing buffer of %d bytes in '%s'",
386 GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (pixbufscale));
388 gst_pad_push (pixbufscale->srcpad, GST_DATA (outbuf));
390 gst_buffer_unref (buf);
394 gst_pixbufscale_set_property (GObject * object, guint prop_id,
395 const GValue * value, GParamSpec * pspec)
399 g_return_if_fail (GST_IS_PIXBUFSCALE (object));
400 src = GST_PIXBUFSCALE (object);
404 src->method = g_value_get_enum (value);
405 switch (src->method) {
406 case GST_PIXBUFSCALE_NEAREST:
407 src->gdk_method = GDK_INTERP_NEAREST;
409 case GST_PIXBUFSCALE_TILES:
410 src->gdk_method = GDK_INTERP_TILES;
412 case GST_PIXBUFSCALE_BILINEAR:
413 src->gdk_method = GDK_INTERP_BILINEAR;
415 case GST_PIXBUFSCALE_HYPER:
416 src->gdk_method = GDK_INTERP_HYPER;
426 gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value,
431 g_return_if_fail (GST_IS_PIXBUFSCALE (object));
432 src = GST_PIXBUFSCALE (object);
436 g_value_set_enum (value, src->method);
439 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
446 pixbufscale_init (GstPlugin * plugin)
448 if (!gst_element_register (plugin, "gdkpixbufscale", GST_RANK_NONE,
449 GST_TYPE_PIXBUFSCALE))
452 GST_DEBUG_CATEGORY_INIT (pixbufscale_debug, "gdkpixbufscale", 0,
453 "pixbufscale element");