vout_pictures.c 36.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
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
32
#include <assert.h>
33

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

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;
55
        vlc_cond_signal( &p_vout->p->picture_wait );
Sam Hocevar's avatar
 
Sam Hocevar committed
56
    }
57
    else
Sam Hocevar's avatar
 
Sam Hocevar committed
58
    {
59
        msg_Err( p_vout, "picture to display %p has invalid status %d",
60
                         p_pic, p_pic->i_status );
Sam Hocevar's avatar
 
Sam Hocevar committed
61
    }
62
    p_vout->p->i_picture_qtype = p_pic->i_qtype;
Sam Hocevar's avatar
 
Sam Hocevar committed
63 64 65 66

    vlc_mutex_unlock( &p_vout->picture_lock );
}

67 68 69
/**
 * Allocate a picture in the video output heap.
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
70 71
 * 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
72 73 74
 * already allocated zone of memory in the picture data fields.
 * It needs locking since several pictures can be created by several producers
 * threads.
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 103 104
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
105
picture_t *vout_CreatePicture( vout_thread_t *p_vout,
106 107
                               bool b_progressive,
                               bool b_top_field_first,
108
                               unsigned int i_nb_fields )
Sam Hocevar's avatar
 
Sam Hocevar committed
109
{
Sam Hocevar's avatar
 
Sam Hocevar committed
110 111 112
    int         i_pic;                                      /* picture index */
    picture_t * p_pic;
    picture_t * p_freepic = NULL;                      /* first free picture */
Sam Hocevar's avatar
 
Sam Hocevar committed
113 114 115 116 117

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
125
        switch( p_pic->i_status )
Sam Hocevar's avatar
 
Sam Hocevar committed
126
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
127 128 129 130
            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
131 132
                p_pic->i_status   = RESERVED_PICTURE;
                p_pic->i_refcount = 0;
133
                p_pic->b_force    = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
134

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

Sam Hocevar's avatar
 
Sam Hocevar committed
139
                p_vout->i_heap_size++;
gbazin's avatar
 
gbazin committed
140 141 142
                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
143
                vlc_mutex_unlock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
144
                return( p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
145

Sam Hocevar's avatar
 
Sam Hocevar committed
146
            case FREE_PICTURE:
Sam Hocevar's avatar
 
Sam Hocevar committed
147
                /* Picture is empty and ready for allocation */
gbazin's avatar
 
gbazin committed
148 149 150
                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
151
                p_freepic = p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
152 153 154 155 156
                break;

            default:
                break;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
157 158 159 160 161
    }

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
176
            p_freepic->i_refcount = 0;
177
            p_freepic->b_force = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
178

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

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

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

        vlc_mutex_unlock( &p_vout->picture_lock );

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

    /* 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 );
}

206 207 208 209 210 211 212 213 214 215 216 217
/* */
static void DestroyPicture( vout_thread_t *p_vout, picture_t *p_picture )
{
    vlc_assert_locked( &p_vout->picture_lock );

    p_picture->i_status = DESTROYED_PICTURE;
    p_vout->i_heap_size--;
    picture_CleanupQuant( p_picture );

    vlc_cond_signal( &p_vout->p->picture_wait );
}

218 219 220
/**
 * Remove a permanent or reserved picture from the heap
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
221 222 223
 * 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 !
224 225
 *
 * TODO remove it, vout_DropPicture should be used instead
226
 */
Sam Hocevar's avatar
 
Sam Hocevar committed
227
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
228
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
229
#ifndef NDEBUG
Sam Hocevar's avatar
 
Sam Hocevar committed
230
    /* Check if picture status is valid */
231
    vlc_mutex_lock( &p_vout->picture_lock );
232
    if( p_pic->i_status != RESERVED_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
233
    {
234 235
        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
236
    }
237
    vlc_mutex_unlock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
238 239
#endif

240 241
    vout_DropPicture( p_vout, p_pic );
}
Sam Hocevar's avatar
 
Sam Hocevar committed
242

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/* */
void vout_UsePictureLocked( vout_thread_t *p_vout, picture_t *p_picture )
{
    vlc_assert_locked( &p_vout->picture_lock );
    if( p_picture->i_refcount > 0 )
    {
        /* Pretend we displayed the picture, but don't destroy
         * it since the decoder might still need it. */
        p_picture->i_status = DISPLAYED_PICTURE;
    }
    else
    {
        /* Destroy the picture without displaying it */
        DestroyPicture( p_vout, p_picture );
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
258 259
}

260 261 262 263 264 265 266 267 268
/* */
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;
269
        vlc_cond_signal( &p_vout->p->picture_wait );
270 271 272
    }
    else
    {
273
        vout_UsePictureLocked( p_vout, p_pic );
274 275 276 277 278
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}

279 280 281
/**
 * Increment reference counter of a picture
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
282 283
 * 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.
284
 */
Sam Hocevar's avatar
 
Sam Hocevar committed
285
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
286 287
{
    vlc_mutex_lock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
288
    p_pic->i_refcount++;
Sam Hocevar's avatar
 
Sam Hocevar committed
289 290 291
    vlc_mutex_unlock( &p_vout->picture_lock );
}

292 293 294
/**
 * Decrement reference counter of a picture
 *
gbazin's avatar
 
gbazin committed
295
 * This function decrement the reference counter of a picture in the video heap
296
 */
Sam Hocevar's avatar
 
Sam Hocevar committed
297
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
298 299 300
{
    vlc_mutex_lock( &p_vout->picture_lock );

301 302 303 304 305 306 307 308
    if( p_pic->i_refcount > 0 )
        p_pic->i_refcount--;
    else
        msg_Err( p_vout, "Invalid picture reference count (%p, %d)",
                 p_pic, p_pic->i_refcount );

    if( p_pic->i_refcount == 0 && p_pic->i_status == DISPLAYED_PICTURE )
        DestroyPicture( p_vout, p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
309 310 311 312

    vlc_mutex_unlock( &p_vout->picture_lock );
}

313 314 315 316 317 318 319 320 321 322 323 324
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 );
}

325 326 327
/**
 * Render a picture
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
328 329 330
 * 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.
331
 */
332
picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
Laurent Aimar's avatar
Laurent Aimar committed
333
                               subpicture_t *p_subpic, bool b_paused )
Sam Hocevar's avatar
 
Sam Hocevar committed
334
{
Sam Hocevar's avatar
 
Sam Hocevar committed
335
    if( p_pic == NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
336
        return NULL;
337

Sam Hocevar's avatar
 
Sam Hocevar committed
338
    if( p_pic->i_type == DIRECT_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
339
    {
340 341 342
        /* Picture is in a direct buffer. */

        if( p_subpic != NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
343
        {
344 345 346 347 348
            /* 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
349

350
            picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
351

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

            vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );

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

361 362 363
        /* 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
364
        return p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
365 366 367 368
    }

    /* Not a direct buffer. We either need to copy it to a direct buffer,
     * or render it if the chroma isn't the same. */
369
    if( p_vout->p->b_direct )
Sam Hocevar's avatar
 
Sam Hocevar committed
370 371 372 373
    {
        /* 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
374

375 376
        if( vout_LockPicture( p_vout, PP_OUTPUTPICTURE[0] ) )
            return NULL;
gbazin's avatar
 
gbazin committed
377

378
        picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
379 380
        spu_RenderSubpictures( p_vout->p_spu,
                               PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
381
                               p_subpic, &p_vout->fmt_in, b_paused );
Sam Hocevar's avatar
 
Sam Hocevar committed
382

383
        vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );
gbazin's avatar
 
gbazin committed
384

Sam Hocevar's avatar
 
Sam Hocevar committed
385
        return PP_OUTPUTPICTURE[0];
Sam Hocevar's avatar
 
Sam Hocevar committed
386 387 388 389
    }

    /* 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
390
     * well. This usually means software YUV, or hardware YUV with a
Sam Hocevar's avatar
 
Sam Hocevar committed
391 392
     * different chroma. */

393 394 395 396 397 398 399 400 401
    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),
402 403 404 405
                                  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 );
406 407
            p_tmp_pic->i_type = MEMORY_PICTURE;
            p_tmp_pic->i_status = RESERVED_PICTURE;
408 409
            /* some modules (such as blend)  needs to know the extra information in picture heap */
            p_tmp_pic->p_heap = &p_vout->output;
410 411 412
        }

        /* Convert image to the first direct buffer */
413 414
        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
415

416
        /* Render subpictures on the first direct buffer */
417 418
        spu_RenderSubpictures( p_vout->p_spu,
                               p_tmp_pic, &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
419
                               p_subpic, &p_vout->fmt_in, b_paused );
Sam Hocevar's avatar
 
Sam Hocevar committed
420

421 422
        if( vout_LockPicture( p_vout, &p_vout->p_picture[0] ) )
            return NULL;
423

424
        picture_Copy( &p_vout->p_picture[0], p_tmp_pic );
425 426 427
    }
    else
    {
428 429
        if( vout_LockPicture( p_vout, &p_vout->p_picture[0] ) )
            return NULL;
430 431

        /* Convert image to the first direct buffer */
432 433
        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 );
434 435

        /* Render subpictures on the first direct buffer */
436 437
        spu_RenderSubpictures( p_vout->p_spu,
                               &p_vout->p_picture[0], &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
438
                               p_subpic, &p_vout->fmt_in, b_paused );
439
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
440

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

Sam Hocevar's avatar
 
Sam Hocevar committed
443 444 445
    return &p_vout->p_picture[0];
}

446 447 448
/**
 * Calculate image window coordinates
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
449 450
 * This function will be accessed by plugins. It calculates the relative
 * position of the output window and the image window.
451
 */
452
void vout_PlacePicture( const vout_thread_t *p_vout,
453
                        unsigned int i_width, unsigned int i_height,
454 455 456 457
                        unsigned int *restrict pi_x,
                        unsigned int *restrict pi_y,
                        unsigned int *restrict pi_width,
                        unsigned int *restrict pi_height )
Sam Hocevar's avatar
 
Sam Hocevar committed
458
{
Laurent Aimar's avatar
Laurent Aimar committed
459
    if( i_width <= 0 || i_height <= 0 )
gbazin's avatar
 
gbazin committed
460 461
    {
        *pi_width = *pi_height = *pi_x = *pi_y = 0;
gbazin's avatar
 
gbazin committed
462
        return;
gbazin's avatar
 
gbazin committed
463
    }
gbazin's avatar
 
gbazin committed
464

Laurent Aimar's avatar
Laurent Aimar committed
465
    if( p_vout->b_autoscale )
Sam Hocevar's avatar
 
Sam Hocevar committed
466 467 468 469
    {
        *pi_width = i_width;
        *pi_height = i_height;
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
470
    else
471
    {
Laurent Aimar's avatar
Laurent Aimar committed
472 473
        int i_zoom = p_vout->i_zoom;
        /* be realistic, scaling factor confined between .2 and 10. */
474 475
        if( i_zoom > 10 * ZOOM_FP_FACTOR )      i_zoom = 10 * ZOOM_FP_FACTOR;
        else if( i_zoom <  ZOOM_FP_FACTOR / 5 ) i_zoom = ZOOM_FP_FACTOR / 5;
Laurent Aimar's avatar
Laurent Aimar committed
476

477 478 479 480 481 482 483 484 485 486 487 488 489 490
        unsigned int i_original_width, i_original_height;

        if( p_vout->fmt_in.i_sar_num >= p_vout->fmt_in.i_sar_den )
        {
            i_original_width = p_vout->fmt_in.i_visible_width *
                               p_vout->fmt_in.i_sar_num / p_vout->fmt_in.i_sar_den;
            i_original_height =  p_vout->fmt_in.i_visible_height;
        }
        else
        {
            i_original_width =  p_vout->fmt_in.i_visible_width;
            i_original_height = p_vout->fmt_in.i_visible_height *
                                p_vout->fmt_in.i_sar_den / p_vout->fmt_in.i_sar_num;
        }
491 492 493 494 495
#ifdef WIN32
        /* On windows, inner video window exceeding container leads to black screen */
        *pi_width = __MIN( i_width, i_original_width * i_zoom / ZOOM_FP_FACTOR );
        *pi_height = __MIN( i_height, i_original_height * i_zoom / ZOOM_FP_FACTOR );
#else
496 497
        *pi_width = i_original_width * i_zoom / ZOOM_FP_FACTOR ;
        *pi_height = i_original_height * i_zoom / ZOOM_FP_FACTOR ;
498
#endif
499
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
500

Laurent Aimar's avatar
Laurent Aimar committed
501
    int64_t i_scaled_width = p_vout->fmt_in.i_visible_width * (int64_t)p_vout->fmt_in.i_sar_num *
502
                              *pi_height / p_vout->fmt_in.i_visible_height / p_vout->fmt_in.i_sar_den;
Laurent Aimar's avatar
Laurent Aimar committed
503
    int64_t i_scaled_height = p_vout->fmt_in.i_visible_height * (int64_t)p_vout->fmt_in.i_sar_den *
504 505 506
                               *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
507
    {
508 509 510
        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
511
    }
512 513 514

    if( i_scaled_width > *pi_width )
        *pi_height = i_scaled_height;
Sam Hocevar's avatar
 
Sam Hocevar committed
515
    else
516
        *pi_width = i_scaled_width;
Sam Hocevar's avatar
 
Sam Hocevar committed
517

gbazin's avatar
 
gbazin committed
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
    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
541 542
}

543 544 545
/**
 * Allocate a new picture in the heap.
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
546 547 548
 * 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.
549
 */
550 551 552
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
553
{
554 555 556 557 558
    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
559

560 561 562 563 564 565
    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
566 567

    /* Calculate how big the new image should be */
gbazin's avatar
 
gbazin committed
568
    i_bytes = p_pic->format.i_bits_per_pixel *
569
        i_width_aligned * i_height_aligned / 8;
gbazin's avatar
 
gbazin committed
570 571 572 573 574 575

    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;
576
        return VLC_EGENERIC;
gbazin's avatar
 
gbazin committed
577 578 579 580 581 582 583
    }

    /* 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++ )
    {
584 585
        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
586
    }
587 588

    return VLC_SUCCESS;
gbazin's avatar
 
gbazin committed
589 590
}

591 592 593
/**
 * Initialise the video format fields given chroma/size.
 *
gbazin's avatar
 
gbazin committed
594 595
 * This function initializes all the video_frame_format_t fields given the
 * static properties of a picture (chroma and size).
596 597 598 599 600 601
 * \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
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
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 )
    {
621 622 623
        case FOURCC_YUVA:
            p_format->i_bits_per_pixel = 32;
            break;
gbazin's avatar
 
gbazin committed
624
        case FOURCC_I444:
625
        case FOURCC_J444:
gbazin's avatar
 
gbazin committed
626 627 628 629
            p_format->i_bits_per_pixel = 24;
            break;
        case FOURCC_I422:
        case FOURCC_YUY2:
630
        case FOURCC_UYVY:
631
        case FOURCC_J422:
gbazin's avatar
 
gbazin committed
632 633
            p_format->i_bits_per_pixel = 16;
            break;
634 635 636 637
        case FOURCC_I440:
        case FOURCC_J440:
            p_format->i_bits_per_pixel = 16;
            break;
gbazin's avatar
 
gbazin committed
638 639 640
        case FOURCC_I411:
        case FOURCC_YV12:
        case FOURCC_I420:
641
        case FOURCC_J420:
gbazin's avatar
 
gbazin committed
642 643 644 645
        case FOURCC_IYUV:
            p_format->i_bits_per_pixel = 12;
            break;
        case FOURCC_I410:
646
        case FOURCC_YVU9:
647
            p_format->i_bits_per_pixel = 9;
gbazin's avatar
 
gbazin committed
648 649 650 651
            break;
        case FOURCC_Y211:
            p_format->i_bits_per_pixel = 8;
            break;
652 653 654 655
        case FOURCC_YUVP:
            p_format->i_bits_per_pixel = 8;
            break;

gbazin's avatar
 
gbazin committed
656
        case FOURCC_RV32:
657
        case FOURCC_RGBA:
gbazin's avatar
 
gbazin committed
658 659 660 661 662 663 664 665 666 667 668 669
            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;
670 671

        case FOURCC_GREY:
672 673
        case FOURCC_Y800:
        case FOURCC_Y8:
674
        case FOURCC_RGBP:
675 676 677
            p_format->i_bits_per_pixel = 8;
            break;

gbazin's avatar
 
gbazin committed
678 679 680 681 682 683
        default:
            p_format->i_bits_per_pixel = 0;
            break;
    }
}

684 685 686
/**
 * Initialise the picture_t fields given chroma/size.
 *
gbazin's avatar
 
gbazin committed
687 688
 * This function initializes most of the picture_t fields given a chroma and
 * size. It makes the assumption that stride == width.
689 690 691 692 693 694 695
 * \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
 */
696 697 698
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
699
{
700
    int i_index, i_width_aligned, i_height_aligned;
gbazin's avatar
 
gbazin committed
701

Sam Hocevar's avatar
 
Sam Hocevar committed
702 703 704 705
    /* Store default values */
    for( i_index = 0; i_index < VOUT_MAX_PLANES; i_index++ )
    {
        p_pic->p[i_index].p_pixels = NULL;
706
        p_pic->p[i_index].i_pixel_pitch = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
707 708
    }

709 710 711
    p_pic->pf_release = NULL;
    p_pic->pf_lock = NULL;
    p_pic->pf_unlock = NULL;
712 713
    p_pic->i_refcount = 0;

714
    p_pic->i_qtype = QTYPE_NONE;
715
    p_pic->i_qstride = 0;
716
    p_pic->p_q = NULL;
717

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

720 721 722 723
    /* 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
724
    /* Calculate coordinates */
Sam Hocevar's avatar
 
Sam Hocevar committed
725
    switch( i_chroma )
Sam Hocevar's avatar
 
Sam Hocevar committed
726
    {
gbazin's avatar
 
gbazin committed
727
        case FOURCC_I411:
728 729
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
730 731
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
732 733
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
734 735
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned / 4;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width / 4;
736 737
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
738 739
            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
740 741 742
            p_pic->i_planes = 3;
            break;

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

Sam Hocevar's avatar
 
Sam Hocevar committed
760
        case FOURCC_YV12:
Sam Hocevar's avatar
 
Sam Hocevar committed
761 762
        case FOURCC_I420:
        case FOURCC_IYUV:
763
        case FOURCC_J420:
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 / 2;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height / 2;
770 771
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned / 2;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width / 2;
772 773
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned / 2;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height / 2;
774 775
            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
776
            p_pic->i_planes = 3;
Sam Hocevar's avatar
 
Sam Hocevar committed
777 778
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
779
        case FOURCC_I422:
780
        case FOURCC_J422:
781 782
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
783 784
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
785 786
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
787 788
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned / 2;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width / 2;
789 790
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
791 792
            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
793
            p_pic->i_planes = 3;
Sam Hocevar's avatar
 
Sam Hocevar committed
794 795
            break;

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
        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
813
        case FOURCC_I444:
814
        case FOURCC_J444:
815 816
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
817 818
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
819 820
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
821 822
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width;
823 824
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
825 826
            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
827 828 829
            p_pic->i_planes = 3;
            break;

830
        case FOURCC_YUVA:
831 832
            p_pic->p[ Y_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ Y_PLANE ].i_visible_lines = i_height;
833 834
            p_pic->p[ Y_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ Y_PLANE ].i_visible_pitch = i_width;
835 836
            p_pic->p[ U_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ U_PLANE ].i_visible_lines = i_height;
837 838
            p_pic->p[ U_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ U_PLANE ].i_visible_pitch = i_width;
839 840
            p_pic->p[ V_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ V_PLANE ].i_visible_lines = i_height;
841 842
            p_pic->p[ V_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ V_PLANE ].i_visible_pitch = i_width;
843 844
            p_pic->p[ A_PLANE ].i_lines = i_height_aligned;
            p_pic->p[ A_PLANE ].i_visible_lines = i_height;
845 846
            p_pic->p[ A_PLANE ].i_pitch = i_width_aligned;
            p_pic->p[ A_PLANE ].i_visible_pitch = i_width;
847 848 849 850
            p_pic->i_planes = 4;
            break;

        case FOURCC_YUVP:
851 852
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
853 854
            p_pic->p->i_pitch = i_width_aligned;
            p_pic->p->i_visible_pitch = i_width;
855 856 857 858
            p_pic->p->i_pixel_pitch = 8;
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
859
        case FOURCC_Y211:
860 861
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
862 863
            p_pic->p->i_pitch = i_width_aligned;
            p_pic->p->i_visible_pitch = i_width;
864
            p_pic->p->i_pixel_pitch = 4;
Sam Hocevar's avatar
 
Sam Hocevar committed
865 866 867
            p_pic->i_planes = 1;
            break;

868
        case FOURCC_UYVY:
869
        case FOURCC_YUY2:
870 871
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
872 873
            p_pic->p->i_pitch = i_width_aligned * 2;
            p_pic->p->i_visible_pitch = i_width * 2;
874
            p_pic->p->i_pixel_pitch = 4;
875 876 877
            p_pic->i_planes = 1;
            break;

878
        case FOURCC_RGB2:
879 880
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
881 882
            p_pic->p->i_pitch = i_width_aligned;
            p_pic->p->i_visible_pitch = i_width;
883 884 885 886
            p_pic->p->i_pixel_pitch = 1;
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
887
        case FOURCC_RV15:
888 889
            p_pic->p->i_lines = i_height_aligned;
            p_pic->p->i_visible_lines = i_height;
890 891
            p_pic->p->i_pitch = i_width_aligned * 2;
            p_pic->p->i_visible_pitch = i_width * 2;
892
            p_pic->p->i_pixel_pitch = 2;