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