vout_pictures.c 34.5 KB
Newer Older
Sam Hocevar's avatar
 
Sam Hocevar committed
1 2 3
/*****************************************************************************
 * vout_pictures.c : picture management functions
 *****************************************************************************
4
 * Copyright (C) 2000-2004 the VideoLAN team
5
 * $Id$
Sam Hocevar's avatar
 
Sam Hocevar committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
 *          Samuel Hocevar <sam@zoy.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Sam Hocevar's avatar
 
Sam Hocevar committed
23 24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc_common.h>
zorglub's avatar
zorglub committed
34 35
#include <vlc_vout.h>
#include <vlc_osd.h>
36
#include <vlc_filter.h>
37
#include "vout_pictures.h"
38
#include "vout_internal.h"
39

Rafaël Carré's avatar
Rafaël Carré committed
40 41
#include <assert.h>

42 43 44
/**
 * Display a picture
 *
gbazin's avatar
 
gbazin committed
45
 * Remove the reservation flag of a picture, which will cause it to be ready
46
 * for display.
47
 */
Sam Hocevar's avatar
 
Sam Hocevar committed
48
void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
49 50
{
    vlc_mutex_lock( &p_vout->picture_lock );
51 52

    if( p_pic->i_status == RESERVED_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
53
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
54
        p_pic->i_status = READY_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
55
    }
56
    else
Sam Hocevar's avatar
 
Sam Hocevar committed
57
    {
58
        msg_Err( p_vout, "picture to display %p has invalid status %d",
59
                         p_pic, p_pic->i_status );
Sam Hocevar's avatar
 
Sam Hocevar committed
60 61 62 63 64
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}

65 66 67
/**
 * Allocate a picture in the video output heap.
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
68 69
 * This function creates a reserved image in the video output heap.
 * A null pointer is returned if the function fails. This method provides an
gbazin's avatar
 
gbazin committed
70 71 72
 * already allocated zone of memory in the picture data fields.
 * It needs locking since several pictures can be created by several producers
 * threads.
73
 */
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
int vout_CountPictureAvailable( vout_thread_t *p_vout )
{
    int i_free = 0;
    int i_pic;

    vlc_mutex_lock( &p_vout->picture_lock );
    for( i_pic = 0; i_pic < I_RENDERPICTURES; i_pic++ )
    {
        picture_t *p_pic = PP_RENDERPICTURE[(p_vout->render.i_last_used_pic + i_pic + 1) % I_RENDERPICTURES];

        switch( p_pic->i_status )
        {
            case DESTROYED_PICTURE:
                i_free++;
                break;

            case FREE_PICTURE:
                i_free++;
                break;

            default:
                break;
        }
    }
    vlc_mutex_unlock( &p_vout->picture_lock );

    return i_free;
}

Sam Hocevar's avatar
 
Sam Hocevar committed
103
picture_t *vout_CreatePicture( vout_thread_t *p_vout,
104 105
                               bool b_progressive,
                               bool b_top_field_first,
106
                               unsigned int i_nb_fields )
Sam Hocevar's avatar
 
Sam Hocevar committed
107
{
Sam Hocevar's avatar
 
Sam Hocevar committed
108 109 110
    int         i_pic;                                      /* picture index */
    picture_t * p_pic;
    picture_t * p_freepic = NULL;                      /* first free picture */
Sam Hocevar's avatar
 
Sam Hocevar committed
111 112 113 114 115

    /* Get lock */
    vlc_mutex_lock( &p_vout->picture_lock );

    /*
gbazin's avatar
 
gbazin committed
116
     * Look for an empty place in the picture heap.
Sam Hocevar's avatar
 
Sam Hocevar committed
117
     */
gbazin's avatar
 
gbazin committed
118
    for( i_pic = 0; i_pic < I_RENDERPICTURES; i_pic++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
119
    {
gbazin's avatar
 
gbazin committed
120 121
        p_pic = PP_RENDERPICTURE[(p_vout->render.i_last_used_pic + i_pic + 1)
                                 % I_RENDERPICTURES];
Sam Hocevar's avatar
 
Sam Hocevar committed
122

Sam Hocevar's avatar
 
Sam Hocevar committed
123
        switch( p_pic->i_status )
Sam Hocevar's avatar
 
Sam Hocevar committed
124
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
125 126 127 128
            case DESTROYED_PICTURE:
                /* Memory will not be reallocated, and function can end
                 * immediately - this is the best possible case, since no
                 * memory allocation needs to be done */
Sam Hocevar's avatar
 
Sam Hocevar committed
129 130
                p_pic->i_status   = RESERVED_PICTURE;
                p_pic->i_refcount = 0;
131
                p_pic->b_force    = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
132

Sam Hocevar's avatar
 
Sam Hocevar committed
133
                p_pic->b_progressive        = b_progressive;
134
                p_pic->i_nb_fields          = i_nb_fields;
Sam Hocevar's avatar
 
Sam Hocevar committed
135
                p_pic->b_top_field_first    = b_top_field_first;
Sam Hocevar's avatar
 
Sam Hocevar committed
136

Sam Hocevar's avatar
 
Sam Hocevar committed
137
                p_vout->i_heap_size++;
gbazin's avatar
 
gbazin committed
138 139 140
                p_vout->render.i_last_used_pic =
                    ( p_vout->render.i_last_used_pic + i_pic + 1 )
                    % I_RENDERPICTURES;
Sam Hocevar's avatar
 
Sam Hocevar committed
141
                vlc_mutex_unlock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
142
                return( p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
143

Sam Hocevar's avatar
 
Sam Hocevar committed
144
            case FREE_PICTURE:
Sam Hocevar's avatar
 
Sam Hocevar committed
145
                /* Picture is empty and ready for allocation */
gbazin's avatar
 
gbazin committed
146 147 148
                p_vout->render.i_last_used_pic =
                    ( p_vout->render.i_last_used_pic + i_pic + 1 )
                    % I_RENDERPICTURES;
Sam Hocevar's avatar
 
Sam Hocevar committed
149
                p_freepic = p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
150 151 152 153 154
                break;

            default:
                break;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
155 156 157 158 159
    }

    /*
     * Prepare picture
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
160
    if( p_freepic != NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
161
    {
gbazin's avatar
 
gbazin committed
162 163
        vout_AllocatePicture( VLC_OBJECT(p_vout),
                              p_freepic, p_vout->render.i_chroma,
Sam Hocevar's avatar
 
Sam Hocevar committed
164
                              p_vout->render.i_width, p_vout->render.i_height,
gbazin's avatar
 
gbazin committed
165
                              p_vout->render.i_aspect );
Sam Hocevar's avatar
 
Sam Hocevar committed
166

Sam Hocevar's avatar
 
Sam Hocevar committed
167
        if( p_freepic->i_planes )
Sam Hocevar's avatar
 
Sam Hocevar committed
168 169
        {
            /* Copy picture information, set some default values */
Sam Hocevar's avatar
 
Sam Hocevar committed
170 171
            p_freepic->i_status   = RESERVED_PICTURE;
            p_freepic->i_type     = MEMORY_PICTURE;
172
            p_freepic->b_slow     = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
173

Sam Hocevar's avatar
 
Sam Hocevar committed
174
            p_freepic->i_refcount = 0;
175
            p_freepic->b_force = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
176

Sam Hocevar's avatar
 
Sam Hocevar committed
177
            p_freepic->b_progressive        = b_progressive;
178
            p_freepic->i_nb_fields          = i_nb_fields;
Sam Hocevar's avatar
 
Sam Hocevar committed
179
            p_freepic->b_top_field_first    = b_top_field_first;
Sam Hocevar's avatar
 
Sam Hocevar committed
180

Sam Hocevar's avatar
 
Sam Hocevar committed
181
            p_vout->i_heap_size++;
Sam Hocevar's avatar
 
Sam Hocevar committed
182 183 184 185
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
Sam Hocevar's avatar
 
Sam Hocevar committed
186 187
            p_freepic->i_status = FREE_PICTURE;
            p_freepic = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
188

189
            msg_Err( p_vout, "picture allocation failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
190 191 192 193
        }

        vlc_mutex_unlock( &p_vout->picture_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
194
        return( p_freepic );
Sam Hocevar's avatar
 
Sam Hocevar committed
195 196 197 198 199 200 201 202 203
    }

    /* No free or destroyed picture could be found, but the decoder
     * will try again in a while. */
    vlc_mutex_unlock( &p_vout->picture_lock );

    return( NULL );
}

204 205 206
/**
 * Remove a permanent or reserved picture from the heap
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
207 208 209
 * This function frees a previously reserved picture or a permanent
 * picture. It is meant to be used when the construction of a picture aborted.
 * Note that the picture will be destroyed even if it is linked !
210
 */
Sam Hocevar's avatar
 
Sam Hocevar committed
211
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
212 213 214
{
    vlc_mutex_lock( &p_vout->picture_lock );

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
215
#ifndef NDEBUG
Sam Hocevar's avatar
 
Sam Hocevar committed
216
    /* Check if picture status is valid */
217
    if( p_pic->i_status != RESERVED_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
218
    {
219 220
        msg_Err( p_vout, "picture to destroy %p has invalid status %d",
                         p_pic, p_pic->i_status );
Sam Hocevar's avatar
 
Sam Hocevar committed
221 222 223
    }
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
224
    p_pic->i_status = DESTROYED_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
225
    p_vout->i_heap_size--;
226
    picture_CleanupQuant( p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
227 228 229 230

    vlc_mutex_unlock( &p_vout->picture_lock );
}

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
/* */
void vout_DropPicture( vout_thread_t *p_vout, picture_t *p_pic  )
{
    vlc_mutex_lock( &p_vout->picture_lock );

    if( p_pic->i_status == READY_PICTURE )
    {
        /* Grr cannot destroy ready picture by myself so be sure vout won't like it */
        p_pic->date = 1;
    }
    else if( p_pic->i_refcount > 0 )
    {
        p_pic->i_status = DISPLAYED_PICTURE;
    }
    else
    {
        p_pic->i_status = DESTROYED_PICTURE;
        p_vout->i_heap_size--;
        picture_CleanupQuant( p_pic );
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}

255 256 257
/**
 * Increment reference counter of a picture
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
258 259
 * This function increments the reference counter of a picture in the video
 * heap. It needs a lock since several producer threads can access the picture.
260
 */
Sam Hocevar's avatar
 
Sam Hocevar committed
261
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
262 263
{
    vlc_mutex_lock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
264
    p_pic->i_refcount++;
Sam Hocevar's avatar
 
Sam Hocevar committed
265 266 267
    vlc_mutex_unlock( &p_vout->picture_lock );
}

268 269 270
/**
 * Decrement reference counter of a picture
 *
gbazin's avatar
 
gbazin committed
271
 * This function decrement the reference counter of a picture in the video heap
272
 */
Sam Hocevar's avatar
 
Sam Hocevar committed
273
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
274 275
{
    vlc_mutex_lock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
276
    p_pic->i_refcount--;
Sam Hocevar's avatar
 
Sam Hocevar committed
277

Sam Hocevar's avatar
 
Sam Hocevar committed
278 279
    if( ( p_pic->i_refcount == 0 ) &&
        ( p_pic->i_status == DISPLAYED_PICTURE ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
280
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
281
        p_pic->i_status = DESTROYED_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
282
        p_vout->i_heap_size--;
283
        picture_CleanupQuant( p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
284 285 286 287 288
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}

289 290 291 292 293 294 295 296 297 298 299 300
static int vout_LockPicture( vout_thread_t *p_vout, picture_t *p_picture )
{
    if( p_picture->pf_lock )
        return p_picture->pf_lock( p_vout, p_picture );
    return VLC_SUCCESS;
}
static void vout_UnlockPicture( vout_thread_t *p_vout, picture_t *p_picture )
{
    if( p_picture->pf_unlock )
        p_picture->pf_unlock( p_vout, p_picture );
}

301 302 303
/**
 * Render a picture
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
304 305 306
 * This function chooses whether the current picture needs to be copied
 * before rendering, does the subpicture magic, and tells the video output
 * thread which direct buffer needs to be displayed.
307
 */
308
picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
Laurent Aimar's avatar
Laurent Aimar committed
309
                               subpicture_t *p_subpic, bool b_paused )
Sam Hocevar's avatar
 
Sam Hocevar committed
310
{
Sam Hocevar's avatar
 
Sam Hocevar committed
311
    if( p_pic == NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
312
        return NULL;
313

Sam Hocevar's avatar
 
Sam Hocevar committed
314
    if( p_pic->i_type == DIRECT_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
315
    {
316 317 318
        /* Picture is in a direct buffer. */

        if( p_subpic != NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
319
        {
320 321 322 323 324
            /* We have subtitles. First copy the picture to
             * the spare direct buffer, then render the
             * subtitles. */
            if( vout_LockPicture( p_vout, PP_OUTPUTPICTURE[0] ) )
                return NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
325

326
            picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
327

328 329
            spu_RenderSubpictures( p_vout->p_spu,
                                   PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
330
                                   p_subpic, &p_vout->fmt_in, b_paused );
331 332 333 334 335

            vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );

            return PP_OUTPUTPICTURE[0];
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
336

337 338 339
        /* No subtitles, picture is in a directbuffer so
         * we can display it directly (even if it is still
         * in use or not). */
Sam Hocevar's avatar
 
Sam Hocevar committed
340
        return p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
341 342 343 344
    }

    /* Not a direct buffer. We either need to copy it to a direct buffer,
     * or render it if the chroma isn't the same. */
345
    if( p_vout->p->b_direct )
Sam Hocevar's avatar
 
Sam Hocevar committed
346 347 348 349
    {
        /* Picture is not in a direct buffer, but is exactly the
         * same size as the direct buffers. A memcpy() is enough,
         * then render the subtitles. */
gbazin's avatar
 
gbazin committed
350

351 352
        if( vout_LockPicture( p_vout, PP_OUTPUTPICTURE[0] ) )
            return NULL;
gbazin's avatar
 
gbazin committed
353

354
        picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
355 356
        spu_RenderSubpictures( p_vout->p_spu,
                               PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
357
                               p_subpic, &p_vout->fmt_in, b_paused );
Sam Hocevar's avatar
 
Sam Hocevar committed
358

359
        vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );
gbazin's avatar
 
gbazin committed
360

Sam Hocevar's avatar
 
Sam Hocevar committed
361
        return PP_OUTPUTPICTURE[0];
Sam Hocevar's avatar
 
Sam Hocevar committed
362 363 364 365
    }

    /* Picture is not in a direct buffer, and needs to be converted to
     * another size/chroma. Then the subtitles need to be rendered as
Sam Hocevar's avatar
 
Sam Hocevar committed
366
     * well. This usually means software YUV, or hardware YUV with a
Sam Hocevar's avatar
 
Sam Hocevar committed
367 368
     * different chroma. */

369 370 371 372 373 374 375 376 377
    if( p_subpic != NULL && p_vout->p_picture[0].b_slow )
    {
        /* The picture buffer is in slow memory. We'll use
         * the "2 * VOUT_MAX_PICTURES + 1" picture as a temporary
         * one for subpictures rendering. */
        picture_t *p_tmp_pic = &p_vout->p_picture[2 * VOUT_MAX_PICTURES];
        if( p_tmp_pic->i_status == FREE_PICTURE )
        {
            vout_AllocatePicture( VLC_OBJECT(p_vout),
378 379 380 381
                                  p_tmp_pic, p_vout->fmt_out.i_chroma,
                                  p_vout->fmt_out.i_width,
                                  p_vout->fmt_out.i_height,
                                  p_vout->fmt_out.i_aspect );
382 383
            p_tmp_pic->i_type = MEMORY_PICTURE;
            p_tmp_pic->i_status = RESERVED_PICTURE;
384 385
            /* some modules (such as blend)  needs to know the extra information in picture heap */
            p_tmp_pic->p_heap = &p_vout->output;
386 387 388
        }

        /* Convert image to the first direct buffer */
389 390
        p_vout->p->p_chroma->p_owner = (filter_owner_sys_t *)p_tmp_pic;
        p_vout->p->p_chroma->pf_video_filter( p_vout->p->p_chroma, p_pic );
gbazin's avatar
 
gbazin committed
391

392
        /* Render subpictures on the first direct buffer */
393 394
        spu_RenderSubpictures( p_vout->p_spu,
                               p_tmp_pic, &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
395
                               p_subpic, &p_vout->fmt_in, b_paused );
Sam Hocevar's avatar
 
Sam Hocevar committed
396

397 398
        if( vout_LockPicture( p_vout, &p_vout->p_picture[0] ) )
            return NULL;
399

400
        picture_Copy( &p_vout->p_picture[0], p_tmp_pic );
401 402 403
    }
    else
    {
404 405
        if( vout_LockPicture( p_vout, &p_vout->p_picture[0] ) )
            return NULL;
406 407

        /* Convert image to the first direct buffer */
408 409
        p_vout->p->p_chroma->p_owner = (filter_owner_sys_t *)&p_vout->p_picture[0];
        p_vout->p->p_chroma->pf_video_filter( p_vout->p->p_chroma, p_pic );
410 411

        /* Render subpictures on the first direct buffer */
412 413
        spu_RenderSubpictures( p_vout->p_spu,
                               &p_vout->p_picture[0], &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
414
                               p_subpic, &p_vout->fmt_in, b_paused );
415
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
416

417
    vout_UnlockPicture( p_vout, &p_vout->p_picture[0] );
gbazin's avatar
 
gbazin committed
418

Sam Hocevar's avatar
 
Sam Hocevar committed
419 420 421
    return &p_vout->p_picture[0];
}

422 423 424
/**
 * Calculate image window coordinates
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
425 426
 * This function will be accessed by plugins. It calculates the relative
 * position of the output window and the image window.
427
 */
428 429 430 431
void vout_PlacePicture( vout_thread_t *p_vout,
                        unsigned int i_width, unsigned int i_height,
                        unsigned int *pi_x, unsigned int *pi_y,
                        unsigned int *pi_width, unsigned int *pi_height )
Sam Hocevar's avatar
 
Sam Hocevar committed
432
{
gbazin's avatar
 
gbazin committed
433
    if( (i_width <= 0) || (i_height <=0) )
gbazin's avatar
 
gbazin committed
434 435
    {
        *pi_width = *pi_height = *pi_x = *pi_y = 0;
gbazin's avatar
 
gbazin committed
436
        return;
gbazin's avatar
 
gbazin committed
437
    }
gbazin's avatar
 
gbazin committed
438

Sam Hocevar's avatar
 
Sam Hocevar committed
439 440 441 442 443 444 445
    if( p_vout->b_scale )
    {
        *pi_width = i_width;
        *pi_height = i_height;
    }
    else
    {
446 447
        *pi_width = __MIN( i_width, p_vout->fmt_in.i_visible_width );
        *pi_height = __MIN( i_height, p_vout->fmt_in.i_visible_height );
Sam Hocevar's avatar
 
Sam Hocevar committed
448 449
    }

450 451 452 453 454 455
     int64_t i_scaled_width = p_vout->fmt_in.i_visible_width * (int64_t)p_vout->fmt_in.i_sar_num *
                              *pi_height / p_vout->fmt_in.i_visible_height / p_vout->fmt_in.i_sar_den;
     int64_t i_scaled_height = p_vout->fmt_in.i_visible_height * (int64_t)p_vout->fmt_in.i_sar_den *
                               *pi_width / p_vout->fmt_in.i_visible_width / p_vout->fmt_in.i_sar_num;

    if( i_scaled_width <= 0 || i_scaled_height <= 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
456
    {
457 458 459
        msg_Warn( p_vout, "ignoring broken aspect ratio" );
        i_scaled_width = *pi_width;
        i_scaled_height = *pi_height;
Sam Hocevar's avatar
 
Sam Hocevar committed
460
    }
461 462 463

    if( i_scaled_width > *pi_width )
        *pi_height = i_scaled_height;
Sam Hocevar's avatar
 
Sam Hocevar committed
464
    else
465
        *pi_width = i_scaled_width;
Sam Hocevar's avatar
 
Sam Hocevar committed
466

gbazin's avatar
 
gbazin committed
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
    switch( p_vout->i_alignment & VOUT_ALIGN_HMASK )
    {
    case VOUT_ALIGN_LEFT:
        *pi_x = 0;
        break;
    case VOUT_ALIGN_RIGHT:
        *pi_x = i_width - *pi_width;
        break;
    default:
        *pi_x = ( i_width - *pi_width ) / 2;
    }

    switch( p_vout->i_alignment & VOUT_ALIGN_VMASK )
    {
    case VOUT_ALIGN_TOP:
        *pi_y = 0;
        break;
    case VOUT_ALIGN_BOTTOM:
        *pi_y = i_height - *pi_height;
        break;
    default:
        *pi_y = ( i_height - *pi_height ) / 2;
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
490 491
}

492 493 494
/**
 * Allocate a new picture in the heap.
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
495 496 497
 * This function allocates a fake direct buffer in memory, which can be
 * used exactly like a video buffer. The video output thread then manages
 * how it gets displayed.
498
 */
499 500 501
int __vout_AllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
                            vlc_fourcc_t i_chroma,
                            int i_width, int i_height, int i_aspect )
Sam Hocevar's avatar
 
Sam Hocevar committed
502
{
503 504 505 506 507
    int i_bytes, i_index, i_width_aligned, i_height_aligned;

    /* Make sure the real dimensions are a multiple of 16 */
    i_width_aligned = (i_width + 15) >> 4 << 4;
    i_height_aligned = (i_height + 15) >> 4 << 4;
Sam Hocevar's avatar
 
Sam Hocevar committed
508

509 510 511 512 513 514
    if( vout_InitPicture( p_this, p_pic, i_chroma,
                          i_width, i_height, i_aspect ) != VLC_SUCCESS )
    {
        p_pic->i_planes = 0;
        return VLC_EGENERIC;
    }
gbazin's avatar
 
gbazin committed
515 516

    /* Calculate how big the new image should be */
gbazin's avatar
 
gbazin committed
517
    i_bytes = p_pic->format.i_bits_per_pixel *
518
        i_width_aligned * i_height_aligned / 8;
gbazin's avatar
 
gbazin committed
519 520 521 522 523 524

    p_pic->p_data = vlc_memalign( &p_pic->p_data_orig, 16, i_bytes );

    if( p_pic->p_data == NULL )
    {
        p_pic->i_planes = 0;
525
        return VLC_EGENERIC;
gbazin's avatar
 
gbazin committed
526 527 528 529 530 531 532
    }

    /* Fill the p_pixels field for each plane */
    p_pic->p[ 0 ].p_pixels = p_pic->p_data;

    for( i_index = 1; i_index < p_pic->i_planes; i_index++ )
    {
533 534
        p_pic->p[i_index].p_pixels = p_pic->p[i_index-1].p_pixels +
            p_pic->p[i_index-1].i_lines * p_pic->p[i_index-1].i_pitch;
gbazin's avatar
 
gbazin committed
535
    }
536 537

    return VLC_SUCCESS;
gbazin's avatar
 
gbazin committed
538 539
}

540 541 542
/**
 * Initialise the video format fields given chroma/size.
 *
gbazin's avatar
 
gbazin committed
543 544
 * This function initializes all the video_frame_format_t fields given the
 * static properties of a picture (chroma and size).
545 546 547 548 549 550
 * \param p_format Pointer to the format structure to initialize
 * \param i_chroma Chroma to set
 * \param i_width Width to set
 * \param i_height Height to set
 * \param i_aspect Aspect ratio
 */
gbazin's avatar
 
gbazin committed
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
void vout_InitFormat( video_frame_format_t *p_format, vlc_fourcc_t i_chroma,
                      int i_width, int i_height, int i_aspect )
{
    p_format->i_chroma   = i_chroma;
    p_format->i_width    = p_format->i_visible_width  = i_width;
    p_format->i_height   = p_format->i_visible_height = i_height;
    p_format->i_x_offset = p_format->i_y_offset = 0;
    p_format->i_aspect   = i_aspect;

#if 0
    /* Assume we have square pixels */
    if( i_width && i_height )
        p_format->i_aspect = i_width * VOUT_ASPECT_FACTOR / i_height;
    else
        p_format->i_aspect = 0;
#endif

    switch( i_chroma )
    {
570 571 572
        case FOURCC_YUVA:
            p_format->i_bits_per_pixel = 32;
            break;
gbazin's avatar
 
gbazin committed
573
        case FOURCC_I444:
574
        case FOURCC_J444:
gbazin's avatar
 
gbazin committed
575 576 577 578
            p_format->i_bits_per_pixel = 24;
            break;
        case FOURCC_I422:
        case FOURCC_YUY2:
579
        case FOURCC_UYVY:
580
        case FOURCC_J422:
gbazin's avatar
 
gbazin committed
581 582
            p_format->i_bits_per_pixel = 16;
            break;
583 584 585 586
        case FOURCC_I440:
        case FOURCC_J440:
            p_format->i_bits_per_pixel = 16;
            break;
gbazin's avatar
 
gbazin committed
587 588 589
        case FOURCC_I411:
        case FOURCC_YV12:
        case FOURCC_I420:
590
        case FOURCC_J420:
gbazin's avatar
 
gbazin committed
591 592 593 594
        case FOURCC_IYUV:
            p_format->i_bits_per_pixel = 12;
            break;
        case FOURCC_I410:
595
        case FOURCC_YVU9:
596
            p_format->i_bits_per_pixel = 9;
gbazin's avatar
 
gbazin committed
597 598 599 600
            break;
        case FOURCC_Y211:
            p_format->i_bits_per_pixel = 8;
            break;
601 602 603 604
        case FOURCC_YUVP:
            p_format->i_bits_per_pixel = 8;
            break;

gbazin's avatar
 
gbazin committed
605
        case FOURCC_RV32:
606
        case FOURCC_RGBA:
gbazin's avatar
 
gbazin committed
607 608 609 610 611 612 613 614 615 616 617 618
            p_format->i_bits_per_pixel = 32;
            break;
        case FOURCC_RV24:
            p_format->i_bits_per_pixel = 24;
            break;
        case FOURCC_RV15:
        case FOURCC_RV16:
            p_format->i_bits_per_pixel = 16;
            break;
        case FOURCC_RGB2:
            p_format->i_bits_per_pixel = 8;
            break;
619 620

        case FOURCC_GREY:
621 622
        case FOURCC_Y800:
        case FOURCC_Y8:
623
        case FOURCC_RGBP:
624 625 626
            p_format->i_bits_per_pixel = 8;
            break;

gbazin's avatar
 
gbazin committed
627 628 629 630 631 632
        default:
            p_format->i_bits_per_pixel = 0;
            break;
    }
}

633 634 635
/**
 * Initialise the picture_t fields given chroma/size.
 *
gbazin's avatar
 
gbazin committed
636 637
 * This function initializes most of the picture_t fields given a chroma and
 * size. It makes the assumption that stride == width.
638 639 640 641 642 643 644
 * \param p_this The calling object
 * \param p_pic Pointer to the picture to initialize
 * \param i_chroma The chroma fourcc to set
 * \param i_width The width of the picture
 * \param i_height The height of the picture
 * \param i_aspect The aspect ratio of the picture
 */
645 646 647
int __vout_InitPicture( vlc_object_t *p_this, picture_t *p_pic,
                        vlc_fourcc_t i_chroma,
                        int i_width, int i_height, int i_aspect )
gbazin's avatar
 
gbazin committed
648
{
649
    int i_index, i_width_aligned, i_height_aligned;
gbazin's avatar
 
gbazin committed
650

Sam Hocevar's avatar
 
Sam Hocevar committed
651 652 653 654
    /* Store default values */
    for( i_index = 0; i_index < VOUT_MAX_PLANES; i_index++ )
    {
        p_pic->p[i_index].p_pixels = NULL;
655
        p_pic->p[i_index].i_pixel_pitch = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
656 657
    }

658 659 660
    p_pic->pf_release = NULL;
    p_pic->pf_lock = NULL;
    p_pic->pf_unlock = NULL;
661 662
    p_pic->i_refcount = 0;

663 664 665 666
    p_pic->p_q = NULL;
    p_pic->i_qstride = 0;
    p_pic->i_qtype = 0;

gbazin's avatar
 
gbazin committed
667 668
    vout_InitFormat( &p_pic->format, i_chroma, i_width, i_height, i_aspect );

669 670 671 672
    /* Make sure the real dimensions are a multiple of 16 */
    i_width_aligned = (i_width + 15) >> 4 << 4;
    i_height_aligned = (i_height + 15) >> 4 << 4;

Sam Hocevar's avatar
 
Sam Hocevar committed
673
    /* Calculate coordinates */
Sam Hocevar's avatar
 
Sam Hocevar committed
674
    switch( i_chroma )
Sam Hocevar's avatar
 
Sam Hocevar committed
675
    {
gbazin's avatar
 
gbazin committed
676
        case FOURCC_I411:
677 678
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
679 680
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
681 682
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
683 684
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned / 4;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width / 4;
685 686
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
687 688
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned / 4;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width / 4;
gbazin's avatar
 
gbazin committed
689 690 691
            p_pic->i_planes = 3;
            break;

692
        case FOURCC_I410:
693
        case FOURCC_YVU9:
694 695
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
696 697
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
698 699
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned / 4;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height / 4;
700 701
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned / 4;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width / 4;
702 703
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned / 4;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height / 4;
704 705
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned / 4;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width / 4;
706 707 708
            p_pic->i_planes = 3;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
709
        case FOURCC_YV12:
Sam Hocevar's avatar
 
Sam Hocevar committed
710 711
        case FOURCC_I420:
        case FOURCC_IYUV:
712
        case FOURCC_J420:
713 714
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
715 716
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
717 718
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned / 2;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height / 2;
719 720
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned / 2;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width / 2;
721 722
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned / 2;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height / 2;
723 724
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned / 2;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width / 2;
Sam Hocevar's avatar
 
Sam Hocevar committed
725
            p_pic->i_planes = 3;
Sam Hocevar's avatar
 
Sam Hocevar committed
726 727
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
728
        case FOURCC_I422:
729
        case FOURCC_J422:
730 731
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
732 733
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
734 735
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
736 737
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned / 2;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width / 2;
738 739
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
740 741
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned / 2;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width / 2;
Sam Hocevar's avatar
 
Sam Hocevar committed
742
            p_pic->i_planes = 3;
Sam Hocevar's avatar
 
Sam Hocevar committed
743 744
            break;

745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
        case FOURCC_I440:
        case FOURCC_J440:
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned / 2;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height / 2;
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width;
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned / 2;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height / 2;
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width;
            p_pic->i_planes = 3;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
762
        case FOURCC_I444:
763
        case FOURCC_J444:
764 765
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
766 767
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
768 769
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
770 771
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width;
772 773
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
774 775
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width;
Sam Hocevar's avatar
 
Sam Hocevar committed
776 777 778
            p_pic->i_planes = 3;
            break;

779
        case FOURCC_YUVA:
780 781
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
782 783
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
784 785
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
786 787
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width;
788 789
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
790 791
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width;
792 793
            p_pic->p[ A_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ A_PLANE ].i_visible_lines = i_height;
794 795
            p_pic->p[ A_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ A_PLANE ].i_visible_pitch = i_width;
796 797 798 799
            p_pic->i_planes = 4;
            break;

        case FOURCC_YUVP:
800 801
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
802 803
            p_pic->p->i_pitch = i_width_aligned;
            p_pic->p->i_visible_pitch = i_width;
804 805 806 807
            p_pic->p->i_pixel_pitch = 8;
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
808
        case FOURCC_Y211:
809 810
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
811 812
            p_pic->p->i_pitch = i_width_aligned;
            p_pic->p->i_visible_pitch = i_width;
813
            p_pic->p->i_pixel_pitch = 4;
Sam Hocevar's avatar
 
Sam Hocevar committed
814 815 816
            p_pic->i_planes = 1;
            break;

817
        case FOURCC_UYVY:
818
        case FOURCC_YUY2:
819 820
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
821 822
            p_pic->p->i_pitch = i_width_aligned * 2;
            p_pic->p->i_visible_pitch = i_width * 2;
823
            p_pic->p->i_pixel_pitch = 4;
824 825 826
            p_pic->i_planes = 1;
            break;

827
        case FOURCC_RGB2:
828 829
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
830 831
            p_pic->p->i_pitch = i_width_aligned;
            p_pic->p->i_visible_pitch = i_width;
832 833 834 835
            p_pic->p->i_pixel_pitch = 1;
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
836
        case FOURCC_RV15:
837 838
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
839 840
            p_pic->p->i_pitch = i_width_aligned * 2;
            p_pic->p->i_visible_pitch = i_width * 2;
841
            p_pic->p->i_pixel_pitch = 2;
Sam Hocevar's avatar
 
Sam Hocevar committed
842 843 844 845
            p_pic->i_planes = 1;
            break;

        case FOURCC_RV16:
846 847
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
848 849
            p_pic->p->i_pitch = i_width_aligned * 2;
            p_pic->p->i_visible_pitch = i_width * 2;
850
            p_pic->p->i_pixel_pitch = 2;
Sam Hocevar's avatar
 
Sam Hocevar committed
851
            p_pic->i_planes = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
852 853
            break;

gbazin's avatar
 
gbazin committed
854
        case FOURCC_RV24:
855 856
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
857 858
            p_pic->p->i_pitch = i_width_aligned * 3;
            p_pic->p->i_visible_pitch = i_width * 3;
gbazin's avatar
 
gbazin committed
859 860 861 862
            p_pic->p->i_pixel_pitch = 3;
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
863
        case FOURCC_RV32:
864
        case FOURCC_RGBA:
865 866
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
867 868
            p_pic->p->i_pitch = i_width_aligned * 4;
            p_pic->p->i_visible_pitch = i_width * 4;
869
            p_pic->p->i_pixel_pitch = 4;
Sam Hocevar's avatar
 
Sam Hocevar committed
870 871 872
            p_pic->i_planes = 1;
            break;

873
        case FOURCC_GREY:
874 875
        case FOURCC_Y800:
        case FOURCC_Y8:
876
        case FOURCC_RGBP:
877 878 879 880 881 882 883 884
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
            p_pic->p->i_pitch = i_width_aligned;
            p_pic->p->i_visible_pitch = i_width;
            p_pic->p->i_pixel_pitch = 1;
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
885
        default:
886 887 888
            if( p_this )
                msg_Err( p_this, "unknown chroma type 0x%.8x (%4.4s)",
                                 i_chroma, (char*)&i_chroma );
Sam Hocevar's avatar
 
Sam Hocevar committed
889
            p_pic->i_planes = 0;
890
            return VLC_EGENERIC;
Sam Hocevar's avatar
 
Sam Hocevar committed
891
    }
892 893

    return VLC_SUCCESS;
Sam Hocevar's avatar