~ubuntu-branches/ubuntu/lucid/vlc/lucid-security

« back to all changes in this revision

Viewing changes to modules/video_filter/canvas.c

  • Committer: Bazaar Package Importer
  • Author(s): Benjamin Drung
  • Date: 2009-09-25 14:44:17 UTC
  • mfrom: (3.5.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090925144417-87vomt575d0agvqa
Tags: 1.0.2-1ubuntu1
* Merge from Debian unstable (LP: #435524), remaining changes:
  - build against xulrunner-dev instead of iceape-dev
  - build against libx264-dev and install libx264 plugin
  - add Xb-Npp header to vlc package
  - recommend vlc-plugin-pulse for vlc

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * canvas.c : automatically resize and padd a video to fit in canvas
3
3
 *****************************************************************************
4
4
 * Copyright (C) 2008 the VideoLAN team
5
 
 * $Id: 4b87b7ea5b07ed60582690fe9fab690d1f17a43e $
 
5
 * $Id: e6c79cd3f370738f805b1f5a9e05f1eae7a43302 $
6
6
 *
7
7
 * Authors: Antoine Cellerier <dionoea at videolan dot org>
8
8
 *
44
44
static picture_t *Filter( filter_t *, picture_t * );
45
45
static int alloc_init( filter_t *, void * );
46
46
 
47
 
#define WIDTH_TEXT N_( "Image width" )
 
47
/* This module effectively implements a form of picture-in-picture.
 
48
 *  - The outer picture is called the canvas.
 
49
 *  - The innter picture is callsed the subpicture.
 
50
 *
 
51
 * NB, all of the following operatons take into account aspect ratio
 
52
 *
 
53
 * A canvas is of canvas_{width,height}.
 
54
 * In Pad mode:
 
55
 *  - The subpicture is upconverted with a inverse scalefactor of:
 
56
 *     (The size of subpicture's largest dimension)
 
57
 *     --------------------------------------------
 
58
 *     (The size of canvas's equivalent dimension)
 
59
 *
 
60
 *   Ie, The subpicture's largest dimension is made equal to the
 
61
 *   equivalent canvas dimension.
 
62
 *
 
63
 *  - The upconverted subpicture's smallest dimension is then padded
 
64
 *    to make the upconverted subpicture have the same dimensions of
 
65
 *    the canvas.
 
66
 *
 
67
 * In Crop mode:
 
68
 *  - The subpicture is upconverted with an inverse scalefactor of:
 
69
 *     (The size of subpicture's smallest dimension)
 
70
 *     --------------------------------------------
 
71
 *     (The size of canvas's equivalent dimension)
 
72
 *
 
73
 *   Ie, The subpicture's smallest dimension is made equal to the
 
74
 *   equivalent canvas dimension. (The subpicture will then be
 
75
 *   larger than the canvas)
 
76
 *
 
77
 *  - The upconverted subpicture's largest dimension is then cropped
 
78
 *    to make the upconverted subpicture have the same dimensions of
 
79
 *    the canvas.
 
80
 */
 
81
 
 
82
/* NB, use of `padd' in this module is a 16-17th Century spelling of `pad' */
 
83
 
 
84
#define WIDTH_TEXT N_( "Output width" )
48
85
#define WIDTH_LONGTEXT N_( \
49
 
    "Image width" )
50
 
#define HEIGHT_TEXT N_( "Image height" )
 
86
    "Output (canvas) image width" )
 
87
#define HEIGHT_TEXT N_( "Output height" )
51
88
#define HEIGHT_LONGTEXT N_( \
52
 
    "Image height" )
53
 
#define ASPECT_TEXT N_( "Aspect ratio" )
 
89
    "Output (canvas) image height" )
 
90
#define ASPECT_TEXT N_( "Output picture aspect ratio" )
54
91
#define ASPECT_LONGTEXT N_( \
55
 
    "Set aspect (like 4:3) of the video canvas" )
56
 
#define PADD_TEXT N_( "Padd video" )
 
92
    "Set the canvas' picture aspect ratio. " \
 
93
    "If omitted, the canvas is assumed to have the same SAR as the input." )
 
94
#define PADD_TEXT N_( "Pad video" )
57
95
#define PADD_LONGTEXT N_( \
58
96
    "If enabled, video will be padded to fit in canvas after scaling. " \
59
97
    "Otherwise, video will be cropped to fix in canvas after scaling." )
64
102
 * Module descriptor
65
103
 *****************************************************************************/
66
104
vlc_module_begin ()
67
 
    set_description( N_("Automatically resize and padd a video") )
 
105
    set_description( N_("Automatically resize and pad a video") )
68
106
    set_capability( "video filter2", 0 )
69
107
    set_callbacks( Activate, Destroy )
70
108
 
76
114
    add_integer_with_range( CFG_PREFIX "height", 0, 0, INT_MAX, NULL,
77
115
                            HEIGHT_TEXT, HEIGHT_LONGTEXT, false )
78
116
 
79
 
    add_string( CFG_PREFIX "aspect", "4:3", NULL,
 
117
    add_string( CFG_PREFIX "aspect", NULL, NULL,
80
118
                ASPECT_TEXT, ASPECT_LONGTEXT, false )
81
119
 
82
120
    add_bool( CFG_PREFIX "padd", true, NULL,
98
136
static int Activate( vlc_object_t *p_this )
99
137
{
100
138
    filter_t *p_filter = (filter_t *)p_this;
101
 
    unsigned int i_width, i_height;
102
 
    es_format_t fmt;
 
139
    unsigned i_canvas_width; /* width of output canvas */
 
140
    unsigned i_canvas_height; /* height of output canvas */
 
141
    unsigned i_canvas_aspect; /* canvas PictureAspectRatio */
 
142
    es_format_t fmt; /* target format after up/down conversion */
103
143
    char psz_croppadd[100];
104
144
    int i_padd,i_offset;
105
145
    char *psz_aspect, *psz_parser;
106
 
    int i_aspect;
107
146
    bool b_padd;
108
147
 
109
148
    if( !p_filter->b_allow_fmt_out_change )
121
160
    config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
122
161
                       p_filter->p_cfg );
123
162
 
124
 
    i_width = var_CreateGetInteger( p_filter, CFG_PREFIX "width" );
125
 
    i_height = var_CreateGetInteger( p_filter, CFG_PREFIX "height" );
 
163
    i_canvas_width = var_CreateGetInteger( p_filter, CFG_PREFIX "width" );
 
164
    i_canvas_height = var_CreateGetInteger( p_filter, CFG_PREFIX "height" );
126
165
 
127
 
    if( i_width == 0 || i_height == 0 )
 
166
    if( i_canvas_width == 0 || i_canvas_height == 0 )
128
167
    {
129
168
        msg_Err( p_filter, "Width and height options must be set" );
130
169
        return VLC_EGENERIC;
131
170
    }
132
171
 
133
 
    if( i_width & 1 || i_height & 1 )
 
172
    if( i_canvas_width & 1 || i_canvas_height & 1 )
134
173
    {
 
174
        /* If this restriction were ever relaxed, it is very important to
 
175
         * get the field polatiry correct */
135
176
        msg_Err( p_filter, "Width and height options must be even integers" );
136
177
        return VLC_EGENERIC;
137
178
    }
138
179
 
139
180
    psz_aspect = var_CreateGetNonEmptyString( p_filter, CFG_PREFIX "aspect" );
140
 
    if( !psz_aspect )
 
181
    if( psz_aspect )
141
182
    {
142
 
        msg_Err( p_filter, "Aspect ratio must be set" );
143
 
        return VLC_EGENERIC;
 
183
        psz_parser = strchr( psz_aspect, ':' );
 
184
        int numerator = atoi( psz_aspect );
 
185
        int denominator = psz_parser ? atoi( psz_parser+1 ) : 0;
 
186
        denominator = denominator == 0 ? 1 : denominator;
 
187
        i_canvas_aspect = numerator * VOUT_ASPECT_FACTOR / denominator;
 
188
        free( psz_aspect );
 
189
 
 
190
        if( numerator <= 0 || denominator < 0 )
 
191
        {
 
192
            msg_Err( p_filter, "Aspect ratio must be strictly positive" );
 
193
            return VLC_EGENERIC;
 
194
        }
144
195
    }
145
 
    psz_parser = strchr( psz_aspect, ':' );
146
 
    if( psz_parser ) psz_parser++;
147
 
    if( psz_parser && atoi( psz_parser ) > 0 )
148
 
        i_aspect = atoi( psz_aspect ) * VOUT_ASPECT_FACTOR / atoi( psz_parser );
149
196
    else
150
 
        i_aspect = atof( psz_aspect ) * VOUT_ASPECT_FACTOR;
151
 
    free( psz_aspect );
152
 
 
153
 
    if( i_aspect <= 0 )
154
197
    {
155
 
        msg_Err( p_filter, "Aspect ratio must be strictly positive" );
156
 
        return VLC_EGENERIC;
 
198
        /* if there is no user supplied aspect ratio, assume the canvas
 
199
         * has the same sample aspect ratio as the subpicture */
 
200
        /* aspect = subpic_sar * canvas_width / canvas_height
 
201
         *  where subpic_sar = subpic_ph * subpic_par / subpic_pw */
 
202
        i_canvas_aspect = (uint64_t) p_filter->fmt_in.video.i_height
 
203
                        * p_filter->fmt_in.video.i_aspect
 
204
                        * i_canvas_width
 
205
                        / (i_canvas_height * p_filter->fmt_in.video.i_width);
157
206
    }
158
207
 
159
208
    b_padd = var_CreateGetBool( p_filter, CFG_PREFIX "padd" );
174
223
 
175
224
    es_format_Copy( &fmt, &p_filter->fmt_in );
176
225
 
177
 
    fmt.video.i_width = i_width;
178
 
    fmt.video.i_height = ( p_filter->fmt_in.video.i_height * i_width )
179
 
                         / p_filter->fmt_in.video.i_width;
180
 
    fmt.video.i_height = ( fmt.video.i_height * i_aspect )
181
 
                         / p_filter->fmt_in.video.i_aspect;
 
226
    /* one dimension will end up with one of the following: */
 
227
    fmt.video.i_width = i_canvas_width;
 
228
    fmt.video.i_height = i_canvas_height;
182
229
 
183
230
    if( b_padd )
184
231
    {
185
232
        /* Padd */
186
 
        if( fmt.video.i_height > i_height )
 
233
        if( i_canvas_aspect > p_filter->fmt_in.video.i_aspect )
187
234
        {
188
 
            fmt.video.i_height = i_height;
189
 
            fmt.video.i_width = ( p_filter->fmt_in.video.i_width * i_height )
190
 
                                / p_filter->fmt_in.video.i_height;
191
 
            fmt.video.i_width = ( fmt.video.i_width * p_filter->fmt_in.video.i_aspect )
192
 
                                / i_aspect;
 
235
            /* The canvas has a wider aspect than the subpicture:
 
236
             *  ie, pillarbox the [scaled] subpicture */
 
237
            /* The following is derived form:
 
238
             * width = upconverted_subpic_height * subpic_par / canvas_sar
 
239
             *  where canvas_sar = canvas_width / (canvas_height * canvas_par)
 
240
             * then simplify */
 
241
            fmt.video.i_width = i_canvas_width
 
242
                              * p_filter->fmt_in.video.i_aspect
 
243
                              / i_canvas_aspect;
193
244
            if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1;
194
245
 
195
 
            i_padd = (i_width - fmt.video.i_width) / 2;
 
246
            i_padd = (i_canvas_width - fmt.video.i_width) / 2;
196
247
            i_offset = (i_padd & 1);
197
 
            /* Gruik */
198
248
            snprintf( psz_croppadd, 100, "croppadd{paddleft=%d,paddright=%d}",
199
249
                      i_padd - i_offset, i_padd + i_offset );
200
250
        }
201
251
        else
202
252
        {
 
253
            /* The canvas has a taller aspect than the subpicture:
 
254
             *  ie, letterbox the [scaled] subpicture */
 
255
            fmt.video.i_height = i_canvas_height
 
256
                               * i_canvas_aspect
 
257
                               / p_filter->fmt_in.video.i_aspect;
203
258
            if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1;
204
 
            i_padd = (i_height - fmt.video.i_height ) / 2;
 
259
 
 
260
            i_padd = (i_canvas_height - fmt.video.i_height ) / 2;
205
261
            i_offset = (i_padd & 1);
206
 
            /* Gruik */
207
262
            snprintf( psz_croppadd, 100, "croppadd{paddtop=%d,paddbottom=%d}",
208
263
                      i_padd - i_offset, i_padd + i_offset );
209
264
        }
211
266
    else
212
267
    {
213
268
        /* Crop */
214
 
        if( fmt.video.i_height < i_height )
 
269
        if( i_canvas_aspect < p_filter->fmt_in.video.i_aspect )
215
270
        {
216
 
            fmt.video.i_height = i_height;
217
 
            fmt.video.i_width = ( p_filter->fmt_in.video.i_width * i_height )
218
 
                                / p_filter->fmt_in.video.i_height;
219
 
            fmt.video.i_width = ( fmt.video.i_width * p_filter->fmt_in.video.i_aspect )
220
 
                                / i_aspect;
 
271
            /* The canvas has a narrower aspect than the subpicture:
 
272
             *  ie, crop the [scaled] subpicture horizontally */
 
273
            fmt.video.i_width = i_canvas_width
 
274
                              * p_filter->fmt_in.video.i_aspect
 
275
                              / i_canvas_aspect;
221
276
            if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1;
222
277
 
223
 
            i_padd = (fmt.video.i_width - i_width) / 2;
224
 
            i_offset =  (i_padd & 1);
225
 
            /* Gruik */
 
278
            i_padd = (fmt.video.i_width - i_canvas_width) / 2;
 
279
            i_offset = (i_padd & 1);
226
280
            snprintf( psz_croppadd, 100, "croppadd{cropleft=%d,cropright=%d}",
227
281
                      i_padd - i_offset, i_padd + i_offset );
228
282
        }
229
283
        else
230
284
        {
 
285
            /* The canvas has a shorter aspect than the subpicture:
 
286
             *  ie, crop the [scaled] subpicture vertically */
 
287
            fmt.video.i_height = i_canvas_height
 
288
                               * i_canvas_aspect
 
289
                               / p_filter->fmt_in.video.i_aspect;
231
290
            if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1;
232
 
            i_padd = (fmt.video.i_height - i_height) / 2;
 
291
 
 
292
            i_padd = (fmt.video.i_height - i_canvas_height) / 2;
233
293
            i_offset = (i_padd & 1);
234
 
            /* Gruik */
235
294
            snprintf( psz_croppadd, 100, "croppadd{croptop=%d,cropbottom=%d}",
236
295
                      i_padd - i_offset, i_padd + i_offset );
237
296
        }
238
297
    }
239
298
 
 
299
    /* xxx, should the clean area include the letter-boxing?
 
300
     *  probably not, as some codecs can make use of that information
 
301
     *  and it should be a scaled version of the input clean area
 
302
     *   -- davidf */
240
303
    fmt.video.i_visible_width = fmt.video.i_width;
241
304
    fmt.video.i_visible_height = fmt.video.i_height;
242
305
 
249
312
    fmt = *filter_chain_GetFmtOut( p_sys->p_chain );
250
313
    es_format_Copy( &p_filter->fmt_out, &fmt );
251
314
 
252
 
    p_filter->fmt_out.video.i_aspect = i_aspect * i_width / i_height;
 
315
    p_filter->fmt_out.video.i_aspect = i_canvas_aspect;
253
316
 
254
 
    if( p_filter->fmt_out.video.i_width != i_width
255
 
     || p_filter->fmt_out.video.i_height != i_height )
 
317
    if( p_filter->fmt_out.video.i_width != i_canvas_width
 
318
     || p_filter->fmt_out.video.i_height != i_canvas_height )
256
319
    {
257
320
        msg_Warn( p_filter, "Looks like something went wrong. "
258
321
                  "Output size is %dx%d while we asked for %dx%d",
259
322
                  p_filter->fmt_out.video.i_width,
260
323
                  p_filter->fmt_out.video.i_height,
261
 
                  i_width, i_height );
 
324
                  i_canvas_width, i_canvas_height );
262
325
    }
263
326
 
264
327
    p_filter->pf_video_filter = Filter;