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