]> git.sesse.net Git - mlt/blob - src/modules/opengl/filter_movit_resize.cpp
32f47c2a59af24a94626411d15b5ffbbf722dd27
[mlt] / src / modules / opengl / filter_movit_resize.cpp
1 /*
2  * filter_movit_resize.cpp
3  * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <framework/mlt.h>
21 #include <string.h>
22 #include <math.h>
23 #include <stdlib.h>
24 #include <assert.h>
25
26 #include "filter_glsl_manager.h"
27 #include <movit/init.h>
28 #include <movit/padding_effect.h>
29 #include "optional_effect.h"
30
31 using namespace movit;
32
33 static float alignment_parse( char* align )
34 {
35         int ret = 0.0f;
36
37         if ( align == NULL );
38         else if ( isdigit( align[ 0 ] ) )
39                 ret = atoi( align );
40         else if ( align[ 0 ] == 'c' || align[ 0 ] == 'm' )
41                 ret = 1.0f;
42         else if ( align[ 0 ] == 'r' || align[ 0 ] == 'b' )
43                 ret = 2.0f;
44
45         return ret;
46 }
47
48 static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
49 {
50         int error = 0;
51         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
52         mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
53         mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
54
55         // Retrieve the aspect ratio
56         double aspect_ratio = mlt_frame_get_aspect_ratio( frame );
57         double consumer_aspect = mlt_profile_sar( profile );
58
59         // Correct Width/height if necessary
60         if ( *width == 0 || *height == 0 )
61         {
62                 *width = profile->width;
63                 *height = profile->height;
64         }
65
66         // Assign requested width/height from our subordinate
67         int owidth = *width;
68         int oheight = *height;
69
70         // Use a mlt_rect to compute position and size
71         mlt_rect rect;
72         rect.x = rect.y = 0.0;
73         if ( mlt_properties_get( properties, "resize.rect" ) ) {
74                 mlt_position position = mlt_filter_get_position( filter, frame );
75                 mlt_position length = mlt_filter_get_length2( filter, frame );
76                 rect = mlt_properties_anim_get_rect( properties, "resize.rect", position, length );
77                 if ( strchr( mlt_properties_get( properties, "resize.rect" ), '%' ) ) {
78                         rect.x *= profile->width;
79                         rect.w *= profile->width;
80                         rect.y *= profile->height;
81                         rect.h *= profile->height;
82                 }
83                 if ( !mlt_properties_get_int( properties, "resize.fill" ) ) {
84                         int x = mlt_properties_get_int( properties, "meta.media.width" );
85                         rect.w = rect.w > x ? x : rect.w;
86                         x = mlt_properties_get_int( properties, "meta.media.height" );
87                         rect.h = rect.h > x ? x : rect.h;
88                 }
89                 owidth = lrintf( rect.w );
90                 oheight = lrintf( rect.h );
91         }
92
93         // Check for the special case - no aspect ratio means no problem :-)
94         if ( aspect_ratio == 0.0 )
95                 aspect_ratio = consumer_aspect;
96
97         // Reset the aspect ratio
98         mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio );
99
100         // Skip processing if requested.
101         char *rescale = mlt_properties_get( properties, "rescale.interp" );
102         if ( *format == mlt_image_none || ( rescale && !strcmp( rescale, "none" ) ) )
103                 return mlt_frame_get_image( frame, image, format, width, height, writable );
104
105         if ( mlt_properties_get_int( properties, "distort" ) == 0 )
106         {
107                 // Normalise the input and out display aspect
108                 int normalised_width = profile->width;
109                 int normalised_height = profile->height;
110                 int real_width = mlt_properties_get_int( properties, "meta.media.width" );
111                 int real_height = mlt_properties_get_int( properties, "meta.media.height" );
112                 if ( real_width == 0 )
113                         real_width = mlt_properties_get_int( properties, "width" );
114                 if ( real_height == 0 )
115                         real_height = mlt_properties_get_int( properties, "height" );
116                 double input_ar = aspect_ratio * real_width / real_height;
117                 double output_ar = consumer_aspect * owidth / oheight;
118                 
119                 // Optimised for the input_ar > output_ar case (e.g. widescreen on standard)
120                 int scaled_width = lrint( ( input_ar * normalised_width ) / output_ar );
121                 int scaled_height = normalised_height;
122
123                 // Now ensure that our images fit in the output frame
124                 if ( scaled_width > normalised_width )
125                 {
126                         scaled_width = normalised_width;
127                         scaled_height = lrint( ( output_ar * normalised_height ) / input_ar );
128                 }
129
130                 // Now calculate the actual image size that we want
131                 owidth = lrint( scaled_width * owidth / normalised_width );
132                 oheight = lrint( scaled_height * oheight / normalised_height );
133
134                 mlt_log_debug( MLT_FILTER_SERVICE(filter),
135                         "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n",
136                         real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar);
137
138                 // Tell frame we have conformed the aspect to the consumer
139                 mlt_frame_set_aspect_ratio( frame, consumer_aspect );
140         }
141
142         mlt_properties_set_int( properties, "distort", 0 );
143
144         // Now get the image
145         *format = mlt_image_glsl;
146         error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable );
147
148         // Offset the position according to alignment
149         float w = float( *width - owidth );
150         float h = float( *height - oheight );
151         if ( mlt_properties_get( properties, "resize.rect" ) ) {
152                 // default left if rect supplied
153                 rect.x += w * alignment_parse( mlt_properties_get( properties, "resize.halign" ) ) / 2.0f;
154                 rect.y += h * alignment_parse( mlt_properties_get( properties, "resize.valign" ) ) / 2.0f;
155         } else {
156                 // default center if no rect
157                 rect.x = w * 0.5f;
158                 rect.y = h * 0.5f;
159         }
160
161         if ( !error ) {
162                 mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
163                 GlslManager::get_instance()->lock_service( frame );
164                 mlt_properties_set_int( filter_properties, "movit.parms.int.width", *width );
165                 mlt_properties_set_int( filter_properties, "movit.parms.int.height", *height );
166                 mlt_properties_set_double( filter_properties, "movit.parms.float.left", rect.x );
167                 mlt_properties_set_double( filter_properties, "movit.parms.float.top", rect.y );
168
169                 bool disable = ( *width == owidth && *height == oheight );
170                 mlt_properties_set_int( filter_properties, "movit.parms.int.disable", disable );
171
172                 GlslManager::get_instance()->unlock_service( frame );
173
174                 GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image );
175                 GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new OptionalEffect<PaddingEffect> );
176                 *image = (uint8_t *) MLT_FILTER_SERVICE( filter );
177                 return error;
178         }
179
180         return error;
181 }
182
183 static mlt_frame process( mlt_filter filter, mlt_frame frame )
184 {
185         mlt_frame_push_service( frame, filter );
186         mlt_frame_push_get_image( frame, get_image );
187         return frame;
188 }
189
190 extern "C"
191 mlt_filter filter_movit_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
192 {
193         mlt_filter filter = NULL;
194         GlslManager* glsl = GlslManager::get_instance();
195
196         if ( glsl && ( filter = mlt_filter_new() ) )
197         {
198                 mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
199                 glsl->add_ref( properties );
200                 filter->process = process;
201         }
202         return filter;
203 }