]> git.sesse.net Git - mlt/blob - src/modules/avformat/filter_swscale.c
d1266aeaeed5c97d5285d915ef685ce75855a3a0
[mlt] / src / modules / avformat / filter_swscale.c
1 /*
2  * filter_swscale.c -- image scaling filter
3  * Copyright (C) 2008-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_factory.h>
24 #include <framework/mlt_factory.h>
25
26
27 // ffmpeg Header files
28 #include <avformat.h>
29 #include <swscale.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <assert.h>
35
36 #if LIBAVUTIL_VERSION_INT < (50<<16)
37 #define PIX_FMT_RGB32 PIX_FMT_RGBA32
38 #define PIX_FMT_YUYV422 PIX_FMT_YUV422
39 #endif
40
41 static inline int is_big_endian( )
42 {
43         union { int i; char c[ 4 ]; } big_endian_test;
44         big_endian_test.i = 1;
45
46         return big_endian_test.c[ 0 ] != 1;
47 }
48
49 static inline int convert_mlt_to_av_cs( mlt_image_format format )
50 {
51         int value = 0;
52
53         switch( format )
54         {
55                 case mlt_image_rgb24:
56                         value = PIX_FMT_RGB24;
57                         break;
58                 case mlt_image_rgb24a:
59                         value = PIX_FMT_RGB32;
60                         break;
61                 case mlt_image_yuv422:
62                         value = PIX_FMT_YUYV422;
63                         break;
64                 case mlt_image_yuv420p:
65                         value = PIX_FMT_YUV420P;
66                         break;
67                 case mlt_image_opengl:
68                 case mlt_image_none:
69                         fprintf( stderr, "Invalid format...\n" );
70                         break;
71         }
72
73         return value;
74 }
75
76 static int filter_scale( mlt_frame this, uint8_t **image, mlt_image_format iformat, mlt_image_format oformat, int iwidth, int iheight, int owidth, int oheight )
77 {
78         // Get the properties
79         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
80
81         // Get the requested interpolation method
82         char *interps = mlt_properties_get( properties, "rescale.interp" );
83
84         // Convert to the SwScale flag
85         int interp = SWS_BILINEAR;
86         if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 )
87                 interp = SWS_POINT;
88         else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 )
89                 interp = SWS_FAST_BILINEAR;
90         else if ( strcmp( interps, "bilinear" ) == 0 )
91                 interp = SWS_BILINEAR;
92         else if ( strcmp( interps, "bicubic" ) == 0 )
93                 interp = SWS_BICUBIC;
94         else if ( strcmp( interps, "bicublin" ) == 0 )
95                 interp = SWS_BICUBLIN;
96         else if ( strcmp( interps, "gauss" ) == 0 )
97                 interp = SWS_GAUSS;
98         else if ( strcmp( interps, "sinc" ) == 0 )
99                 interp = SWS_SINC;
100         else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "lanczos" ) == 0 )
101                 interp = SWS_LANCZOS;
102         else if ( strcmp( interps, "spline" ) == 0 )
103                 interp = SWS_SPLINE;
104
105         AVPicture input;
106         AVPicture output;
107         uint8_t *outbuf = mlt_pool_alloc( owidth * ( oheight + 1 ) * 2 );
108
109         // Convert the pixel formats
110         iformat = convert_mlt_to_av_cs( iformat );
111         oformat = convert_mlt_to_av_cs( oformat );
112
113         avpicture_fill( &input, *image, iformat, iwidth, iheight );
114         avpicture_fill( &output, outbuf, oformat, owidth, oheight );
115
116         // Extract the alpha channel
117         if ( iformat == PIX_FMT_RGB32 && oformat == PIX_FMT_YUYV422 )
118         {
119                 // Allocate the alpha mask
120                 uint8_t *alpha = mlt_pool_alloc( iwidth * ( iheight + 1 ) );
121                 if ( alpha )
122                 {
123                         // Convert the image and extract alpha
124                         mlt_convert_rgb24a_to_yuv422( *image, iwidth, iheight, iwidth * 4, outbuf, alpha );
125                         mlt_properties_set_data( properties, "alpha", alpha, iwidth * ( iheight + 1 ), ( mlt_destructor )mlt_pool_release, NULL );
126                         iformat = PIX_FMT_YUYV422;
127                         avpicture_fill( &input, outbuf, iformat, iwidth, iheight );
128                         avpicture_fill( &output, *image, oformat, owidth, oheight );
129                 }
130         }
131
132         // Create the context and output image
133         struct SwsContext *context = sws_getContext( iwidth, iheight, iformat, owidth, oheight, oformat, interp, NULL, NULL, NULL);
134         assert(context);
135
136         // Perform the scaling
137         sws_scale( context, input.data, input.linesize, 0, iheight, output.data, output.linesize);
138         sws_freeContext( context );
139
140         // Now update the frame
141         mlt_properties_set_data( properties, "image", output.data[0], owidth * ( oheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL );
142         mlt_properties_set_int( properties, "width", owidth );
143         mlt_properties_set_int( properties, "height", oheight );
144
145         // Return the output
146         *image = output.data[0];
147
148         // Scale the alpha channel only if exists and not correct size
149         int alpha_size = 0;
150         mlt_properties_get_data( properties, "alpha", &alpha_size );
151         if ( alpha_size > 0 && alpha_size != ( owidth * oheight ) )
152         {
153                 // Create the context and output image
154                 uint8_t *alpha = mlt_frame_get_alpha_mask( this );
155                 if ( alpha )
156                 {
157                         iformat = oformat = PIX_FMT_GRAY8;
158                         struct SwsContext *context = sws_getContext( iwidth, iheight, iformat, owidth, oheight, oformat, interp, NULL, NULL, NULL);
159                         avpicture_fill( &input, alpha, iformat, iwidth, iheight );
160                         outbuf = mlt_pool_alloc( owidth * oheight );
161                         avpicture_fill( &output, outbuf, oformat, owidth, oheight );
162
163                         // Perform the scaling
164                         sws_scale( context, input.data, input.linesize, 0, iheight, output.data, output.linesize);
165                         sws_freeContext( context );
166
167                         // Set it back on the frame
168                         mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "alpha", output.data[0], owidth * oheight, mlt_pool_release, NULL );
169                 }
170         }
171
172         return 0;
173 }
174
175 /** Constructor for the filter.
176 */
177
178 mlt_filter filter_swscale_init( mlt_profile profile, void *arg )
179 {
180         // Create a new scaler
181         mlt_filter this = mlt_factory_filter( profile, "rescale", arg );
182
183         // If successful, then initialise it
184         if ( this != NULL )
185         {
186                 // Get the properties
187                 mlt_properties properties = MLT_FILTER_PROPERTIES( this );
188
189                 // Set the inerpolation
190                 mlt_properties_set( properties, "interpolation", arg == NULL ? "bilinear" : arg );
191
192                 // Set the method
193                 mlt_properties_set_data( properties, "method", filter_scale, 0, NULL, NULL );
194         }
195
196         return this;
197 }