]> git.sesse.net Git - mlt/blob - src/modules/core/filter_imageconvert.c
Cleanup existing native color space conversions.
[mlt] / src / modules / core / filter_imageconvert.c
1 /*
2  * filter_imageconvert.c -- colorspace and pixel format converter
3  * Copyright (C) 2009 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <framework/mlt_filter.h>
22 #include <framework/mlt_frame.h>
23 #include <framework/mlt_log.h>
24 #include <framework/mlt_pool.h>
25
26 #include <stdlib.h>
27
28 /** This macro converts a YUV value to the RGB color space. */
29 #define RGB2YUV_601_UNSCALED(r, g, b, y, u, v)\
30   y = (299*r + 587*g + 114*b) >> 10;\
31   u = ((-169*r - 331*g + 500*b) >> 10) + 128;\
32   v = ((500*r - 419*g - 81*b) >> 10) + 128;\
33   y = y < 16 ? 16 : y;\
34   u = u < 16 ? 16 : u;\
35   v = v < 16 ? 16 : v;\
36   y = y > 235 ? 235 : y;\
37   u = u > 240 ? 240 : u;\
38   v = v > 240 ? 240 : v
39
40 /** This macro scales YUV up into the full gamut of the RGB color space. */
41 #define YUV2RGB_601_SCALED( y, u, v, r, g, b ) \
42   r = ((1192 * ( y - 16 ) + 1634 * ( v - 128 ) ) >> 10 ); \
43   g = ((1192 * ( y - 16 ) - 832 * ( v - 128 ) - 401 * ( u - 128 ) ) >> 10 ); \
44   b = ((1192 * ( y - 16 ) + 2066 * ( u - 128 ) ) >> 10 ); \
45   r = r < 0 ? 0 : r > 255 ? 255 : r; \
46   g = g < 0 ? 0 : g > 255 ? 255 : g; \
47   b = b < 0 ? 0 : b > 255 ? 255 : b;
48
49 /** This macro converts a YUV value to the RGB color space. */
50 #define YUV2RGB_601_UNSCALED( y, u, v, r, g, b ) \
51   r = ((1024 * y + 1404 * ( v - 128 ) ) >> 10 ); \
52   g = ((1024 * y - 715 * ( v - 128 ) - 345 * ( u - 128 ) ) >> 10 ); \
53   b = ((1024 * y + 1774 * ( u - 128 ) ) >> 10 ); \
54   r = r < 0 ? 0 : r > 255 ? 255 : r; \
55   g = g < 0 ? 0 : g > 255 ? 255 : g; \
56   b = b < 0 ? 0 : b > 255 ? 255 : b;
57
58
59 static int convert_yuv422_to_rgb24a( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height )
60 {
61         int ret = 0;
62         int yy, uu, vv;
63         int r,g,b;
64         int total = width * height / 2 + 1;
65
66         while ( --total )
67         {
68                 yy = yuv[0];
69                 uu = yuv[1];
70                 vv = yuv[3];
71                 YUV2RGB_601_SCALED (yy, uu, vv, r, g, b);
72                 rgba[0] = r;
73                 rgba[1] = g;
74                 rgba[2] = b;
75                 rgba[3] = 255;
76                 yy = yuv[2];
77                 YUV2RGB_601_SCALED (yy, uu, vv, r, g, b);
78                 rgba[4] = r;
79                 rgba[5] = g;
80                 rgba[6] = b;
81                 rgba[7] = 255;
82                 yuv += 4;
83                 rgba += 8;
84         }
85         return ret;
86 }
87
88 static int convert_yuv422_to_rgb24( uint8_t *yuv, uint8_t *rgb, uint8_t *alpha, int width, int height )
89 {
90         int ret = 0;
91         int yy, uu, vv;
92         int r,g,b;
93         int total = width * height / 2 + 1;
94
95         while ( --total )
96         {
97                 yy = yuv[0];
98                 uu = yuv[1];
99                 vv = yuv[3];
100                 YUV2RGB_601_SCALED (yy, uu, vv, r, g, b);
101                 rgb[0] = r;
102                 rgb[1] = g;
103                 rgb[2] = b;
104                 yy = yuv[2];
105                 YUV2RGB_601_SCALED (yy, uu, vv, r, g, b);
106                 rgb[3] = r;
107                 rgb[4] = g;
108                 rgb[5] = b;
109                 yuv += 4;
110                 rgb += 6;
111         }
112         return ret;
113 }
114
115 static int convert_rgb24a_to_yuv422( uint8_t *rgba, uint8_t *yuv, uint8_t *alpha, int width, int height )
116 {
117         int ret = 0;
118         int stride = width * 4;
119         int y0, y1, u0, u1, v0, v1;
120         int r, g, b;
121         uint8_t *s, *d = yuv;
122         int i, j, n = width / 2 + 1;
123
124         if ( alpha )
125         for ( i = 0; i < height; i++ )
126         {
127                 s = rgba + ( stride * i );
128                 j = n;
129                 while ( --j )
130                 {
131                         r = *s++;
132                         g = *s++;
133                         b = *s++;
134                         *alpha++ = *s++;
135                         RGB2YUV_601_SCALED (r, g, b, y0, u0 , v0);
136                         r = *s++;
137                         g = *s++;
138                         b = *s++;
139                         *alpha++ = *s++;
140                         RGB2YUV_601_SCALED (r, g, b, y1, u1 , v1);
141                         *d++ = y0;
142                         *d++ = (u0+u1) >> 1;
143                         *d++ = y1;
144                         *d++ = (v0+v1) >> 1;
145                 }
146                 if ( width % 2 )
147                 {
148                         r = *s++;
149                         g = *s++;
150                         b = *s++;
151                         *alpha++ = *s++;
152                         RGB2YUV_601_SCALED (r, g, b, y0, u0 , v0);
153                         *d++ = y0;
154                         *d++ = u0;
155                 }
156         }
157         else
158         for ( i = 0; i < height; i++ )
159         {
160                 s = rgba + ( stride * i );
161                 j = n;
162                 while ( --j )
163                 {
164                         r = *s++;
165                         g = *s++;
166                         b = *s++;
167                         s++;
168                         RGB2YUV_601_SCALED (r, g, b, y0, u0 , v0);
169                         r = *s++;
170                         g = *s++;
171                         b = *s++;
172                         s++;
173                         RGB2YUV_601_SCALED (r, g, b, y1, u1 , v1);
174                         *d++ = y0;
175                         *d++ = (u0+u1) >> 1;
176                         *d++ = y1;
177                         *d++ = (v0+v1) >> 1;
178                 }
179                 if ( width % 2 )
180                 {
181                         r = *s++;
182                         g = *s++;
183                         b = *s++;
184                         s++;
185                         RGB2YUV_601_SCALED (r, g, b, y0, u0 , v0);
186                         *d++ = y0;
187                         *d++ = u0;
188                 }
189         }
190
191         return ret;
192 }
193
194 static int convert_rgb24_to_yuv422( uint8_t *rgb, uint8_t *yuv, uint8_t *alpha, int width, int height )
195 {
196         int ret = 0;
197         int stride = width * 3;
198         int y0, y1, u0, u1, v0, v1;
199         int r, g, b;
200         uint8_t *s, *d = yuv;
201         int i, j, n = width / 2 + 1;
202
203         for ( i = 0; i < height; i++ )
204         {
205                 s = rgb + ( stride * i );
206                 j = n;
207                 while ( --j )
208                 {
209                         r = *s++;
210                         g = *s++;
211                         b = *s++;
212                         RGB2YUV_601_SCALED (r, g, b, y0, u0 , v0);
213                         r = *s++;
214                         g = *s++;
215                         b = *s++;
216                         RGB2YUV_601_SCALED (r, g, b, y1, u1 , v1);
217                         *d++ = y0;
218                         *d++ = (u0+u1) >> 1;
219                         *d++ = y1;
220                         *d++ = (v0+v1) >> 1;
221                 }
222                 if ( width % 2 )
223                 {
224                         r = *s++;
225                         g = *s++;
226                         b = *s++;
227                         RGB2YUV_601_SCALED (r, g, b, y0, u0 , v0);
228                         *d++ = y0;
229                         *d++ = u0;
230                 }
231         }
232         return ret;
233 }
234
235 static int convert_yuv420p_to_yuv422( uint8_t *yuv420p, uint8_t *yuv, uint8_t *alpha, int width, int height )
236 {
237         int ret = 0;
238         int i, j;
239         int half = width >> 1;
240         uint8_t *Y = yuv420p;
241         uint8_t *U = Y + width * height;
242         uint8_t *V = U + width * height / 4;
243         uint8_t *d = yuv;
244
245         for ( i = 0; i < height; i++ )
246         {
247                 uint8_t *u = U + ( i / 2 ) * ( half );
248                 uint8_t *v = V + ( i / 2 ) * ( half );
249
250                 j = half + 1;
251                 while ( --j )
252                 {
253                         *d ++ = *Y ++;
254                         *d ++ = *u ++;
255                         *d ++ = *Y ++;
256                         *d ++ = *v ++;
257                 }
258         }
259         return ret;
260 }
261
262 static int convert_rgb24_to_rgb24a( uint8_t *rgb, uint8_t *rgba, uint8_t *alpha, int width, int height )
263 {
264         uint8_t *s = rgb;
265         uint8_t *d = rgba;
266         int total = width * height + 1;
267
268         while ( --total )
269         {
270                 *d++ = s[0];
271                 *d++ = s[1];
272                 *d++ = s[2];
273                 *d++ = 0xff;
274                 s += 3;
275         }
276         return 0;
277 }
278
279 static int convert_rgb24a_to_rgb24( uint8_t *rgba, uint8_t *rgb, uint8_t *alpha, int width, int height )
280 {
281         uint8_t *s = rgba;
282         uint8_t *d = rgb;
283         int total = width * height + 1;
284
285         while ( --total )
286         {
287                 *d++ = s[0];
288                 *d++ = s[1];
289                 *d++ = s[2];
290                 *alpha++ = s[3];
291                 s += 4;
292         }
293         return 0;
294 }
295
296 typedef int ( *conversion_function )( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height );
297
298 static conversion_function conversion_matrix[5][5] = {
299         { NULL, convert_rgb24_to_rgb24a, convert_rgb24_to_yuv422, NULL, convert_rgb24_to_rgb24a },
300         { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL },
301         { convert_yuv422_to_rgb24, convert_yuv422_to_rgb24a, NULL, NULL, convert_yuv422_to_rgb24a },
302         { NULL, NULL, convert_yuv420p_to_yuv422, NULL, NULL },
303         { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL },
304 };
305
306 static uint8_t bpp_table[4] = { 3, 4, 2, 0 };
307
308 static int convert_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, mlt_image_format requested_format )
309 {
310         int error = 0;
311         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
312         int width = mlt_properties_get_int( properties, "width" );
313         int height = mlt_properties_get_int( properties, "height" );
314
315         if ( *format != requested_format )
316         {
317                 conversion_function converter = conversion_matrix[ *format - 1 ][ requested_format - 1 ];
318
319                 mlt_log_debug( NULL, "[filter imageconvert] %s -> %s\n",
320                         mlt_image_format_name( *format ), mlt_image_format_name( requested_format ) );
321                 if ( converter )
322                 {
323                         int size = width * height * bpp_table[ requested_format - 1 ];
324                         uint8_t *image = mlt_pool_alloc( size );
325                         uint8_t *alpha = ( *format == mlt_image_rgb24a ||
326                                            *format == mlt_image_opengl )
327                                          ? mlt_pool_alloc( width * height ) : NULL;
328
329                         if ( !( error = converter( *buffer, image, alpha, width, height ) ) )
330                         {
331                                 mlt_properties_set_data( properties, "image", image, size, mlt_pool_release, NULL );
332                                 if ( alpha )
333                                         mlt_properties_set_data( properties, "alpha", alpha, width * height, mlt_pool_release, NULL );
334                                 *buffer = image;
335                                 *format = requested_format;
336                         }
337                         else
338                         {
339                                 mlt_pool_release( image );
340                                 if ( alpha )
341                                         mlt_pool_release( alpha );
342                         }
343                 }
344                 else
345                 {
346                         error = 1;
347                 }
348         }
349         if ( !error )
350                 mlt_properties_set_int( properties, "format", *format );
351
352         return error;
353 }
354
355 /** Filter processing.
356 */
357
358 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
359 {
360         frame->convert_image = convert_image;
361         return frame;
362 }
363
364 /** Constructor for the filter.
365 */
366
367 mlt_filter filter_imageconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
368 {
369         mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 );
370         if ( mlt_filter_init( this, this ) == 0 )
371         {
372                 this->process = filter_process;
373         }
374         return this;
375 }