2 * filter_movit_resize.cpp
3 * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
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.
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.
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.
20 #include <framework/mlt.h>
26 #include "filter_glsl_manager.h"
27 #include <movit/init.h>
28 #include <movit/padding_effect.h>
30 static float alignment_parse( char* align )
35 else if ( isdigit( align[ 0 ] ) )
37 else if ( align[ 0 ] == 'c' || align[ 0 ] == 'm' )
39 else if ( align[ 0 ] == 'r' || align[ 0 ] == 'b' )
45 static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
48 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
49 mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
50 mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
52 // Retrieve the aspect ratio
53 double aspect_ratio = mlt_frame_get_aspect_ratio( frame );
54 double consumer_aspect = mlt_profile_sar( profile );
56 // Correct Width/height if necessary
57 if ( *width == 0 || *height == 0 )
59 *width = profile->width;
60 *height = profile->height;
63 // Assign requested width/height from our subordinate
65 int oheight = *height;
67 // Use a mlt_rect to compute position and size
69 rect.x = rect.y = 0.0;
70 if ( mlt_properties_get( properties, "resize.rect" ) ) {
71 mlt_position position = mlt_filter_get_position( filter, frame );
72 mlt_position length = mlt_filter_get_length2( filter, frame );
73 rect = mlt_properties_anim_get_rect( properties, "resize.rect", position, length );
74 if ( strchr( mlt_properties_get( properties, "resize.rect" ), '%' ) ) {
75 rect.x *= profile->width;
76 rect.w *= profile->width;
77 rect.y *= profile->height;
78 rect.h *= profile->height;
80 if ( !mlt_properties_get_int( properties, "resize.fill" ) ) {
81 int x = mlt_properties_get_int( properties, "meta.media.width" );
82 rect.w = rect.w > x ? x : rect.w;
83 x = mlt_properties_get_int( properties, "meta.media.height" );
84 rect.h = rect.h > x ? x : rect.h;
86 owidth = lrintf( rect.w );
87 oheight = lrintf( rect.h );
90 // Check for the special case - no aspect ratio means no problem :-)
91 if ( aspect_ratio == 0.0 )
92 aspect_ratio = consumer_aspect;
94 // Reset the aspect ratio
95 mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio );
97 // Skip processing if requested.
98 char *rescale = mlt_properties_get( properties, "rescale.interp" );
99 if ( *format == mlt_image_none || ( rescale && !strcmp( rescale, "none" ) ) )
100 return mlt_frame_get_image( frame, image, format, width, height, writable );
102 if ( mlt_properties_get_int( properties, "distort" ) == 0 )
104 // Normalise the input and out display aspect
105 int normalised_width = profile->width;
106 int normalised_height = profile->height;
107 int real_width = mlt_properties_get_int( properties, "meta.media.width" );
108 int real_height = mlt_properties_get_int( properties, "meta.media.height" );
109 if ( real_width == 0 )
110 real_width = mlt_properties_get_int( properties, "width" );
111 if ( real_height == 0 )
112 real_height = mlt_properties_get_int( properties, "height" );
113 double input_ar = aspect_ratio * real_width / real_height;
114 double output_ar = consumer_aspect * owidth / oheight;
116 // Optimised for the input_ar > output_ar case (e.g. widescreen on standard)
117 int scaled_width = lrint( ( input_ar * normalised_width ) / output_ar );
118 int scaled_height = normalised_height;
120 // Now ensure that our images fit in the output frame
121 if ( scaled_width > normalised_width )
123 scaled_width = normalised_width;
124 scaled_height = lrint( ( output_ar * normalised_height ) / input_ar );
127 // Now calculate the actual image size that we want
128 owidth = lrint( scaled_width * owidth / normalised_width );
129 oheight = lrint( scaled_height * oheight / normalised_height );
131 mlt_log_debug( MLT_FILTER_SERVICE(filter),
132 "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n",
133 real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar);
135 // Tell frame we have conformed the aspect to the consumer
136 mlt_frame_set_aspect_ratio( frame, consumer_aspect );
139 mlt_properties_set_int( properties, "distort", 0 );
142 *format = mlt_image_glsl;
143 error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable );
145 // Offset the position according to alignment
146 float w = float( *width - owidth );
147 float h = float( *height - oheight );
148 if ( mlt_properties_get( properties, "resize.rect" ) ) {
149 // default left if rect supplied
150 rect.x += w * alignment_parse( mlt_properties_get( properties, "resize.halign" ) ) / 2.0f;
151 rect.y += h * alignment_parse( mlt_properties_get( properties, "resize.valign" ) ) / 2.0f;
153 // default center if no rect
159 GlslManager::get_instance()->lock_service( frame );
160 Effect* effect = GlslManager::get_effect( filter, frame );
162 bool ok = effect->set_int( "width", *width );
163 ok |= effect->set_int( "height", *height );
164 ok |= effect->set_float( "left", rect.x );
165 ok |= effect->set_float( "top", rect.y );
168 GlslManager::get_instance()->unlock_service( frame );
174 static mlt_frame process( mlt_filter filter, mlt_frame frame )
176 if ( !GlslManager::get_effect( filter, frame ) )
177 GlslManager::add_effect( filter, frame, new PaddingEffect );
178 mlt_frame_push_service( frame, filter );
179 mlt_frame_push_get_image( frame, get_image );
184 mlt_filter filter_movit_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
186 mlt_filter filter = NULL;
187 GlslManager* glsl = GlslManager::get_instance();
189 if ( glsl && ( filter = mlt_filter_new() ) )
191 filter->process = process;