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