2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
5 * Copyright (C) 2010 David Schleef <ds@schleef.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 * SECTION:element-videoconvert
26 * Convert video frames between a great variety of video formats.
29 * <title>Example launch line</title>
31 * gst-launch -v videotestsrc ! video/x-raw,format=\(string\)YUY2 ! videoconvert ! ximagesink
40 #include "gstvideoconvert.h"
42 #include <gst/video/video.h>
43 #include <gst/video/gstvideometa.h>
44 #include <gst/video/gstvideopool.h>
48 GST_DEBUG_CATEGORY (videoconvert_debug);
49 #define GST_CAT_DEFAULT videoconvert_debug
50 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
52 GType gst_video_convert_get_type (void);
54 static GQuark _colorspace_quark;
56 #define gst_video_convert_parent_class parent_class
57 G_DEFINE_TYPE (GstVideoConvert, gst_video_convert, GST_TYPE_VIDEO_FILTER);
65 #define CSP_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL)
67 static GstStaticPadTemplate gst_video_convert_src_template =
68 GST_STATIC_PAD_TEMPLATE ("src",
71 GST_STATIC_CAPS (CSP_VIDEO_CAPS)
74 static GstStaticPadTemplate gst_video_convert_sink_template =
75 GST_STATIC_PAD_TEMPLATE ("sink",
78 GST_STATIC_CAPS (CSP_VIDEO_CAPS)
81 static void gst_video_convert_set_property (GObject * object,
82 guint property_id, const GValue * value, GParamSpec * pspec);
83 static void gst_video_convert_get_property (GObject * object,
84 guint property_id, GValue * value, GParamSpec * pspec);
86 static gboolean gst_video_convert_set_info (GstVideoFilter * filter,
87 GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
88 GstVideoInfo * out_info);
89 static GstFlowReturn gst_video_convert_transform_frame (GstVideoFilter * filter,
90 GstVideoFrame * in_frame, GstVideoFrame * out_frame);
93 dither_method_get_type (void)
95 static GType gtype = 0;
98 static const GEnumValue values[] = {
99 {DITHER_NONE, "No dithering (default)", "none"},
100 {DITHER_VERTERR, "Vertical error propogation", "verterr"},
101 {DITHER_HALFTONE, "Half-tone", "halftone"},
105 gtype = g_enum_register_static ("GstVideoConvertDitherMethod", values);
110 /* copies the given caps */
112 gst_video_convert_caps_remove_format_info (GstCaps * caps)
118 res = gst_caps_new_empty ();
120 n = gst_caps_get_size (caps);
121 for (i = 0; i < n; i++) {
122 st = gst_caps_get_structure (caps, i);
124 /* If this is already expressed by the existing caps
125 * skip this structure */
126 if (i > 0 && gst_caps_is_subset_structure (res, st))
129 st = gst_structure_copy (st);
130 gst_structure_remove_fields (st, "format",
131 "colorimetry", "chroma-site", NULL);
133 gst_caps_append_structure (res, st);
140 gst_video_convert_fixate_caps (GstBaseTransform * trans,
141 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
145 GST_DEBUG_OBJECT (trans, "fixating caps %" GST_PTR_FORMAT, othercaps);
147 result = gst_caps_intersect (othercaps, caps);
148 if (gst_caps_is_empty (result)) {
149 gst_caps_unref (result);
152 gst_caps_unref (othercaps);
155 /* fixate remaining fields */
156 result = gst_caps_fixate (result);
162 gst_video_convert_filter_meta (GstBaseTransform * trans, GstQuery * query,
163 GType api, const GstStructure * params)
165 /* propose all metadata upstream */
169 /* The caps can be transformed into any other caps with format info removed.
170 * However, we should prefer passthrough, so if passthrough is possible,
171 * put it first in the list. */
173 gst_video_convert_transform_caps (GstBaseTransform * btrans,
174 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
179 /* Get all possible caps that we can transform to */
180 tmp = gst_video_convert_caps_remove_format_info (caps);
183 tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
184 gst_caps_unref (tmp);
190 GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
191 GST_PTR_FORMAT, caps, result);
197 gst_video_convert_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
198 GstMeta * meta, GstBuffer * inbuf)
200 const GstMetaInfo *info = meta->info;
203 if (gst_meta_api_type_has_tag (info->api, _colorspace_quark)) {
204 /* don't copy colorspace specific metadata, FIXME, we need a MetaTransform
205 * for the colorspace metadata. */
208 /* copy other metadata */
215 gst_video_convert_set_info (GstVideoFilter * filter,
216 GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
217 GstVideoInfo * out_info)
219 GstVideoConvert *space;
221 space = GST_VIDEO_CONVERT_CAST (filter);
223 if (space->convert) {
224 videoconvert_convert_free (space->convert);
227 /* these must match */
228 if (in_info->width != out_info->width || in_info->height != out_info->height
229 || in_info->fps_n != out_info->fps_n || in_info->fps_d != out_info->fps_d)
230 goto format_mismatch;
232 /* if present, these must match too */
233 if (in_info->par_n != out_info->par_n || in_info->par_d != out_info->par_d)
234 goto format_mismatch;
236 /* if present, these must match too */
237 if (in_info->interlace_mode != out_info->interlace_mode)
238 goto format_mismatch;
240 space->convert = videoconvert_convert_new (in_info, out_info);
241 if (space->convert == NULL)
244 GST_DEBUG ("reconfigured %d %d", GST_VIDEO_INFO_FORMAT (in_info),
245 GST_VIDEO_INFO_FORMAT (out_info));
252 GST_ERROR_OBJECT (space, "input and output formats do not match");
257 GST_ERROR_OBJECT (space, "could not create converter");
263 gst_video_convert_finalize (GObject * obj)
265 GstVideoConvert *space = GST_VIDEO_CONVERT (obj);
267 if (space->convert) {
268 videoconvert_convert_free (space->convert);
271 G_OBJECT_CLASS (parent_class)->finalize (obj);
275 gst_video_convert_class_init (GstVideoConvertClass * klass)
277 GObjectClass *gobject_class = (GObjectClass *) klass;
278 GstElementClass *gstelement_class = (GstElementClass *) klass;
279 GstBaseTransformClass *gstbasetransform_class =
280 (GstBaseTransformClass *) klass;
281 GstVideoFilterClass *gstvideofilter_class = (GstVideoFilterClass *) klass;
283 gobject_class->set_property = gst_video_convert_set_property;
284 gobject_class->get_property = gst_video_convert_get_property;
285 gobject_class->finalize = gst_video_convert_finalize;
287 gst_element_class_add_pad_template (gstelement_class,
288 gst_static_pad_template_get (&gst_video_convert_src_template));
289 gst_element_class_add_pad_template (gstelement_class,
290 gst_static_pad_template_get (&gst_video_convert_sink_template));
292 gst_element_class_set_static_metadata (gstelement_class,
293 "Colorspace converter", "Filter/Converter/Video",
294 "Converts video from one colorspace to another",
295 "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
297 gstbasetransform_class->transform_caps =
298 GST_DEBUG_FUNCPTR (gst_video_convert_transform_caps);
299 gstbasetransform_class->fixate_caps =
300 GST_DEBUG_FUNCPTR (gst_video_convert_fixate_caps);
301 gstbasetransform_class->filter_meta =
302 GST_DEBUG_FUNCPTR (gst_video_convert_filter_meta);
303 gstbasetransform_class->transform_meta =
304 GST_DEBUG_FUNCPTR (gst_video_convert_transform_meta);
306 gstbasetransform_class->passthrough_on_same_caps = TRUE;
308 gstvideofilter_class->set_info =
309 GST_DEBUG_FUNCPTR (gst_video_convert_set_info);
310 gstvideofilter_class->transform_frame =
311 GST_DEBUG_FUNCPTR (gst_video_convert_transform_frame);
313 g_object_class_install_property (gobject_class, PROP_DITHER,
314 g_param_spec_enum ("dither", "Dither", "Apply dithering while converting",
315 dither_method_get_type (), DITHER_NONE,
316 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
320 gst_video_convert_init (GstVideoConvert * space)
325 gst_video_convert_set_property (GObject * object, guint property_id,
326 const GValue * value, GParamSpec * pspec)
328 GstVideoConvert *csp;
330 csp = GST_VIDEO_CONVERT (object);
332 switch (property_id) {
334 csp->dither = g_value_get_enum (value);
337 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
343 gst_video_convert_get_property (GObject * object, guint property_id,
344 GValue * value, GParamSpec * pspec)
346 GstVideoConvert *csp;
348 csp = GST_VIDEO_CONVERT (object);
350 switch (property_id) {
352 g_value_set_enum (value, csp->dither);
355 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
361 gst_video_convert_transform_frame (GstVideoFilter * filter,
362 GstVideoFrame * in_frame, GstVideoFrame * out_frame)
364 GstVideoConvert *space;
366 space = GST_VIDEO_CONVERT_CAST (filter);
368 GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, filter,
369 "doing colorspace conversion from %s -> to %s",
370 GST_VIDEO_INFO_NAME (&filter->in_info),
371 GST_VIDEO_INFO_NAME (&filter->out_info));
373 videoconvert_convert_set_dither (space->convert, space->dither);
375 videoconvert_convert_convert (space->convert, out_frame, in_frame);
381 plugin_init (GstPlugin * plugin)
383 GST_DEBUG_CATEGORY_INIT (videoconvert_debug, "videoconvert", 0,
384 "Colorspace Converter");
386 _colorspace_quark = g_quark_from_static_string ("colorspace");
388 return gst_element_register (plugin, "videoconvert",
389 GST_RANK_NONE, GST_TYPE_VIDEO_CONVERT);
392 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
394 videoconvert, "Colorspace conversion", plugin_init, VERSION, GST_LICENSE,
395 GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)