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