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