vout_pictures.c 38.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 40
#include <vlc_image.h>
#include <vlc_block.h>
Laurent Aimar's avatar
Laurent Aimar committed
41
#include <vlc_picture_fifo.h>
42

43
#include "vout_pictures.h"
44
#include "vout_internal.h"
45

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

    if( p_pic->i_status == RESERVED_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
57
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
58
        p_pic->i_status = READY_PICTURE;
59
        vlc_cond_signal( &p_vout->p->picture_wait );
Sam Hocevar's avatar
 
Sam Hocevar committed
60
    }
61
    else
Sam Hocevar's avatar
 
Sam Hocevar committed
62
    {
63
        msg_Err( p_vout, "picture to display %p has invalid status %d",
64
                         p_pic, p_pic->i_status );
Sam Hocevar's avatar
 
Sam Hocevar committed
65
    }
66
    p_vout->p->i_picture_qtype = p_pic->i_qtype;
Sam Hocevar's avatar
 
Sam Hocevar committed
67 68 69 70

    vlc_mutex_unlock( &p_vout->picture_lock );
}

71 72 73
/**
 * Allocate a picture in the video output heap.
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
74 75
 * 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
76 77 78
 * already allocated zone of memory in the picture data fields.
 * It needs locking since several pictures can be created by several producers
 * threads.
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 105 106 107 108
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
109
picture_t *vout_CreatePicture( vout_thread_t *p_vout,
110 111
                               bool b_progressive,
                               bool 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;
178
            p_freepic->b_slow     = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
179

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

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

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

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

        vlc_mutex_unlock( &p_vout->picture_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
200
        return( p_freepic );
Sam Hocevar's avatar
 
Sam Hocevar committed
201 202 203 204 205 206 207 208 209
    }

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

210 211 212 213 214 215 216 217 218 219 220 221
/* */
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 );
}

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

244 245
    vout_DropPicture( p_vout, p_pic );
}
Sam Hocevar's avatar
 
Sam Hocevar committed
246

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
/* */
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
262 263
}

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

    vlc_mutex_unlock( &p_vout->picture_lock );
}

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

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

305 306 307 308 309 310 311 312
    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
313 314 315 316

    vlc_mutex_unlock( &p_vout->picture_lock );
}

317 318 319 320 321 322 323 324 325 326 327 328
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 );
}

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

Sam Hocevar's avatar
 
Sam Hocevar committed
342
    if( p_pic->i_type == DIRECT_PICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
343
    {
344 345 346
        /* Picture is in a direct buffer. */

        if( p_subpic != NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
347
        {
348 349 350 351 352
            /* 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
353

354
            picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
355

356 357
            spu_RenderSubpictures( p_vout->p_spu,
                                   PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
358
                                   p_subpic, &p_vout->fmt_in, b_paused );
359 360 361 362 363

            vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );

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

365 366 367
        /* 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
368
        return p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
369 370 371 372
    }

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

379 380
        if( vout_LockPicture( p_vout, PP_OUTPUTPICTURE[0] ) )
            return NULL;
gbazin's avatar
 
gbazin committed
381

382
        picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
383 384
        spu_RenderSubpictures( p_vout->p_spu,
                               PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
Laurent Aimar's avatar
Laurent Aimar committed
385
                               p_subpic, &p_vout->fmt_in, b_paused );
Sam Hocevar's avatar
 
Sam Hocevar committed
386

387
        vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );
gbazin's avatar
 
gbazin committed
388

Sam Hocevar's avatar
 
Sam Hocevar committed
389
        return PP_OUTPUTPICTURE[0];
Sam Hocevar's avatar
 
Sam Hocevar committed
390 391 392 393
    }

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

397 398 399 400 401 402 403 404 405
    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),
406 407 408 409
                                  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 );
410 411 412 413 414
            p_tmp_pic->i_type = MEMORY_PICTURE;
            p_tmp_pic->i_status = RESERVED_PICTURE;
        }

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

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

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

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

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

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

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

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

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

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

479 480 481 482 483 484 485 486 487 488 489 490 491 492
        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;
        }
493 494 495 496 497
#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
498 499
        *pi_width = i_original_width * i_zoom / ZOOM_FP_FACTOR ;
        *pi_height = i_original_height * i_zoom / ZOOM_FP_FACTOR ;
500
#endif
501
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
502

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

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

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

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

562 563
    if( picture_Setup( p_pic, i_chroma,
                       i_width, i_height, i_aspect ) != VLC_SUCCESS )
564 565 566 567
    {
        p_pic->i_planes = 0;
        return VLC_EGENERIC;
    }
gbazin's avatar
 
gbazin committed
568 569

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

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

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

    return VLC_SUCCESS;
gbazin's avatar
 
gbazin committed
591 592
}

593 594 595
/**
 * Compare two chroma values
 *
596
 * This function returns 1 if the two fourcc values given as argument are
gbazin's avatar
 
gbazin committed
597
 * the same format (eg. UYVY/UYNV) or almost the same format (eg. I420/YV12)
598
 */
599 600
int vout_ChromaCmp( vlc_fourcc_t i_chroma, vlc_fourcc_t i_amorhc )
{
Laurent Aimar's avatar
Laurent Aimar committed
601
    static const vlc_fourcc_t p_I420[] = {
602
        VLC_CODEC_I420, VLC_CODEC_YV12, VLC_CODEC_J420, 0
603 604
    };
    static const vlc_fourcc_t p_I422[] = {
605
        VLC_CODEC_I422, VLC_CODEC_J422, 0
606 607
    };
    static const vlc_fourcc_t p_I440[] = {
608
        VLC_CODEC_I440, VLC_CODEC_J440, 0
609 610
    };
    static const vlc_fourcc_t p_I444[] = {
611
        VLC_CODEC_I444, VLC_CODEC_J444, 0
Laurent Aimar's avatar
Laurent Aimar committed
612 613
    };
    static const vlc_fourcc_t *pp_fcc[] = {
614
        p_I420, p_I422, p_I440, p_I444, NULL
Laurent Aimar's avatar
Laurent Aimar committed
615 616
    };

617 618 619 620
    /* */
    i_chroma = vlc_fourcc_GetCodec( VIDEO_ES, i_chroma );
    i_amorhc = vlc_fourcc_GetCodec( VIDEO_ES, i_amorhc );

621 622 623 624 625
    /* If they are the same, they are the same ! */
    if( i_chroma == i_amorhc )
        return 1;

    /* Check for equivalence classes */
Laurent Aimar's avatar
Laurent Aimar committed
626
    for( int i = 0; pp_fcc[i] != NULL; i++ )
627
    {
Laurent Aimar's avatar
Laurent Aimar committed
628 629 630 631 632 633 634 635 636 637 638
        bool b_fcc1 = false;
        bool b_fcc2 = false;
        for( int j = 0; pp_fcc[i][j] != 0; j++ )
        {
            if( i_chroma == pp_fcc[i][j] )
                b_fcc1 = true;
            if( i_amorhc == pp_fcc[i][j] )
                b_fcc2 = true;
        }
        if( b_fcc1 && b_fcc2 )
            return 1;
639
    }
Laurent Aimar's avatar
Laurent Aimar committed
640
    return 0;
641 642
}

643 644 645 646 647 648 649 650 651
/*****************************************************************************
 *
 *****************************************************************************/
static void PictureReleaseCallback( picture_t *p_picture )
{
    if( --p_picture->i_refcount > 0 )
        return;
    picture_Delete( p_picture );
}
652

Laurent Aimar's avatar
Laurent Aimar committed
653 654 655 656 657 658 659 660 661 662 663 664 665 666
/*****************************************************************************
 *
 *****************************************************************************/
void picture_Reset( picture_t *p_picture )
{
    /* */
    p_picture->date = VLC_TS_INVALID;
    p_picture->b_force = false;
    p_picture->b_progressive = false;
    p_picture->i_nb_fields = 0;
    p_picture->b_top_field_first = false;
    picture_CleanupQuant( p_picture );
}

667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
/*****************************************************************************
 *
 *****************************************************************************/
int picture_Setup( picture_t *p_picture, vlc_fourcc_t i_chroma, int i_width, int i_height, int i_aspect )
{
    int i_index, i_width_aligned, i_height_aligned;

    /* Store default values */
    for( i_index = 0; i_index < VOUT_MAX_PLANES; i_index++ )
    {
        p_picture->p[i_index].p_pixels = NULL;
        p_picture->p[i_index].i_pixel_pitch = 1;
    }

    p_picture->pf_release = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
682
    p_picture->p_release_sys = NULL;
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 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 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
    p_picture->pf_lock = NULL;
    p_picture->pf_unlock = NULL;
    p_picture->i_refcount = 0;

    p_picture->i_qtype = QTYPE_NONE;
    p_picture->i_qstride = 0;
    p_picture->p_q = NULL;

    video_format_Setup( &p_picture->format, i_chroma, i_width, i_height, i_aspect );

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

    /* Calculate coordinates */
    switch( vlc_fourcc_GetCodec( VIDEO_ES, i_chroma ) )
    {
    case VLC_CODEC_I411:
        p_picture->p[ Y_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ Y_PLANE ].i_visible_lines = i_height;
        p_picture->p[ Y_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ Y_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ U_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ U_PLANE ].i_visible_lines = i_height;
        p_picture->p[ U_PLANE ].i_pitch = i_width_aligned / 4;
        p_picture->p[ U_PLANE ].i_visible_pitch = i_width / 4;
        p_picture->p[ V_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ V_PLANE ].i_visible_lines = i_height;
        p_picture->p[ V_PLANE ].i_pitch = i_width_aligned / 4;
        p_picture->p[ V_PLANE ].i_visible_pitch = i_width / 4;
        p_picture->i_planes = 3;
        break;

    case VLC_CODEC_I410:
        p_picture->p[ Y_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ Y_PLANE ].i_visible_lines = i_height;
        p_picture->p[ Y_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ Y_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ U_PLANE ].i_lines = i_height_aligned / 4;
        p_picture->p[ U_PLANE ].i_visible_lines = i_height / 4;
        p_picture->p[ U_PLANE ].i_pitch = i_width_aligned / 4;
        p_picture->p[ U_PLANE ].i_visible_pitch = i_width / 4;
        p_picture->p[ V_PLANE ].i_lines = i_height_aligned / 4;
        p_picture->p[ V_PLANE ].i_visible_lines = i_height / 4;
        p_picture->p[ V_PLANE ].i_pitch = i_width_aligned / 4;
        p_picture->p[ V_PLANE ].i_visible_pitch = i_width / 4;
        p_picture->i_planes = 3;
        break;

    case VLC_CODEC_YV12:
    case VLC_CODEC_I420:
    case VLC_CODEC_J420:
        p_picture->p[ Y_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ Y_PLANE ].i_visible_lines = i_height;
        p_picture->p[ Y_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ Y_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ U_PLANE ].i_lines = i_height_aligned / 2;
        p_picture->p[ U_PLANE ].i_visible_lines = i_height / 2;
        p_picture->p[ U_PLANE ].i_pitch = i_width_aligned / 2;
        p_picture->p[ U_PLANE ].i_visible_pitch = i_width / 2;
        p_picture->p[ V_PLANE ].i_lines = i_height_aligned / 2;
        p_picture->p[ V_PLANE ].i_visible_lines = i_height / 2;
        p_picture->p[ V_PLANE ].i_pitch = i_width_aligned / 2;
        p_picture->p[ V_PLANE ].i_visible_pitch = i_width / 2;
        p_picture->i_planes = 3;
        break;

    case VLC_CODEC_I422:
    case VLC_CODEC_J422:
        p_picture->p[ Y_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ Y_PLANE ].i_visible_lines = i_height;
        p_picture->p[ Y_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ Y_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ U_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ U_PLANE ].i_visible_lines = i_height;
        p_picture->p[ U_PLANE ].i_pitch = i_width_aligned / 2;
        p_picture->p[ U_PLANE ].i_visible_pitch = i_width / 2;
        p_picture->p[ V_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ V_PLANE ].i_visible_lines = i_height;
        p_picture->p[ V_PLANE ].i_pitch = i_width_aligned / 2;
        p_picture->p[ V_PLANE ].i_visible_pitch = i_width / 2;
        p_picture->i_planes = 3;
        break;

    case VLC_CODEC_I440:
    case VLC_CODEC_J440:
        p_picture->p[ Y_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ Y_PLANE ].i_visible_lines = i_height;
        p_picture->p[ Y_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ Y_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ U_PLANE ].i_lines = i_height_aligned / 2;
        p_picture->p[ U_PLANE ].i_visible_lines = i_height / 2;
        p_picture->p[ U_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ U_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ V_PLANE ].i_lines = i_height_aligned / 2;
        p_picture->p[ V_PLANE ].i_visible_lines = i_height / 2;
        p_picture->p[ V_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ V_PLANE ].i_visible_pitch = i_width;
        p_picture->i_planes = 3;
        break;

    case VLC_CODEC_I444:
    case VLC_CODEC_J444:
        p_picture->p[ Y_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ Y_PLANE ].i_visible_lines = i_height;
        p_picture->p[ Y_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ Y_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ U_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ U_PLANE ].i_visible_lines = i_height;
        p_picture->p[ U_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ U_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ V_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ V_PLANE ].i_visible_lines = i_height;
        p_picture->p[ V_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ V_PLANE ].i_visible_pitch = i_width;
        p_picture->i_planes = 3;
        break;

    case VLC_CODEC_YUVA:
        p_picture->p[ Y_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ Y_PLANE ].i_visible_lines = i_height;
        p_picture->p[ Y_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ Y_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ U_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ U_PLANE ].i_visible_lines = i_height;
        p_picture->p[ U_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ U_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ V_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ V_PLANE ].i_visible_lines = i_height;
        p_picture->p[ V_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ V_PLANE ].i_visible_pitch = i_width;
        p_picture->p[ A_PLANE ].i_lines = i_height_aligned;
        p_picture->p[ A_PLANE ].i_visible_lines = i_height;
        p_picture->p[ A_PLANE ].i_pitch = i_width_aligned;
        p_picture->p[ A_PLANE ].i_visible_pitch = i_width;
        p_picture->i_planes = 4;
        break;

    case VLC_CODEC_YUVP:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned;
        p_picture->p->i_visible_pitch = i_width;
        p_picture->p->i_pixel_pitch = 8;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_Y211:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned;
        p_picture->p->i_visible_pitch = i_width;
        p_picture->p->i_pixel_pitch = 4;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_UYVY:
    case VLC_CODEC_VYUY:
    case VLC_CODEC_YUYV:
    case VLC_CODEC_YVYU:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned * 2;
        p_picture->p->i_visible_pitch = i_width * 2;
        p_picture->p->i_pixel_pitch = 4;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_RGB8:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned;
        p_picture->p->i_visible_pitch = i_width;
        p_picture->p->i_pixel_pitch = 1;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_RGB15:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned * 2;
        p_picture->p->i_visible_pitch = i_width * 2;
        p_picture->p->i_pixel_pitch = 2;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_RGB16:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned * 2;
        p_picture->p->i_visible_pitch = i_width * 2;
        p_picture->p->i_pixel_pitch = 2;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_RGB24:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned * 3;
        p_picture->p->i_visible_pitch = i_width * 3;
        p_picture->p->i_pixel_pitch = 3;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_RGB32:
    case VLC_CODEC_RGBA:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned * 4;
        p_picture->p->i_visible_pitch = i_width * 4;
        p_picture->p->i_pixel_pitch = 4;
        p_picture->i_planes = 1;
        break;

    case VLC_CODEC_GREY:
    case VLC_CODEC_RGBP:
        p_picture->p->i_lines = i_height_aligned;
        p_picture->p->i_visible_lines = i_height;
        p_picture->p->i_pitch = i_width_aligned;
        p_picture->p->i_visible_pitch = i_width;
        p_picture->p->i_pixel_pitch = 1;
        p_picture->i_planes = 1;
        break;

    default:
        p_picture->i_planes = 0;
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

915 916 917 918 919
/*****************************************************************************
 *
 *****************************************************************************/
picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_aspect )
{
ivoire's avatar
ivoire committed
920
    picture_t *p_picture = calloc( 1, sizeof(*p_picture) );
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
    if( !p_picture )
        return NULL;

    if( __vout_AllocatePicture( NULL, p_picture,
                                i_chroma, i_width, i_height, i_aspect ) )
    {
        free( p_picture );
        return NULL;
    }

    p_picture->i_refcount = 1;
    p_picture->pf_release = PictureReleaseCallback;
    p_picture->i_status = RESERVED_PICTURE;

    return p_picture;
}

/*****************************************************************************
 *
 *****************************************************************************/
void picture_Delete( picture_t *p_picture )
{
    assert( p_picture && p_picture->i_refcount == 0 );
Laurent Aimar's avatar
Laurent Aimar committed
944
    assert( p_picture->p_release_sys == NULL );
945

946
    free( p_picture->p_q );
947 948 949 950 951 952 953 954 955 956
    free( p_picture->p_data_orig );
    free( p_picture->p_sys );
    free( p_picture );
}

/*****************************************************************************
 *
 *****************************************************************************/
void picture_CopyPixels( picture_t *p_dst, const picture_t *p_src )
{
957 958 959
    int i;

    for( i = 0; i < p_src->i_planes ; i++ )
960 961
        plane_CopyPixels( p_dst->p+i, p_src->p+i );
}
962

963 964 965 966 967 968
void plane_CopyPixels( plane_t *p_dst, const plane_t *p_src )
{
    const unsigned i_width  = __MIN( p_dst->i_visible_pitch,
                                     p_src->i_visible_pitch );
    const unsigned i_height = __MIN( p_dst->i_visible_lines,
                                     p_src->i_visible_lines );
969

970 971 972 973 974 975 976 977 978 979 980 981
    if( p_src->i_pitch == p_dst->i_pitch )
    {
        /* There are margins, but with the same width : perfect ! */
        vlc_memcpy( p_dst->p_pixels, p_src->p_pixels,
                    p_src->i_pitch * i_height );
    }
    else
    {
        /* We need to proceed line by line */
        uint8_t *p_in = p_src->p_pixels;
        uint8_t *p_out = p_dst->p_pixels;
        int i_line;
982

983 984 985 986 987 988 989 990
        assert( p_in );
        assert( p_out );

        for( i_line = i_height; i_line--; )
        {
            vlc_memcpy( p_out, p_in, i_width );
            p_in += p_src->i_pitch;
            p_out += p_dst->i_pitch;
991 992 993
        }
    }
}
Laurent Aimar's avatar
Laurent Aimar committed
994

995 996 997
/*****************************************************************************
 *
 *****************************************************************************/
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
int picture_Export( vlc_object_t *p_obj,
                    block_t **pp_image,
                    video_format_t *p_fmt,
                    picture_t *p_picture,
                    vlc_fourcc_t i_format,
                    int i_override_width, int i_override_height )
{
    /* */
    video_format_t fmt_in = p_picture->format;
    if( fmt_in.i_sar_num <= 0 || fmt_in.i_sar_den <= 0 )
    {
        fmt_in.i_sar_num =
        fmt_in.i_sar_den = 1;
    }

    /* */
    video_format_t fmt_out;
    memset( &fmt_out, 0, sizeof(fmt_out) );
    fmt_out.i_sar_num =
    fmt_out.i_sar_den = 1;
    fmt_out.i_chroma  = i_format;

1020 1021 1022 1023
    /* compute original width/height */
    unsigned int i_original_width;
    unsigned int i_original_height;
    if( fmt_in.i_sar_num >= fmt_in.i_sar_den )
1024
    {
1025 1026
        i_original_width = fmt_in.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
        i_original_height = fmt_in.i_height;
1027 1028 1029
    }
    else
    {
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
        i_original_width =  fmt_in.i_width;
        i_original_height = fmt_in.i_height * fmt_in.i_sar_den / fmt_in.i_sar_num;
    }

    /* */
    fmt_out.i_width  = ( i_override_width < 0 ) ?
                       i_original_width : i_override_width;
    fmt_out.i_height = ( i_override_height < 0 ) ?
                       i_original_height : i_override_height;

    /* scale if only one direction is provided */
    if( fmt_out.i_height == 0 && fmt_out.i_width > 0 )
    {
        fmt_out.i_height = fmt_in.i_height * fmt_out.i_width
                     * fmt_in.i_sar_den / fmt_in.i_width / fmt_in.i_sar_num;
    }
    else if( fmt_out.i_width == 0 && fmt_out.i_height > 0 )
    {
        fmt_out.i_width  = fmt_in.i_width * fmt_out.i_height
                     * fmt_in.i_sar_num / fmt_in.i_height / fmt_in.i_sar_den;
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
    }

    image_handler_t *p_image = image_HandlerCreate( p_obj );

    block_t *p_block = image_Write( p_image, p_picture, &fmt_in, &fmt_out );

    image_HandlerDelete( p_image );

    if( !p_block )
        return VLC_EGENERIC;

    p_block->i_pts =
    p_block->i_dts = p_picture->date;

    if( p_fmt )
        *p_fmt = fmt_out;
    *pp_image = p_block;

    return VLC_SUCCESS;
}

/*****************************************************************************
 *
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132