2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * SECTION:element-alphacolor
23 * The alphacolor element does memory-efficient (in-place) colourspace
24 * conversion from RGBA to AYUV or AYUV to RGBA while preserving the
29 * gst-launch-1.0 videotestsrc ! "video/x-raw,format=(fourcc)AYUV" ! \
30 * alphacolor ! videoconvert ! autovideosink
38 #include "gstalphacolor.h"
41 #include <gst/video/video.h>
45 GST_DEBUG_CATEGORY_STATIC (alpha_color_debug);
46 #define GST_CAT_DEFAULT alpha_color_debug
48 /* elementfactory information */
49 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
52 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, BGRA, ARGB, ABGR, AYUV }"))
55 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
58 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, BGRA, ARGB, ABGR, AYUV }"))
61 G_DEFINE_TYPE (GstAlphaColor, gst_alpha_color, GST_TYPE_VIDEO_FILTER);
63 static GstCaps *gst_alpha_color_transform_caps (GstBaseTransform * btrans,
64 GstPadDirection direction, GstCaps * caps, GstCaps * filter);
66 static gboolean gst_alpha_color_set_info (GstVideoFilter * filter,
67 GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
68 GstVideoInfo * out_info);
69 static GstFlowReturn gst_alpha_color_transform_frame_ip (GstVideoFilter *
70 filter, GstVideoFrame * frame);
73 gst_alpha_color_class_init (GstAlphaColorClass * klass)
75 GstElementClass *gstelement_class = (GstElementClass *) klass;
76 GstBaseTransformClass *gstbasetransform_class =
77 (GstBaseTransformClass *) klass;
78 GstVideoFilterClass *gstvideofilter_class = (GstVideoFilterClass *) klass;
80 GST_DEBUG_CATEGORY_INIT (alpha_color_debug, "alphacolor", 0,
81 "ARGB<->AYUV colorspace conversion preserving the alpha channels");
83 gst_element_class_set_static_metadata (gstelement_class, "Alpha color filter",
84 "Filter/Converter/Video",
85 "ARGB from/to AYUV colorspace conversion preserving the alpha channel",
86 "Wim Taymans <wim.taymans@gmail.com>");
88 gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
89 gst_element_class_add_static_pad_template (gstelement_class, &src_template);
91 gstbasetransform_class->transform_caps =
92 GST_DEBUG_FUNCPTR (gst_alpha_color_transform_caps);
93 gstbasetransform_class->transform_ip_on_passthrough = FALSE;
95 gstvideofilter_class->set_info = GST_DEBUG_FUNCPTR (gst_alpha_color_set_info);
96 gstvideofilter_class->transform_frame_ip =
97 GST_DEBUG_FUNCPTR (gst_alpha_color_transform_frame_ip);
101 gst_alpha_color_init (GstAlphaColor * alpha)
103 GstBaseTransform *btrans = GST_BASE_TRANSFORM (alpha);
105 gst_base_transform_set_in_place (btrans, TRUE);
109 gst_alpha_color_transform_caps (GstBaseTransform * btrans,
110 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
112 GstCaps *tmpl_caps = NULL;
113 GstCaps *result = NULL, *local_caps = NULL;
116 local_caps = gst_caps_new_empty ();
118 for (i = 0; i < gst_caps_get_size (caps); i++) {
119 GstStructure *structure =
120 gst_structure_copy (gst_caps_get_structure (caps, i));
122 /* Remove any specific parameter from the structure */
123 gst_structure_remove_field (structure, "format");
124 gst_structure_remove_field (structure, "colorimetry");
125 gst_structure_remove_field (structure, "chroma-site");
127 gst_structure_set_name (structure, "video/x-raw");
128 gst_caps_append_structure (local_caps, structure);
131 /* Get the appropriate template */
132 if (direction == GST_PAD_SINK) {
133 tmpl_caps = gst_static_pad_template_get_caps (&src_template);
134 } else if (direction == GST_PAD_SRC) {
135 tmpl_caps = gst_static_pad_template_get_caps (&sink_template);
138 /* Intersect with our template caps */
139 result = gst_caps_intersect (local_caps, tmpl_caps);
140 gst_caps_unref (tmpl_caps);
141 gst_caps_unref (local_caps);
143 result = gst_caps_simplify (result);
145 GST_LOG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT,
149 GstCaps *intersection;
151 GST_DEBUG_OBJECT (btrans, "Using filter caps %" GST_PTR_FORMAT, filter);
153 gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
154 gst_caps_unref (result);
155 result = intersection;
156 GST_DEBUG_OBJECT (btrans, "Intersection %" GST_PTR_FORMAT, result);
163 /* Generated by -bad/ext/cog/generate_tables */
164 static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
166 298, -55, -136, 19681,
170 static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
172 298, -100, -208, 34707,
176 static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
178 -26, -87, 112, 32768,
179 112, -102, -10, 32768,
182 static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
184 -38, -74, 112, 32768,
185 112, -94, -18, 32768,
188 static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
189 256, -30, -53, 10600,
194 static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
200 #define DEFINE_ARGB_AYUV_FUNCTIONS(name, A, R, G, B) \
202 transform_##name##_ayuv (GstVideoFrame * frame, const gint *matrix) \
211 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);\
212 size = GST_VIDEO_FRAME_SIZE (frame);\
214 memcpy (yc, matrix, 4 * sizeof (gint)); \
215 memcpy (uc, matrix + 4, 4 * sizeof (gint)); \
216 memcpy (vc, matrix + 8, 4 * sizeof (gint)); \
219 y = (data[R] * yc[0] + data[G] * yc[1] + data[B] * yc[2] + yc[3]) >> 8; \
220 u = (data[R] * uc[0] + data[G] * uc[1] + data[B] * uc[2] + uc[3]) >> 8; \
221 v = (data[R] * vc[0] + data[G] * vc[1] + data[B] * vc[2] + vc[3]) >> 8; \
234 transform_ayuv_##name (GstVideoFrame * frame, const gint *matrix) \
243 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);\
244 size = GST_VIDEO_FRAME_SIZE (frame);\
246 memcpy (rc, matrix, 4 * sizeof (gint)); \
247 memcpy (gc, matrix + 4, 4 * sizeof (gint)); \
248 memcpy (bc, matrix + 8, 4 * sizeof (gint)); \
251 r = (data[1] * rc[0] + data[2] * rc[1] + data[3] * rc[2] + rc[3]) >> 8; \
252 g = (data[1] * gc[0] + data[2] * gc[1] + data[3] * gc[2] + gc[3]) >> 8; \
253 b = (data[1] * bc[0] + data[2] * bc[1] + data[3] * bc[2] + bc[3]) >> 8; \
256 data[R] = CLAMP (r, 0, 255); \
257 data[G] = CLAMP (g, 0, 255); \
258 data[B] = CLAMP (b, 0, 255); \
265 DEFINE_ARGB_AYUV_FUNCTIONS (rgba, 3, 0, 1, 2);
266 DEFINE_ARGB_AYUV_FUNCTIONS (bgra, 3, 2, 1, 0);
267 DEFINE_ARGB_AYUV_FUNCTIONS (argb, 0, 1, 2, 3);
268 DEFINE_ARGB_AYUV_FUNCTIONS (abgr, 0, 3, 2, 1);
271 transform_ayuv_ayuv (GstVideoFrame * frame, const gint * matrix)
283 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
284 size = GST_VIDEO_FRAME_SIZE (frame);
286 memcpy (yc, matrix, 4 * sizeof (gint));
287 memcpy (uc, matrix + 4, 4 * sizeof (gint));
288 memcpy (vc, matrix + 8, 4 * sizeof (gint));
291 y = (data[1] * yc[0] + data[2] * yc[1] + data[3] * yc[2] + yc[3]) >> 8;
292 u = (data[1] * uc[0] + data[2] * uc[1] + data[3] * uc[2] + uc[3]) >> 8;
293 v = (data[1] * vc[0] + data[2] * vc[1] + data[3] * vc[2] + vc[3]) >> 8;
305 transform_argb_bgra (GstVideoFrame * frame, const gint * matrix)
311 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
312 size = GST_VIDEO_FRAME_SIZE (frame);
329 #define transform_abgr_rgba transform_argb_bgra
332 transform_argb_abgr (GstVideoFrame * frame, const gint * matrix)
338 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
339 size = GST_VIDEO_FRAME_SIZE (frame);
346 /* data[0] = data[0]; */
356 #define transform_abgr_argb transform_argb_abgr
359 transform_rgba_bgra (GstVideoFrame * frame, const gint * matrix)
365 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
366 size = GST_VIDEO_FRAME_SIZE (frame);
373 /* data[3] = data[3] */ ;
383 #define transform_bgra_rgba transform_rgba_bgra
386 transform_argb_rgba (GstVideoFrame * frame, const gint * matrix)
392 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
393 size = GST_VIDEO_FRAME_SIZE (frame);
410 #define transform_abgr_bgra transform_argb_rgba
413 transform_bgra_argb (GstVideoFrame * frame, const gint * matrix)
419 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
420 size = GST_VIDEO_FRAME_SIZE (frame);
437 #define transform_rgba_abgr transform_bgra_argb
440 transform_rgba_argb (GstVideoFrame * frame, const gint * matrix)
446 data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
447 size = GST_VIDEO_FRAME_SIZE (frame);
464 #define transform_bgra_abgr transform_rgba_argb
467 gst_alpha_color_set_info (GstVideoFilter * filter, GstCaps * incaps,
468 GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
470 GstAlphaColor *alpha = GST_ALPHA_COLOR (filter);
471 gboolean in_sdtv, out_sdtv;
473 alpha->process = NULL;
474 alpha->matrix = NULL;
476 if (GST_VIDEO_INFO_WIDTH (in_info) != GST_VIDEO_INFO_WIDTH (out_info) ||
477 GST_VIDEO_INFO_HEIGHT (in_info) != GST_VIDEO_INFO_HEIGHT (out_info))
480 in_sdtv = in_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
481 out_sdtv = out_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
483 switch (GST_VIDEO_INFO_FORMAT (in_info)) {
484 case GST_VIDEO_FORMAT_ARGB:
485 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
486 case GST_VIDEO_FORMAT_ARGB:
487 alpha->process = NULL;
488 alpha->matrix = NULL;
490 case GST_VIDEO_FORMAT_BGRA:
491 alpha->process = transform_argb_bgra;
492 alpha->matrix = NULL;
494 case GST_VIDEO_FORMAT_ABGR:
495 alpha->process = transform_argb_abgr;
496 alpha->matrix = NULL;
498 case GST_VIDEO_FORMAT_RGBA:
499 alpha->process = transform_argb_rgba;
500 alpha->matrix = NULL;
502 case GST_VIDEO_FORMAT_AYUV:
503 alpha->process = transform_argb_ayuv;
505 out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
506 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
509 alpha->process = NULL;
510 alpha->matrix = NULL;
514 case GST_VIDEO_FORMAT_BGRA:
515 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
516 case GST_VIDEO_FORMAT_BGRA:
517 alpha->process = NULL;
518 alpha->matrix = NULL;
520 case GST_VIDEO_FORMAT_ARGB:
521 alpha->process = transform_bgra_argb;
522 alpha->matrix = NULL;
524 case GST_VIDEO_FORMAT_ABGR:
525 alpha->process = transform_bgra_abgr;
526 alpha->matrix = NULL;
528 case GST_VIDEO_FORMAT_RGBA:
529 alpha->process = transform_bgra_rgba;
530 alpha->matrix = NULL;
532 case GST_VIDEO_FORMAT_AYUV:
533 alpha->process = transform_bgra_ayuv;
535 out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
536 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
539 alpha->process = NULL;
540 alpha->matrix = NULL;
544 case GST_VIDEO_FORMAT_ABGR:
545 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
546 case GST_VIDEO_FORMAT_ABGR:
547 alpha->process = NULL;
548 alpha->matrix = NULL;
550 case GST_VIDEO_FORMAT_RGBA:
551 alpha->process = transform_abgr_rgba;
552 alpha->matrix = NULL;
554 case GST_VIDEO_FORMAT_ARGB:
555 alpha->process = transform_abgr_argb;
556 alpha->matrix = NULL;
558 case GST_VIDEO_FORMAT_BGRA:
559 alpha->process = transform_abgr_bgra;
560 alpha->matrix = NULL;
562 case GST_VIDEO_FORMAT_AYUV:
563 alpha->process = transform_abgr_ayuv;
565 out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
566 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
569 alpha->process = NULL;
570 alpha->matrix = NULL;
574 case GST_VIDEO_FORMAT_RGBA:
575 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
576 case GST_VIDEO_FORMAT_RGBA:
577 alpha->process = NULL;
578 alpha->matrix = NULL;
580 case GST_VIDEO_FORMAT_ARGB:
581 alpha->process = transform_rgba_argb;
582 alpha->matrix = NULL;
584 case GST_VIDEO_FORMAT_ABGR:
585 alpha->process = transform_rgba_abgr;
586 alpha->matrix = NULL;
588 case GST_VIDEO_FORMAT_BGRA:
589 alpha->process = transform_rgba_bgra;
590 alpha->matrix = NULL;
592 case GST_VIDEO_FORMAT_AYUV:
593 alpha->process = transform_rgba_ayuv;
595 out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
596 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
599 alpha->process = NULL;
600 alpha->matrix = NULL;
604 case GST_VIDEO_FORMAT_AYUV:
605 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
606 case GST_VIDEO_FORMAT_AYUV:
607 if (in_sdtv == out_sdtv) {
608 alpha->process = transform_ayuv_ayuv;
609 alpha->matrix = NULL;
611 alpha->process = transform_ayuv_ayuv;
613 out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
614 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit;
617 case GST_VIDEO_FORMAT_ARGB:
618 alpha->process = transform_ayuv_argb;
620 in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
621 cog_ycbcr_to_rgb_matrix_8bit_hdtv;
623 case GST_VIDEO_FORMAT_BGRA:
624 alpha->process = transform_ayuv_bgra;
626 in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
627 cog_ycbcr_to_rgb_matrix_8bit_hdtv;
629 case GST_VIDEO_FORMAT_ABGR:
630 alpha->process = transform_ayuv_abgr;
632 in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
633 cog_ycbcr_to_rgb_matrix_8bit_hdtv;
635 case GST_VIDEO_FORMAT_RGBA:
636 alpha->process = transform_ayuv_rgba;
638 in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
639 cog_ycbcr_to_rgb_matrix_8bit_hdtv;
642 alpha->process = NULL;
643 alpha->matrix = NULL;
648 alpha->process = NULL;
649 alpha->matrix = NULL;
653 if (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_INFO_FORMAT (out_info)
654 && in_sdtv == out_sdtv)
655 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
656 else if (!alpha->process)
664 GST_DEBUG_OBJECT (alpha, "incomplete or invalid caps");
669 GST_DEBUG_OBJECT (alpha, "could not find process function");
675 gst_alpha_color_transform_frame_ip (GstVideoFilter * filter,
676 GstVideoFrame * frame)
678 GstAlphaColor *alpha = GST_ALPHA_COLOR (filter);
680 if (G_UNLIKELY (!alpha->process))
683 /* Transform in place */
684 alpha->process (frame, alpha->matrix);
691 GST_ERROR_OBJECT (alpha, "Not negotiated yet");
692 return GST_FLOW_NOT_NEGOTIATED;
697 plugin_init (GstPlugin * plugin)
699 return gst_element_register (plugin, "alphacolor", GST_RANK_NONE,
700 GST_TYPE_ALPHA_COLOR);
703 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
706 "RGBA from/to AYUV colorspace conversion preserving the alpha channel",
707 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)