]> git.sesse.net Git - mlt/blob - src/modules/avformat/filter_avcolour_space.c
Massive refactoring of image conversion.
[mlt] / src / modules / avformat / filter_avcolour_space.c
1 /*
2  * filter_avcolour_space.c -- Colour space filter
3  * Copyright (C) 2004-2005 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
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
25 // ffmpeg Header files
26 #include <avformat.h>
27 #ifdef SWSCALE
28 #include <swscale.h>
29 #endif
30
31 #if LIBAVUTIL_VERSION_INT < (50<<16)
32 #define PIX_FMT_YUYV422 PIX_FMT_YUV422
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 static inline int is_big_endian( )
39 {
40         union { int i; char c[ 4 ]; } big_endian_test;
41         big_endian_test.i = 1;
42
43         return big_endian_test.c[ 0 ] != 1;
44 }
45
46 static inline int convert_mlt_to_av_cs( mlt_image_format format )
47 {
48         int value = 0;
49
50         switch( format )
51         {
52                 case mlt_image_rgb24:
53                         value = PIX_FMT_RGB24;
54                         break;
55                 case mlt_image_rgb24a:
56                 case mlt_image_opengl:
57                         value = PIX_FMT_RGBA;
58                         break;
59                 case mlt_image_yuv422:
60                         value = PIX_FMT_YUYV422;
61                         break;
62                 case mlt_image_yuv420p:
63                         value = PIX_FMT_YUV420P;
64                         break;
65                 case mlt_image_none:
66                         mlt_log_error( NULL, "[filter avcolour_space] Invalid format\n" );
67                         break;
68         }
69
70         return value;
71 }
72
73 static inline void av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt, int width, int height )
74 {
75         AVPicture input;
76         AVPicture output;
77         avpicture_fill( &input, in, in_fmt, width, height );
78         avpicture_fill( &output, out, out_fmt, width, height );
79 #ifdef SWSCALE
80         struct SwsContext *context = sws_getContext( width, height, in_fmt,
81                 width, height, out_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
82         sws_scale( context, input.data, input.linesize, 0, height,
83                 output.data, output.linesize);
84         sws_freeContext( context );
85 #else
86         img_convert( &output, out_fmt, &input, in_fmt, width, height );
87 #endif
88 }
89
90 /** Do it :-).
91 */
92
93 // static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
94 static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format )
95 {
96         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
97         int width = mlt_properties_get_int( properties, "width" );
98         int height = mlt_properties_get_int( properties, "height" );
99         int error = 0;
100
101         if ( *format != output_format )
102         {
103                 mlt_log_debug( NULL, "[filter avcolour_space] %s -> %s\n",
104                         mlt_image_format_name( *format ), mlt_image_format_name( output_format ) );
105                 if ( output_format != mlt_image_opengl )
106                 {
107                         int in_fmt = convert_mlt_to_av_cs( *format );
108                         int out_fmt = convert_mlt_to_av_cs( output_format );
109                         int size = avpicture_get_size( out_fmt, width, height );
110                         uint8_t *output = mlt_pool_alloc( size );
111                         av_convert_image( output, *image, out_fmt, in_fmt, width, height );
112         
113                         // Special case for alpha rgb input
114                         //if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl )
115 if (0)
116                         {
117                                 register uint8_t *alpha = mlt_frame_get_alpha_mask( frame );
118                                 register int len = width * height;
119                                 register uint8_t *bits = *image;
120                                 register int n = ( len + 7 ) / 8;
121         
122                                 if( !is_big_endian( ) )
123                                         bits += 3;
124         
125                                 // Extract alpha mask from the image using Duff's Device
126                                 switch( len % 8 )
127                                 {
128                                         case 0: do { *alpha ++ = *bits; bits += 4;
129                                         case 7:          *alpha ++ = *bits; bits += 4;
130                                         case 6:          *alpha ++ = *bits; bits += 4;
131                                         case 5:          *alpha ++ = *bits; bits += 4;
132                                         case 4:          *alpha ++ = *bits; bits += 4;
133                                         case 3:          *alpha ++ = *bits; bits += 4;
134                                         case 2:          *alpha ++ = *bits; bits += 4;
135                                         case 1:          *alpha ++ = *bits; bits += 4;
136                                                         }
137                                                         while( --n );
138                                 }
139                         }
140         
141                         // Update the output
142                         *image = output;
143                         *format = output_format;
144                         mlt_properties_set_data( properties, "image", output, size, mlt_pool_release, NULL );
145                         mlt_properties_set_int( properties, "format", output_format );
146         
147                         // Special case for alpha rgb output
148 //                      if ( output_format == mlt_image_rgb24a )
149 if (0)
150                         {
151                                 // Fetch the alpha
152                                 register uint8_t *alpha = mlt_frame_get_alpha_mask( frame );
153         
154                                 if ( alpha != NULL )
155                                 {
156                                         register uint8_t *bits = *image;
157                                         register int len = width * height;
158                                         register int n = ( len + 7 ) / 8;
159                                         
160                                         if( !is_big_endian( ) )
161                                                 bits += 3;
162         
163                                         // Merge the alpha mask into the RGB image using Duff's Device
164                                         switch( len % 8 )
165                                         {
166                                                 case 0: do { *bits = *alpha++; bits += 4;
167                                                 case 7:          *bits = *alpha++; bits += 4;
168                                                 case 6:          *bits = *alpha++; bits += 4;
169                                                 case 5:          *bits = *alpha++; bits += 4;
170                                                 case 4:          *bits = *alpha++; bits += 4;
171                                                 case 3:          *bits = *alpha++; bits += 4;
172                                                 case 2:          *bits = *alpha++; bits += 4;
173                                                 case 1:          *bits = *alpha++; bits += 4;
174                                                                 }
175                                                                 while( --n );
176                                         }
177                                 }
178                         }
179                 }
180                 else if ( *format == mlt_image_yuv422 ) // && output_format == mlt_image_opengl
181                 {
182                         int size = width * height * 4;
183                         uint8_t *output = mlt_pool_alloc( size );
184                         int h = height;
185                         int w = width;
186                         uint8_t *o = output + size;
187                         int ostride = w * 4;
188                         uint8_t *p = *image;
189                         uint8_t *alpha = mlt_frame_get_alpha_mask( frame ) + width * height;
190                         int r, g, b;
191
192                         while( h -- )
193                         {
194                                 w = width;
195                                 o -= ostride;
196                                 alpha -= width;
197                                 while( w >= 2 )
198                                 {
199                                         YUV2RGB( *p, *( p + 1 ), *( p + 3 ), r, g, b );
200                                         *o ++ = r;
201                                         *o ++ = g;
202                                         *o ++ = b;
203                                         *o ++ = *alpha ++;
204                                         YUV2RGB( *( p + 2 ), *( p + 1 ), *( p + 3 ), r, g, b );
205                                         *o ++ = r;
206                                         *o ++ = g;
207                                         *o ++ = b;
208                                         *o ++ = *alpha ++;
209                                         w -= 2;
210                                         p += 4;
211                                 }
212                                 o -= ostride;
213                                 alpha -= width;
214                         }
215
216                         mlt_properties_set_data( properties, "image", output, size, mlt_pool_release, NULL );
217                         mlt_properties_set_int( properties, "format", output_format );
218                         *image = output;
219                         *format = output_format;
220                 }
221         }
222         return error;
223 }
224
225 /** Filter processing.
226 */
227
228 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
229 {
230         frame->convert_image = convert_image;
231         return frame;
232 }
233
234 /** Constructor for the filter.
235 */
236
237 mlt_filter filter_avcolour_space_init( void *arg )
238 {
239         mlt_filter this = mlt_filter_new( );
240         if ( this != NULL )
241                 this->process = filter_process;
242         return this;
243 }
244