]> git.sesse.net Git - mlt/blob - src/modules/core/filter_imageconvert.c
33c938802ce8762a91d1d840e24c09982cdcf8b8
[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 #define SCALED 1
59 #if SCALED
60 #define RGB2YUV_601 RGB2YUV_601_SCALED
61 #define YUV2RGB_601 YUV2RGB_601_SCALED
62 #else
63 #define RGB2YUV_601 RGB2YUV_601_UNSCALED
64 #define YUV2RGB_601 YUV2RGB_601_UNSCALED
65 #endif
66
67 static int convert_yuv422_to_rgb24a( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height )
68 {
69         int ret = 0;
70         int yy, uu, vv;
71         int r,g,b;
72         int total = width * height / 2 + 1;
73
74         while ( --total )
75         {
76                 yy = yuv[0];
77                 uu = yuv[1];
78                 vv = yuv[3];
79                 YUV2RGB_601( yy, uu, vv, r, g, b );
80                 rgba[0] = r;
81                 rgba[1] = g;
82                 rgba[2] = b;
83                 rgba[3] = *alpha++;
84                 yy = yuv[2];
85                 YUV2RGB_601( yy, uu, vv, r, g, b );
86                 rgba[4] = r;
87                 rgba[5] = g;
88                 rgba[6] = b;
89                 rgba[7] = *alpha++;
90                 yuv += 4;
91                 rgba += 8;
92         }
93         return ret;
94 }
95
96 static int convert_yuv422_to_rgb24( uint8_t *yuv, uint8_t *rgb, uint8_t *alpha, int width, int height )
97 {
98         int ret = 0;
99         int yy, uu, vv;
100         int r,g,b;
101         int total = width * height / 2 + 1;
102
103         while ( --total )
104         {
105                 yy = yuv[0];
106                 uu = yuv[1];
107                 vv = yuv[3];
108                 YUV2RGB_601( yy, uu, vv, r, g, b );
109                 rgb[0] = r;
110                 rgb[1] = g;
111                 rgb[2] = b;
112                 yy = yuv[2];
113                 YUV2RGB_601( yy, uu, vv, r, g, b );
114                 rgb[3] = r;
115                 rgb[4] = g;
116                 rgb[5] = b;
117                 yuv += 4;
118                 rgb += 6;
119         }
120         return ret;
121 }
122
123 static int convert_rgb24a_to_yuv422( uint8_t *rgba, uint8_t *yuv, uint8_t *alpha, int width, int height )
124 {
125         int ret = 0;
126         int stride = width * 4;
127         int y0, y1, u0, u1, v0, v1;
128         int r, g, b;
129         uint8_t *s, *d = yuv;
130         int i, j, n = width / 2 + 1;
131
132         if ( alpha )
133         for ( i = 0; i < height; i++ )
134         {
135                 s = rgba + ( stride * i );
136                 j = n;
137                 while ( --j )
138                 {
139                         r = *s++;
140                         g = *s++;
141                         b = *s++;
142                         *alpha++ = *s++;
143                         RGB2YUV_601( r, g, b, y0, u0 , v0 );
144                         r = *s++;
145                         g = *s++;
146                         b = *s++;
147                         *alpha++ = *s++;
148                         RGB2YUV_601( r, g, b, y1, u1 , v1 );
149                         *d++ = y0;
150                         *d++ = (u0+u1) >> 1;
151                         *d++ = y1;
152                         *d++ = (v0+v1) >> 1;
153                 }
154                 if ( width % 2 )
155                 {
156                         r = *s++;
157                         g = *s++;
158                         b = *s++;
159                         *alpha++ = *s++;
160                         RGB2YUV_601( r, g, b, y0, u0 , v0 );
161                         *d++ = y0;
162                         *d++ = u0;
163                 }
164         }
165         else
166         for ( i = 0; i < height; i++ )
167         {
168                 s = rgba + ( stride * i );
169                 j = n;
170                 while ( --j )
171                 {
172                         r = *s++;
173                         g = *s++;
174                         b = *s++;
175                         s++;
176                         RGB2YUV_601( r, g, b, y0, u0 , v0 );
177                         r = *s++;
178                         g = *s++;
179                         b = *s++;
180                         s++;
181                         RGB2YUV_601( r, g, b, y1, u1 , v1 );
182                         *d++ = y0;
183                         *d++ = (u0+u1) >> 1;
184                         *d++ = y1;
185                         *d++ = (v0+v1) >> 1;
186                 }
187                 if ( width % 2 )
188                 {
189                         r = *s++;
190                         g = *s++;
191                         b = *s++;
192                         s++;
193                         RGB2YUV_601( r, g, b, y0, u0 , v0 );
194                         *d++ = y0;
195                         *d++ = u0;
196                 }
197         }
198
199         return ret;
200 }
201
202 static int convert_rgb24_to_yuv422( uint8_t *rgb, uint8_t *yuv, uint8_t *alpha, int width, int height )
203 {
204         int ret = 0;
205         int stride = width * 3;
206         int y0, y1, u0, u1, v0, v1;
207         int r, g, b;
208         uint8_t *s, *d = yuv;
209         int i, j, n = width / 2 + 1;
210
211         for ( i = 0; i < height; i++ )
212         {
213                 s = rgb + ( stride * i );
214                 j = n;
215                 while ( --j )
216                 {
217                         r = *s++;
218                         g = *s++;
219                         b = *s++;
220                         RGB2YUV_601( r, g, b, y0, u0 , v0 );
221                         r = *s++;
222                         g = *s++;
223                         b = *s++;
224                         RGB2YUV_601( r, g, b, y1, u1 , v1 );
225                         *d++ = y0;
226                         *d++ = (u0+u1) >> 1;
227                         *d++ = y1;
228                         *d++ = (v0+v1) >> 1;
229                 }
230                 if ( width % 2 )
231                 {
232                         r = *s++;
233                         g = *s++;
234                         b = *s++;
235                         RGB2YUV_601( r, g, b, y0, u0 , v0 );
236                         *d++ = y0;
237                         *d++ = u0;
238                 }
239         }
240         return ret;
241 }
242
243 static int convert_yuv420p_to_yuv422( uint8_t *yuv420p, uint8_t *yuv, uint8_t *alpha, int width, int height )
244 {
245         int ret = 0;
246         int i, j;
247         int half = width >> 1;
248         uint8_t *Y = yuv420p;
249         uint8_t *U = Y + width * height;
250         uint8_t *V = U + width * height / 4;
251         uint8_t *d = yuv;
252
253         for ( i = 0; i < height; i++ )
254         {
255                 uint8_t *u = U + ( i / 2 ) * ( half );
256                 uint8_t *v = V + ( i / 2 ) * ( half );
257
258                 j = half + 1;
259                 while ( --j )
260                 {
261                         *d ++ = *Y ++;
262                         *d ++ = *u ++;
263                         *d ++ = *Y ++;
264                         *d ++ = *v ++;
265                 }
266         }
267         return ret;
268 }
269
270 static int convert_rgb24_to_rgb24a( uint8_t *rgb, uint8_t *rgba, uint8_t *alpha, int width, int height )
271 {
272         uint8_t *s = rgb;
273         uint8_t *d = rgba;
274         int total = width * height + 1;
275
276         while ( --total )
277         {
278                 *d++ = s[0];
279                 *d++ = s[1];
280                 *d++ = s[2];
281                 *d++ = 0xff;
282                 s += 3;
283         }
284         return 0;
285 }
286
287 static int convert_rgb24a_to_rgb24( uint8_t *rgba, uint8_t *rgb, uint8_t *alpha, int width, int height )
288 {
289         uint8_t *s = rgba;
290         uint8_t *d = rgb;
291         int total = width * height + 1;
292
293         while ( --total )
294         {
295                 *d++ = s[0];
296                 *d++ = s[1];
297                 *d++ = s[2];
298                 *alpha++ = s[3];
299                 s += 4;
300         }
301         return 0;
302 }
303
304 typedef int ( *conversion_function )( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height );
305
306 static conversion_function conversion_matrix[5][5] = {
307         { NULL, convert_rgb24_to_rgb24a, convert_rgb24_to_yuv422, NULL, convert_rgb24_to_rgb24a },
308         { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL },
309         { convert_yuv422_to_rgb24, convert_yuv422_to_rgb24a, NULL, NULL, convert_yuv422_to_rgb24a },
310         { NULL, NULL, convert_yuv420p_to_yuv422, NULL, NULL },
311         { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL },
312 };
313
314 static uint8_t bpp_table[4] = { 3, 4, 2, 0 };
315
316 static int convert_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, mlt_image_format requested_format )
317 {
318         int error = 0;
319         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
320         int width = mlt_properties_get_int( properties, "width" );
321         int height = mlt_properties_get_int( properties, "height" );
322
323         if ( *format != requested_format )
324         {
325                 conversion_function converter = conversion_matrix[ *format - 1 ][ requested_format - 1 ];
326
327                 mlt_log_debug( NULL, "[filter imageconvert] %s -> %s @ %dx%d\n",
328                         mlt_image_format_name( *format ), mlt_image_format_name( requested_format ),
329                         width, height );
330                 if ( converter )
331                 {
332                         int size = width * height * bpp_table[ requested_format - 1 ];
333                         int alpha_size = width * height;
334                         uint8_t *image = mlt_pool_alloc( size );
335                         uint8_t *alpha = ( *format == mlt_image_rgb24a ||
336                                            *format == mlt_image_opengl )
337                                          ? mlt_pool_alloc( width * height ) : NULL;
338                         if ( requested_format == mlt_image_rgb24a || requested_format == mlt_image_opengl )
339                         {
340                                 if ( alpha )
341                                         mlt_pool_release( alpha );
342                                 alpha = mlt_frame_get_alpha_mask( frame );
343                                 mlt_properties_get_data( properties, "alpha", &alpha_size );
344                         }
345
346                         if ( !( error = converter( *buffer, image, alpha, width, height ) ) )
347                         {
348                                 mlt_frame_set_image( frame, image, size, mlt_pool_release );
349                                 if ( alpha && ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) )
350                                         mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release );
351                                 *buffer = image;
352                                 *format = requested_format;
353                         }
354                         else
355                         {
356                                 mlt_pool_release( image );
357                                 if ( alpha )
358                                         mlt_pool_release( alpha );
359                         }
360                 }
361                 else
362                 {
363                         error = 1;
364                 }
365         }
366
367         return error;
368 }
369
370 /** Filter processing.
371 */
372
373 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
374 {
375         if ( !frame->convert_image )
376                 frame->convert_image = convert_image;
377         return frame;
378 }
379
380 /** Constructor for the filter.
381 */
382
383 mlt_filter filter_imageconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
384 {
385         mlt_filter this = calloc( 1, sizeof( struct mlt_filter_s ) );
386         if ( mlt_filter_init( this, this ) == 0 )
387         {
388                 this->process = filter_process;
389         }
390         return this;
391 }