]> git.sesse.net Git - mlt/blob - src/modules/core/filter_imageconvert.c
dc07db72162ebc8ad8045167fc4a704486cfc9cc
[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
29 static int convert_yuv422_to_rgb24a( uint8_t *yuv, uint8_t *rgba, unsigned int total )
30 {
31         int ret = 0;
32         int yy, uu, vv;
33         int r,g,b;
34         total /= 2;
35         while (total--)
36         {
37                 yy = yuv[0];
38                 uu = yuv[1];
39                 vv = yuv[3];
40                 YUV2RGB(yy, uu, vv, r, g, b);
41                 rgba[0] = r;
42                 rgba[1] = g;
43                 rgba[2] = b;
44                 rgba[3] = 255;
45                 yy = yuv[2];
46                 YUV2RGB(yy, uu, vv, r, g, b);
47                 rgba[4] = r;
48                 rgba[5] = g;
49                 rgba[6] = b;
50                 rgba[7] = 255;
51                 yuv += 4;
52                 rgba += 8;
53         }
54         return ret;
55 }
56
57 static int convert_yuv422_to_rgb24( uint8_t *yuv, uint8_t *rgb, unsigned int total )
58 {
59         int ret = 0;
60         int yy, uu, vv;
61         int r,g,b;
62         total /= 2;
63         while (total--) 
64         {
65                 yy = yuv[0];
66                 uu = yuv[1];
67                 vv = yuv[3];
68                 YUV2RGB(yy, uu, vv, r, g, b);
69                 rgb[0] = r;
70                 rgb[1] = g;
71                 rgb[2] = b;
72                 yy = yuv[2];
73                 YUV2RGB(yy, uu, vv, r, g, b);
74                 rgb[3] = r;
75                 rgb[4] = g;
76                 rgb[5] = b;
77                 yuv += 4;
78                 rgb += 6;
79         }
80         return ret;
81 }
82
83 static int convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha )
84 {
85         int ret = 0;
86         register int y0, y1, u0, u1, v0, v1;
87         register int r, g, b;
88         register uint8_t *d = yuv;
89         register int i, j;
90
91         if ( alpha )
92         for ( i = 0; i < height; i++ )
93         {
94                 register uint8_t *s = rgba + ( stride * i );
95                 for ( j = 0; j < ( width / 2 ); j++ )
96                 {
97                         r = *s++;
98                         g = *s++;
99                         b = *s++;
100                         *alpha++ = *s++;
101                         RGB2YUV (r, g, b, y0, u0 , v0);
102                         r = *s++;
103                         g = *s++;
104                         b = *s++;
105                         *alpha++ = *s++;
106                         RGB2YUV (r, g, b, y1, u1 , v1);
107                         *d++ = y0;
108                         *d++ = (u0+u1) >> 1;
109                         *d++ = y1;
110                         *d++ = (v0+v1) >> 1;
111                 }
112                 if ( width % 2 )
113                 {
114                         r = *s++;
115                         g = *s++;
116                         b = *s++;
117                         *alpha++ = *s++;
118                         RGB2YUV (r, g, b, y0, u0 , v0);
119                         *d++ = y0;
120                         *d++ = u0;
121                 }
122         }
123         else
124         for ( i = 0; i < height; i++ )
125         {
126                 register uint8_t *s = rgba + ( stride * i );
127                 for ( j = 0; j < ( width / 2 ); j++ )
128                 {
129                         r = *s++;
130                         g = *s++;
131                         b = *s++;
132                         s++;
133                         RGB2YUV (r, g, b, y0, u0 , v0);
134                         r = *s++;
135                         g = *s++;
136                         b = *s++;
137                         s++;
138                         RGB2YUV (r, g, b, y1, u1 , v1);
139                         *d++ = y0;
140                         *d++ = (u0+u1) >> 1;
141                         *d++ = y1;
142                         *d++ = (v0+v1) >> 1;
143                 }
144                 if ( width % 2 )
145                 {
146                         r = *s++;
147                         g = *s++;
148                         b = *s++;
149                         s++;
150                         RGB2YUV (r, g, b, y0, u0 , v0);
151                         *d++ = y0;
152                         *d++ = u0;
153                 }
154         }
155
156         return ret;
157 }
158
159 static int convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv )
160 {
161         int ret = 0;
162         register int y0, y1, u0, u1, v0, v1;
163         register int r, g, b;
164         register uint8_t *d = yuv;
165         register int i, j;
166
167         for ( i = 0; i < height; i++ )
168         {
169                 register uint8_t *s = rgb + ( stride * i );
170                 for ( j = 0; j < ( width / 2 ); j++ )
171                 {
172                         r = *s++;
173                         g = *s++;
174                         b = *s++;
175                         RGB2YUV (r, g, b, y0, u0 , v0);
176                         r = *s++;
177                         g = *s++;
178                         b = *s++;
179                         RGB2YUV (r, g, b, y1, u1 , v1);
180                         *d++ = y0;
181                         *d++ = (u0+u1) >> 1;
182                         *d++ = y1;
183                         *d++ = (v0+v1) >> 1;
184                 }
185                 if ( width % 2 )
186                 {
187                         r = *s++;
188                         g = *s++;
189                         b = *s++;
190                         RGB2YUV (r, g, b, y0, u0 , v0);
191                         *d++ = y0;
192                         *d++ = u0;
193                 }
194         }
195         return ret;
196 }
197
198 static int convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, uint8_t *yuv )
199 {
200         int ret = 0;
201         register int i, j;
202
203         int half = width >> 1;
204
205         uint8_t *Y = yuv420p;
206         uint8_t *U = Y + width * height;
207         uint8_t *V = U + width * height / 4;
208
209         register uint8_t *d = yuv;
210
211         for ( i = 0; i < height; i++ )
212         {
213                 register uint8_t *u = U + ( i / 2 ) * ( half );
214                 register uint8_t *v = V + ( i / 2 ) * ( half );
215
216                 for ( j = 0; j < half; j++ )
217                 {
218                         *d ++ = *Y ++;
219                         *d ++ = *u ++;
220                         *d ++ = *Y ++;
221                         *d ++ = *v ++;
222                 }
223         }
224         return ret;
225 }
226
227 static int convert_rgb24_to_rgb24a( uint8_t *rgb, uint8_t *rgba, int total )
228 {
229         uint8_t *s = rgb;
230         uint8_t *d = rgba;
231         while ( total-- )
232         {
233                 *d++ = s[0];
234                 *d++ = s[1];
235                 *d++ = s[2];
236                 *d++ = 0xff;
237                 s += 3;
238         }
239         return 0;
240 }
241
242 static int convert_rgb24a_to_rgb24( uint8_t *rgba, uint8_t *rgb, int total, uint8_t *alpha )
243 {
244         uint8_t *s = rgba;
245         uint8_t *d = rgb;
246         while ( total-- )
247         {
248                 *d++ = s[0];
249                 *d++ = s[1];
250                 *d++ = s[2];
251                 *alpha++ = s[3];
252                 s += 4;
253         }
254         return 0;
255 }
256
257 static int convert_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, mlt_image_format requested_format )
258 {
259         int error = 0;
260         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
261         int width = mlt_properties_get_int( properties, "width" );
262         int height = mlt_properties_get_int( properties, "height" );
263
264         if ( *format != requested_format )
265         {
266                 mlt_log_debug( NULL, "[filter imageconvert] %s -> %s\n",
267                         mlt_image_format_name( *format ), mlt_image_format_name( requested_format ) );
268                 switch ( *format )
269                 {
270                 case mlt_image_yuv422:
271                         switch ( requested_format )
272                         {
273                         case mlt_image_rgb24:
274                         {
275                                 uint8_t *rgb = mlt_pool_alloc( width * height * 3 );
276                                 error = convert_yuv422_to_rgb24( *buffer, rgb, width * height );
277                                 if ( error )
278                                 {
279                                         mlt_pool_release( rgb );
280                                 }
281                                 else
282                                 {
283                                         mlt_properties_set_data( properties, "image", rgb, width * height * 3, mlt_pool_release, NULL );
284                                         *buffer = rgb;
285                                         *format = mlt_image_rgb24;
286                                 }
287                                 break;
288                         }
289                         case mlt_image_rgb24a:
290                         case mlt_image_opengl:
291                         {
292                                 uint8_t *rgba = mlt_pool_alloc( width * height * 4 );
293                                 error = convert_yuv422_to_rgb24a( *buffer, rgba, width * height );
294                                 if ( error )
295                                 {
296                                         mlt_pool_release( rgba );
297                                 }
298                                 else
299                                 {
300                                         mlt_properties_set_data( properties, "image", rgba, width * height * 4, mlt_pool_release, NULL );
301                                         *buffer = rgba;
302                                         *format = requested_format;
303                                 }
304                                 break;
305                         }
306                         default:
307                                 error = 1;
308                         }
309                         break;
310                 case mlt_image_rgb24:
311                         switch ( requested_format )
312                         {
313                         case mlt_image_yuv422:
314                         {
315                                 uint8_t *yuv = mlt_pool_alloc( width * height * 2 );
316                                 error = convert_rgb24_to_yuv422( *buffer, width, height, width * 3, yuv );
317                                 if ( error )
318                                 {
319                                         mlt_pool_release( yuv );
320                                 }
321                                 else
322                                 {
323                                         mlt_properties_set_data( properties, "image", yuv, width * height * 2, mlt_pool_release, NULL );
324                                         *buffer = yuv;
325                                         *format = mlt_image_yuv422;
326                                 }
327                                 break;
328                         }
329                         case mlt_image_rgb24a:
330                         case mlt_image_opengl:
331                         {
332                                 uint8_t *rgba = mlt_pool_alloc( width * height * 4 );
333                                 error = convert_rgb24_to_rgb24a( *buffer, rgba, width * height );
334                                 if ( error )
335                                 {
336                                         mlt_pool_release( rgba );
337                                 }
338                                 else
339                                 {
340                                         mlt_properties_set_data( properties, "image", rgba, width * height * 4, mlt_pool_release, NULL );
341                                         *buffer = rgba;
342                                         *format = requested_format;
343                                 }
344                                 break;
345                         }
346                         default:
347                                 error = 1;
348                         }
349                         break;
350                 case mlt_image_rgb24a:
351                 case mlt_image_opengl:
352                         switch ( requested_format )
353                         {
354                         case mlt_image_yuv422:
355                         {
356                                 uint8_t *yuv = mlt_pool_alloc( width * height * 2 );
357                                 uint8_t *alpha = mlt_pool_alloc( width * height );
358                                 error = convert_rgb24a_to_yuv422( *buffer, width, height, width * 4, yuv, alpha );
359                                 if ( error )
360                                 {
361                                         mlt_pool_release( yuv );
362                                         mlt_pool_release( alpha );
363                                 }
364                                 else
365                                 {
366                                         mlt_properties_set_data( properties, "image", yuv, width * height * 2, mlt_pool_release, NULL );
367                                         mlt_properties_set_data( properties, "alpha", alpha, width * height, mlt_pool_release, NULL );
368                                         *buffer = yuv;
369                                         *format = mlt_image_yuv422;
370                                 }
371                                 break;
372                         }
373                         case mlt_image_rgb24:
374                         {
375                                 uint8_t *rgb = mlt_pool_alloc( width * height * 3 );
376                                 uint8_t *alpha = mlt_pool_alloc( width * height );
377                                 error = convert_rgb24a_to_rgb24( *buffer, rgb, width * height, alpha );
378                                 if ( error )
379                                 {
380                                         mlt_pool_release( rgb );
381                                         mlt_pool_release( alpha );
382                                 }
383                                 else
384                                 {
385                                         mlt_properties_set_data( properties, "image", rgb, width * height * 3, mlt_pool_release, NULL );
386                                         mlt_properties_set_data( properties, "alpha", alpha, width * height, mlt_pool_release, NULL );
387                                         *buffer = rgb;
388                                         *format = mlt_image_rgb24;
389                                 }
390                                 break;
391                         }
392                         case mlt_image_rgb24a:
393                         case mlt_image_opengl:
394                                 *format = requested_format;
395                                 break;
396                         default:
397                                 error = 1;
398                         }
399                         break;
400                 case mlt_image_yuv420p:
401                         switch ( requested_format )
402                         {
403                         case mlt_image_rgb24:
404                         case mlt_image_rgb24a:
405                         case mlt_image_opengl:
406                         case mlt_image_yuv422:
407                         {
408                                 uint8_t *yuv = mlt_pool_alloc( width * height * 2 );
409                                 int error = convert_yuv420p_to_yuv422( *buffer, width, height, yuv );
410                                 if ( error )
411                                 {
412                                         mlt_pool_release( yuv );
413                                 }
414                                 else
415                                 {
416                                         mlt_properties_set_data( properties, "image", yuv, width * height * 2, mlt_pool_release, NULL );
417                                         *buffer = yuv;
418                                         *format = mlt_image_yuv422;
419                                 }
420                                 switch ( requested_format )
421                                 {
422                                 case mlt_image_yuv422:
423                                         break;
424                                 case mlt_image_rgb24:
425                                 case mlt_image_rgb24a:
426                                 case mlt_image_opengl:
427                                         error = convert_image( frame, buffer, format, requested_format );
428                                         break;
429                                 default:
430                                         error = 1;
431                                         break;
432                                 }
433                                 break;
434                         }
435                         default:
436                                 error = 1;
437                         }
438                         break;
439                 default:
440                         error = 1;
441                 }
442         }
443         if ( !error )
444                 mlt_properties_set_int( properties, "format", *format );
445
446         return error;
447 }
448
449 /** Filter processing.
450 */
451
452 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
453 {
454         frame->convert_image = convert_image;
455         return frame;
456 }
457
458 /** Constructor for the filter.
459 */
460
461 mlt_filter filter_imageconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
462 {
463         mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 );
464         if ( mlt_filter_init( this, this ) == 0 )
465         {
466                 this->process = filter_process;
467         }
468         return this;
469 }