vout_pictures.c 30 KB
Newer Older
Sam Hocevar's avatar
 
Sam Hocevar committed
1 2 3
/*****************************************************************************
 * vout_pictures.c : picture management functions
 *****************************************************************************
zorglub's avatar
zorglub committed
4
 * Copyright (C) 2000-2004 VideoLAN
5
 * $Id: vout_pictures.c,v 1.47 2004/02/27 14:01:35 fenrir Exp $
Sam Hocevar's avatar
 
Sam Hocevar committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                                /* free() */
#include <stdio.h>                                              /* sprintf() */
#include <string.h>                                            /* strerror() */

32
#include <vlc/vlc.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
33

34
#include "vlc_video.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
35 36
#include "video_output.h"

37 38
#include "vout_pictures.h"

39 40 41
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
42
static void CopyPicture( vout_thread_t *, picture_t *, picture_t * );
43

Sam Hocevar's avatar
 
Sam Hocevar committed
44 45 46
/*****************************************************************************
 * vout_DisplayPicture: display a picture
 *****************************************************************************
gbazin's avatar
 
gbazin committed
47 48
 * Remove the reservation flag of a picture, which will cause it to be ready
 * for display. The picture won't be displayed until vout_DatePicture has been
Sam Hocevar's avatar
 
Sam Hocevar committed
49 50
 * called.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
51
void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
52 53
{
    vlc_mutex_lock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
54
    switch( p_pic->i_status )
Sam Hocevar's avatar
 
Sam Hocevar committed
55 56
    {
    case RESERVED_PICTURE:
Sam Hocevar's avatar
 
Sam Hocevar committed
57
        p_pic->i_status = RESERVED_DISP_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
58 59
        break;
    case RESERVED_DATED_PICTURE:
Sam Hocevar's avatar
 
Sam Hocevar committed
60
        p_pic->i_status = READY_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
61 62
        break;
    default:
63 64
        msg_Err( p_vout, "picture to display %p has invalid status %d",
                         p_pic, p_pic->i_status );
Sam Hocevar's avatar
 
Sam Hocevar committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78
        break;
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}

/*****************************************************************************
 * vout_DatePicture: date a picture
 *****************************************************************************
 * Remove the reservation flag of a picture, which will cause it to be ready
 * for display. The picture won't be displayed until vout_DisplayPicture has
 * been called.
 *****************************************************************************/
void vout_DatePicture( vout_thread_t *p_vout,
Sam Hocevar's avatar
 
Sam Hocevar committed
79
                       picture_t *p_pic, mtime_t date )
Sam Hocevar's avatar
 
Sam Hocevar committed
80 81
{
    vlc_mutex_lock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
82 83
    p_pic->date = date;
    switch( p_pic->i_status )
Sam Hocevar's avatar
 
Sam Hocevar committed
84 85
    {
    case RESERVED_PICTURE:
Sam Hocevar's avatar
 
Sam Hocevar committed
86
        p_pic->i_status = RESERVED_DATED_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
87 88
        break;
    case RESERVED_DISP_PICTURE:
Sam Hocevar's avatar
 
Sam Hocevar committed
89
        p_pic->i_status = READY_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
90 91
        break;
    default:
92 93
        msg_Err( p_vout, "picture to date %p has invalid status %d",
                         p_pic, p_pic->i_status );
Sam Hocevar's avatar
 
Sam Hocevar committed
94 95 96 97 98 99 100 101 102 103 104
        break;
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}

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

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
139
                p_pic->b_progressive        = b_progressive;
140
                p_pic->i_nb_fields          = i_nb_fields;
Sam Hocevar's avatar
 
Sam Hocevar committed
141
                p_pic->b_top_field_first    = b_top_field_first;
Sam Hocevar's avatar
 
Sam Hocevar committed
142

Sam Hocevar's avatar
 
Sam Hocevar committed
143
                p_vout->i_heap_size++;
gbazin's avatar
 
gbazin committed
144 145 146
                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
147
                vlc_mutex_unlock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
148
                return( p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
149

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

            default:
                break;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
161 162 163 164 165
    }

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

Sam Hocevar's avatar
 
Sam Hocevar committed
173
        if( p_freepic->i_planes )
Sam Hocevar's avatar
 
Sam Hocevar committed
174 175
        {
            /* Copy picture information, set some default values */
Sam Hocevar's avatar
 
Sam Hocevar committed
176 177
            p_freepic->i_status   = RESERVED_PICTURE;
            p_freepic->i_type     = MEMORY_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
178

Sam Hocevar's avatar
 
Sam Hocevar committed
179
            p_freepic->i_refcount = 0;
180
            p_freepic->b_force = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
181

Sam Hocevar's avatar
 
Sam Hocevar committed
182
            p_freepic->b_progressive        = b_progressive;
183
            p_freepic->i_nb_fields          = i_nb_fields;
Sam Hocevar's avatar
 
Sam Hocevar committed
184
            p_freepic->b_top_field_first    = b_top_field_first;
Sam Hocevar's avatar
 
Sam Hocevar committed
185

Sam Hocevar's avatar
 
Sam Hocevar committed
186
            p_freepic->i_matrix_coefficients = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
187

Sam Hocevar's avatar
 
Sam Hocevar committed
188
            p_vout->i_heap_size++;
Sam Hocevar's avatar
 
Sam Hocevar committed
189 190 191 192
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
Sam Hocevar's avatar
 
Sam Hocevar committed
193 194
            p_freepic->i_status = FREE_PICTURE;
            p_freepic = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
195

196
            msg_Err( p_vout, "picture allocation failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
197 198 199 200
        }

        vlc_mutex_unlock( &p_vout->picture_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
201
        return( p_freepic );
Sam Hocevar's avatar
 
Sam Hocevar committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
    }

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

/*****************************************************************************
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
 *****************************************************************************
 * 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 !
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
218
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
219 220 221 222 223
{
    vlc_mutex_lock( &p_vout->picture_lock );

#ifdef DEBUG
    /* Check if picture status is valid */
Sam Hocevar's avatar
 
Sam Hocevar committed
224 225 226
    if( (p_pic->i_status != RESERVED_PICTURE) &&
        (p_pic->i_status != RESERVED_DATED_PICTURE) &&
        (p_pic->i_status != RESERVED_DISP_PICTURE) )
Sam Hocevar's avatar
 
Sam Hocevar committed
227
    {
228 229
        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
230 231 232
    }
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
233
    p_pic->i_status = DESTROYED_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
234
    p_vout->i_heap_size--;
Sam Hocevar's avatar
 
Sam Hocevar committed
235 236 237 238 239 240 241 242 243 244

    vlc_mutex_unlock( &p_vout->picture_lock );
}

/*****************************************************************************
 * vout_LinkPicture: increment reference counter of a picture
 *****************************************************************************
 * 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.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
245
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
246 247
{
    vlc_mutex_lock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
248
    p_pic->i_refcount++;
Sam Hocevar's avatar
 
Sam Hocevar committed
249 250 251 252 253 254
    vlc_mutex_unlock( &p_vout->picture_lock );
}

/*****************************************************************************
 * vout_UnlinkPicture: decrement reference counter of a picture
 *****************************************************************************
gbazin's avatar
 
gbazin committed
255
 * This function decrement the reference counter of a picture in the video heap
Sam Hocevar's avatar
 
Sam Hocevar committed
256
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
257
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
Sam Hocevar's avatar
 
Sam Hocevar committed
258 259
{
    vlc_mutex_lock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
260
    p_pic->i_refcount--;
Sam Hocevar's avatar
 
Sam Hocevar committed
261

Sam Hocevar's avatar
 
Sam Hocevar committed
262
    if( p_pic->i_refcount < 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
263
    {
zorglub's avatar
zorglub committed
264
        msg_Err( p_vout, "picture %p refcount is %i",
265
                 p_pic, p_pic->i_refcount );
Sam Hocevar's avatar
 
Sam Hocevar committed
266
        p_pic->i_refcount = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
267 268
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
269 270
    if( ( p_pic->i_refcount == 0 ) &&
        ( p_pic->i_status == DISPLAYED_PICTURE ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
271
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
272
        p_pic->i_status = DESTROYED_PICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
273
        p_vout->i_heap_size--;
Sam Hocevar's avatar
 
Sam Hocevar committed
274 275 276 277 278 279 280 281 282 283 284 285
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}

/*****************************************************************************
 * vout_RenderPicture: render a picture
 *****************************************************************************
 * 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.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
286
picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
Sam Hocevar's avatar
 
Sam Hocevar committed
287 288
                                                       subpicture_t *p_subpic )
{
Sam Hocevar's avatar
 
Sam Hocevar committed
289
    if( p_pic == NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
290 291 292 293 294 295
    {
        /* XXX: subtitles */

        return NULL;
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
296
    if( p_pic->i_type == DIRECT_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
297
    {
gbazin's avatar
 
gbazin committed
298
        if( !p_vout->render.b_allow_modify_pics || p_pic->i_refcount )
Sam Hocevar's avatar
 
Sam Hocevar committed
299 300 301 302 303 304 305 306 307
        {
            /* Picture is in a direct buffer and is still in use,
             * we need to copy it to another direct buffer before
             * displaying it if there are subtitles. */
            if( p_subpic != NULL )
            {
                /* We have subtitles. First copy the picture to
                 * the spare direct buffer, then render the
                 * subtitles. */
308
                CopyPicture( p_vout, p_pic, PP_OUTPUTPICTURE[0] );
Sam Hocevar's avatar
 
Sam Hocevar committed
309

Sam Hocevar's avatar
 
Sam Hocevar committed
310
                vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic );
Sam Hocevar's avatar
 
Sam Hocevar committed
311

Sam Hocevar's avatar
 
Sam Hocevar committed
312
                return PP_OUTPUTPICTURE[0];
Sam Hocevar's avatar
 
Sam Hocevar committed
313 314 315 316 317
            }

            /* No subtitles, picture is in a directbuffer so
             * we can display it directly even if it is still
             * in use. */
Sam Hocevar's avatar
 
Sam Hocevar committed
318
            return p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
319 320 321 322 323
        }

        /* Picture is in a direct buffer but isn't used by the
         * decoder. We can safely render subtitles on it and
         * display it. */
Sam Hocevar's avatar
 
Sam Hocevar committed
324
        vout_RenderSubPictures( p_vout, p_pic, p_subpic );
Sam Hocevar's avatar
 
Sam Hocevar committed
325

Sam Hocevar's avatar
 
Sam Hocevar committed
326
        return p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
327 328 329 330
    }

    /* Not a direct buffer. We either need to copy it to a direct buffer,
     * or render it if the chroma isn't the same. */
Sam Hocevar's avatar
 
Sam Hocevar committed
331
    if( p_vout->b_direct )
Sam Hocevar's avatar
 
Sam Hocevar committed
332 333 334 335
    {
        /* 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
336 337 338 339 340 341 342 343 344 345

        if( PP_OUTPUTPICTURE[0]->pf_lock )
            if( PP_OUTPUTPICTURE[0]->pf_lock( p_vout, PP_OUTPUTPICTURE[0] ) )
            {
                if( PP_OUTPUTPICTURE[0]->pf_unlock )
                PP_OUTPUTPICTURE[0]->pf_unlock( p_vout, PP_OUTPUTPICTURE[0] );

                return NULL;
            }

346
        CopyPicture( p_vout, p_pic, PP_OUTPUTPICTURE[0] );
Sam Hocevar's avatar
 
Sam Hocevar committed
347

Sam Hocevar's avatar
 
Sam Hocevar committed
348
        vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic );
Sam Hocevar's avatar
 
Sam Hocevar committed
349

gbazin's avatar
 
gbazin committed
350 351 352
        if( PP_OUTPUTPICTURE[0]->pf_unlock )
            PP_OUTPUTPICTURE[0]->pf_unlock( p_vout, PP_OUTPUTPICTURE[0] );

Sam Hocevar's avatar
 
Sam Hocevar committed
353
        return PP_OUTPUTPICTURE[0];
Sam Hocevar's avatar
 
Sam Hocevar committed
354 355 356 357
    }

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

gbazin's avatar
 
gbazin committed
361 362 363 364
    if( p_vout->p_picture[0].pf_lock )
        if( p_vout->p_picture[0].pf_lock( p_vout, &p_vout->p_picture[0] ) )
            return NULL;

Sam Hocevar's avatar
 
Sam Hocevar committed
365
    /* Convert image to the first direct buffer */
Sam Hocevar's avatar
 
Sam Hocevar committed
366
    p_vout->chroma.pf_convert( p_vout, p_pic, &p_vout->p_picture[0] );
Sam Hocevar's avatar
 
Sam Hocevar committed
367

Sam Hocevar's avatar
 
Sam Hocevar committed
368 369 370
    /* Render subpictures on the first direct buffer */
    vout_RenderSubPictures( p_vout, &p_vout->p_picture[0], p_subpic );

gbazin's avatar
 
gbazin committed
371 372 373
    if( p_vout->p_picture[0].pf_unlock )
        p_vout->p_picture[0].pf_unlock( p_vout, &p_vout->p_picture[0] );

Sam Hocevar's avatar
 
Sam Hocevar committed
374 375 376
    return &p_vout->p_picture[0];
}

Sam Hocevar's avatar
 
Sam Hocevar committed
377 378 379 380 381 382
/*****************************************************************************
 * vout_PlacePicture: calculate image window coordinates
 *****************************************************************************
 * This function will be accessed by plugins. It calculates the relative
 * position of the output window and the image window.
 *****************************************************************************/
383 384 385 386
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
387
{
gbazin's avatar
 
gbazin committed
388
    if( (i_width <= 0) || (i_height <=0) )
gbazin's avatar
 
gbazin committed
389 390 391
    {
        *pi_width = *pi_height = *pi_x = *pi_y = 0;

gbazin's avatar
 
gbazin committed
392
        return;
gbazin's avatar
 
gbazin committed
393
    }
gbazin's avatar
 
gbazin committed
394

Sam Hocevar's avatar
 
Sam Hocevar committed
395 396 397 398 399 400 401
    if( p_vout->b_scale )
    {
        *pi_width = i_width;
        *pi_height = i_height;
    }
    else
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
402 403
        *pi_width = __MIN( i_width, p_vout->render.i_width );
        *pi_height = __MIN( i_height, p_vout->render.i_height );
Sam Hocevar's avatar
 
Sam Hocevar committed
404 405
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
406
    if( VOUT_ASPECT_FACTOR * *pi_width / *pi_height < p_vout->render.i_aspect )
Sam Hocevar's avatar
 
Sam Hocevar committed
407
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
408
        *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
Sam Hocevar's avatar
 
Sam Hocevar committed
409 410 411
    }
    else
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
412
        *pi_height = *pi_width * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
Sam Hocevar's avatar
 
Sam Hocevar committed
413 414 415 416 417
    }

    if( *pi_width > i_width )
    {
        *pi_width = i_width;
Sam Hocevar's avatar
 
Sam Hocevar committed
418
        *pi_height = VOUT_ASPECT_FACTOR * *pi_width / p_vout->render.i_aspect;
Sam Hocevar's avatar
 
Sam Hocevar committed
419 420 421 422 423
    }

    if( *pi_height > i_height )
    {
        *pi_height = i_height;
Sam Hocevar's avatar
 
Sam Hocevar committed
424
        *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
Sam Hocevar's avatar
 
Sam Hocevar committed
425 426
    }

gbazin's avatar
 
gbazin committed
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
    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
450 451
}

Sam Hocevar's avatar
 
Sam Hocevar committed
452
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
453
 * vout_AllocatePicture: allocate a new picture in the heap.
Sam Hocevar's avatar
 
Sam Hocevar committed
454 455 456 457 458
 *****************************************************************************
 * 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.
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
459
void vout_AllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
gbazin's avatar
 
gbazin committed
460 461
                           vlc_fourcc_t i_chroma,
                           int i_width, int i_height, int i_aspect )
Sam Hocevar's avatar
 
Sam Hocevar committed
462
{
Sam Hocevar's avatar
 
Sam Hocevar committed
463
    int i_bytes, i_index;
Sam Hocevar's avatar
 
Sam Hocevar committed
464

gbazin's avatar
 
gbazin committed
465
    vout_InitPicture( p_this, p_pic, i_chroma,
gbazin's avatar
 
gbazin committed
466
                      i_width, i_height, i_aspect );
gbazin's avatar
 
gbazin committed
467 468

    /* Calculate how big the new image should be */
gbazin's avatar
 
gbazin committed
469 470
    i_bytes = p_pic->format.i_bits_per_pixel *
        p_pic->format.i_width * p_pic->format.i_height / 8;
gbazin's avatar
 
gbazin committed
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490

    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;
        return;
    }

    /* 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++ )
    {
        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
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
/*****************************************************************************
 * vout_InitFormat: initialise the video format fields given chroma/size.
 *****************************************************************************
 * This function initializes all the video_frame_format_t fields given the
 * static properties of a picture (chroma and size).
 *****************************************************************************/
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 )
    {
        case FOURCC_I444:
            p_format->i_bits_per_pixel = 24;
            break;
        case FOURCC_I422:
        case FOURCC_YUY2:
            p_format->i_bits_per_pixel = 16;
            p_format->i_bits_per_pixel = 16;
            break;
        case FOURCC_I411:
        case FOURCC_YV12:
        case FOURCC_I420:
        case FOURCC_IYUV:
            p_format->i_bits_per_pixel = 12;
            break;
        case FOURCC_I410:
531
        case FOURCC_YVU9:
gbazin's avatar
 
gbazin committed
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
            p_format->i_bits_per_pixel = 9;
            break;
        case FOURCC_Y211:
            p_format->i_bits_per_pixel = 8;
            break;
        case FOURCC_RV32:
            p_format->i_bits_per_pixel = 32;
            break;
        case FOURCC_RV24:
            /* FIXME: Should be 24 here but x11 and our chroma conversion
             * routines assume 32. */
#ifdef WIN32
            p_format->i_bits_per_pixel = 24;
#else
            p_format->i_bits_per_pixel = 32;
#endif
            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;
        default:
            p_format->i_bits_per_pixel = 0;
            break;
    }
}

gbazin's avatar
 
gbazin committed
562 563 564 565 566 567 568
/*****************************************************************************
 * vout_InitPicture: initialise the picture_t fields given chroma/size.
 *****************************************************************************
 * This function initializes most of the picture_t fields given a chroma and
 * size. It makes the assumption that stride == width.
 *****************************************************************************/
void vout_InitPicture( vlc_object_t *p_this, picture_t *p_pic,
gbazin's avatar
 
gbazin committed
569 570
                       vlc_fourcc_t i_chroma,
                       int i_width, int i_height, int i_aspect )
gbazin's avatar
 
gbazin committed
571 572 573
{
    int i_index;

Sam Hocevar's avatar
 
Sam Hocevar committed
574 575 576 577
    /* Store default values */
    for( i_index = 0; i_index < VOUT_MAX_PLANES; i_index++ )
    {
        p_pic->p[i_index].p_pixels = NULL;
578
        p_pic->p[i_index].i_pixel_pitch = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
579 580
    }

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

Sam Hocevar's avatar
 
Sam Hocevar committed
583
    /* Calculate coordinates */
Sam Hocevar's avatar
 
Sam Hocevar committed
584
    switch( i_chroma )
Sam Hocevar's avatar
 
Sam Hocevar committed
585
    {
gbazin's avatar
 
gbazin committed
586 587 588 589 590 591 592 593 594 595 596 597 598
        case FOURCC_I411:
            p_pic->p[ Y_PLANE ].i_lines = i_height;
            p_pic->p[ Y_PLANE ].i_pitch = i_width;
            p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
            p_pic->p[ U_PLANE ].i_lines = i_height;
            p_pic->p[ U_PLANE ].i_pitch = i_width / 4;
            p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
            p_pic->p[ V_PLANE ].i_lines = i_height;
            p_pic->p[ V_PLANE ].i_pitch = i_width / 4;
            p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
            p_pic->i_planes = 3;
            break;

599
        case FOURCC_I410:
600
        case FOURCC_YVU9:
601 602 603 604 605 606 607 608 609 610 611 612
            p_pic->p[ Y_PLANE ].i_lines = i_height;
            p_pic->p[ Y_PLANE ].i_pitch = i_width;
            p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
            p_pic->p[ U_PLANE ].i_lines = i_height / 4;
            p_pic->p[ U_PLANE ].i_pitch = i_width / 4;
            p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
            p_pic->p[ V_PLANE ].i_lines = i_height / 4;
            p_pic->p[ V_PLANE ].i_pitch = i_width / 4;
            p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
            p_pic->i_planes = 3;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
613
        case FOURCC_YV12:
Sam Hocevar's avatar
 
Sam Hocevar committed
614 615
        case FOURCC_I420:
        case FOURCC_IYUV:
Sam Hocevar's avatar
 
Sam Hocevar committed
616 617
            p_pic->p[ Y_PLANE ].i_lines = i_height;
            p_pic->p[ Y_PLANE ].i_pitch = i_width;
618
            p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
619 620
            p_pic->p[ U_PLANE ].i_lines = i_height / 2;
            p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
621
            p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
622 623
            p_pic->p[ V_PLANE ].i_lines = i_height / 2;
            p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
624
            p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
625
            p_pic->i_planes = 3;
Sam Hocevar's avatar
 
Sam Hocevar committed
626 627
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
628 629 630
        case FOURCC_I422:
            p_pic->p[ Y_PLANE ].i_lines = i_height;
            p_pic->p[ Y_PLANE ].i_pitch = i_width;
631
            p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
632 633
            p_pic->p[ U_PLANE ].i_lines = i_height;
            p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
634
            p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
635 636
            p_pic->p[ V_PLANE ].i_lines = i_height;
            p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
637
            p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
638
            p_pic->i_planes = 3;
Sam Hocevar's avatar
 
Sam Hocevar committed
639 640
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
641 642 643
        case FOURCC_I444:
            p_pic->p[ Y_PLANE ].i_lines = i_height;
            p_pic->p[ Y_PLANE ].i_pitch = i_width;
644
            p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
645 646
            p_pic->p[ U_PLANE ].i_lines = i_height;
            p_pic->p[ U_PLANE ].i_pitch = i_width;
647
            p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
648 649
            p_pic->p[ V_PLANE ].i_lines = i_height;
            p_pic->p[ V_PLANE ].i_pitch = i_width;
650
            p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
Sam Hocevar's avatar
 
Sam Hocevar committed
651 652 653 654 655 656
            p_pic->i_planes = 3;
            break;

        case FOURCC_Y211:
            p_pic->p->i_lines = i_height;
            p_pic->p->i_pitch = i_width;
657 658
            p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
            p_pic->p->i_pixel_pitch = 4;
Sam Hocevar's avatar
 
Sam Hocevar committed
659 660 661
            p_pic->i_planes = 1;
            break;

662 663 664
        case FOURCC_YUY2:
            p_pic->p->i_lines = i_height;
            p_pic->p->i_pitch = i_width * 2;
665 666
            p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
            p_pic->p->i_pixel_pitch = 4;
667 668 669
            p_pic->i_planes = 1;
            break;

670 671 672 673 674 675 676 677
        case FOURCC_RGB2:
            p_pic->p->i_lines = i_height;
            p_pic->p->i_pitch = i_width;
            p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
            p_pic->p->i_pixel_pitch = 1;
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
678 679 680
        case FOURCC_RV15:
            p_pic->p->i_lines = i_height;
            p_pic->p->i_pitch = i_width * 2;
681 682
            p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
            p_pic->p->i_pixel_pitch = 2;
683
/* FIXME: p_heap isn't always reachable
Sam Hocevar's avatar
 
Sam Hocevar committed
684 685
            p_pic->p_heap->i_rmask = 0x001f;
            p_pic->p_heap->i_gmask = 0x03e0;
686
            p_pic->p_heap->i_bmask = 0x7c00; */
Sam Hocevar's avatar
 
Sam Hocevar committed
687 688 689 690 691 692
            p_pic->i_planes = 1;
            break;

        case FOURCC_RV16:
            p_pic->p->i_lines = i_height;
            p_pic->p->i_pitch = i_width * 2;
693 694
            p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
            p_pic->p->i_pixel_pitch = 2;
695
/* FIXME: p_heap isn't always reachable
Sam Hocevar's avatar
 
Sam Hocevar committed
696 697
            p_pic->p_heap->i_rmask = 0x001f;
            p_pic->p_heap->i_gmask = 0x07e0;
698
            p_pic->p_heap->i_bmask = 0xf800; */
Sam Hocevar's avatar
 
Sam Hocevar committed
699
            p_pic->i_planes = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
700 701
            break;

gbazin's avatar
 
gbazin committed
702 703
        case FOURCC_RV24:
            p_pic->p->i_lines = i_height;
gbazin's avatar
 
gbazin committed
704 705 706 707

            /* FIXME: Should be 3 here but x11 and our chroma conversion
             * routines assume 4. */
#ifdef WIN32
gbazin's avatar
 
gbazin committed
708 709
            p_pic->p->i_pitch = i_width * 3;
            p_pic->p->i_pixel_pitch = 3;
gbazin's avatar
 
gbazin committed
710 711 712 713 714
#else
            p_pic->p->i_pitch = i_width * 4;
            p_pic->p->i_pixel_pitch = 4;
#endif
            p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
gbazin's avatar
 
gbazin committed
715 716 717 718 719 720 721
/* FIXME: p_heap isn't always reachable
            p_pic->p_heap->i_rmask = 0xff0000;
            p_pic->p_heap->i_gmask = 0x00ff00;
            p_pic->p_heap->i_bmask = 0x0000ff; */
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
722 723 724
        case FOURCC_RV32:
            p_pic->p->i_lines = i_height;
            p_pic->p->i_pitch = i_width * 4;
725 726
            p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
            p_pic->p->i_pixel_pitch = 4;
727
/* FIXME: p_heap isn't always reachable
Sam Hocevar's avatar
 
Sam Hocevar committed
728 729
            p_pic->p_heap->i_rmask = 0xff0000;
            p_pic->p_heap->i_gmask = 0x00ff00;
730
            p_pic->p_heap->i_bmask = 0x0000ff; */
Sam Hocevar's avatar
 
Sam Hocevar committed
731 732 733
            p_pic->i_planes = 1;
            break;

Sam Hocevar's avatar
 
Sam Hocevar committed
734
        default:
gbazin's avatar
 
gbazin committed
735
            msg_Err( p_this, "unknown chroma type 0x%.8x (%4.4s)",
736
                             i_chroma, (char*)&i_chroma );
Sam Hocevar's avatar
 
Sam Hocevar committed
737
            p_pic->i_planes = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
738 739 740 741
            return;
    }
}

742 743 744 745
/*****************************************************************************
 * vout_ChromaCmp: compare two chroma values
 *****************************************************************************
 * This function returns 1 if the two fourcc values given as argument are
gbazin's avatar
 
gbazin committed
746
 * the same format (eg. UYVY/UYNV) or almost the same format (eg. I420/YV12)
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
 *****************************************************************************/
int vout_ChromaCmp( vlc_fourcc_t i_chroma, vlc_fourcc_t i_amorhc )
{
    /* If they are the same, they are the same ! */
    if( i_chroma == i_amorhc )
    {
        return 1;
    }

    /* Check for equivalence classes */
    switch( i_chroma )
    {
        case FOURCC_I420:
        case FOURCC_IYUV:
        case FOURCC_YV12:
            switch( i_amorhc )
            {
                case FOURCC_I420:
                case FOURCC_IYUV:
                case FOURCC_YV12:
                    return 1;

                default:
                    return 0;
            }

        case FOURCC_UYVY:
        case FOURCC_UYNV:
        case FOURCC_Y422:
            switch( i_amorhc )
            {
                case FOURCC_UYVY:
                case FOURCC_UYNV:
                case FOURCC_Y422:
                    return 1;

                default:
                    return 0;
            }

        case FOURCC_YUY2:
        case FOURCC_YUNV:
            switch( i_amorhc )
            {
                case FOURCC_YUY2:
                case FOURCC_YUNV:
                    return 1;

                default:
                    return 0;
            }

        default:
            return 0;
    }
}

804 805 806
/* Following functions are local */

/*****************************************************************************
807
 * CopyPicture: copy a picture to another one
808 809 810
 *****************************************************************************
 * This function takes advantage of the image format, and reduces the
 * number of calls to memcpy() to the minimum. Source and destination
811
 * images must have same width (hence i_visible_pitch), height, and chroma.
812
 *****************************************************************************/
813 814
static void CopyPicture( vout_thread_t * p_vout,
                         picture_t *p_src, picture_t *p_dest )
815 816 817 818 819 820 821
{
    int i;

    for( i = 0; i < p_src->i_planes ; i++ )
    {
        if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
        {
822 823 824 825
            /* There are margins, but with the same width : perfect ! */
            p_vout->p_vlc->pf_memcpy(
                         p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
                         p_src->p[i].i_pitch * p_src->p[i].i_lines );
826 827 828
        }
        else
        {
829
            /* We need to proceed line by line */
830 831
            uint8_t *p_in = p_src->p[i].p_pixels;
            uint8_t *p_out = p_dest->p[i].p_pixels;
832 833 834 835
            int i_line;

            for( i_line = p_src->p[i].i_lines; i_line--; )
            {
836
                p_vout->p_vlc->pf_memcpy( p_out, p_in,
837
                                          p_src->p[i].i_visible_pitch );
838 839 840 841 842
                p_in += p_src->p[i].i_pitch;
                p_out += p_dest->p[i].i_pitch;
            }
        }
    }
843
    p_dest->date = p_src->date;
844
}