vout_pictures.c 35.6 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 41
#include <vlc_image.h>
#include <vlc_block.h>

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

45 46 47
/**
 * Display a picture
 *
gbazin's avatar
 
gbazin committed
48
 * Remove the reservation flag of a picture, which will cause it to be ready
49
 * for display.
50
 */
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 );
54 55

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

    vlc_mutex_unlock( &p_vout->picture_lock );
}

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

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

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

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

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

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

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
172
        if( p_freepic->i_planes )
Sam Hocevar's avatar
 
Sam Hocevar committed
173 174
        {
            /* Copy picture information, set some default values */
Sam Hocevar's avatar
 
Sam Hocevar committed
175 176
            p_freepic->i_status   = RESERVED_PICTURE;
            p_freepic->i_type     = MEMORY_PICTURE;
177
            p_freepic->b_slow     = 0;
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_vout->i_heap_size++;
Sam Hocevar's avatar
 
Sam Hocevar committed
187 188 189 190
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
Sam Hocevar's avatar
 
Sam Hocevar committed
191 192
            p_freepic->i_status = FREE_PICTURE;
            p_freepic = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
193

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

        vlc_mutex_unlock( &p_vout->picture_lock );

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

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

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

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

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

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

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

    vlc_mutex_unlock( &p_vout->picture_lock );
}

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

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

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

    vlc_mutex_unlock( &p_vout->picture_lock );
}

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

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

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

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

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

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

            vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

620 621 622 623 624
    /* 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
625
    for( int i = 0; pp_fcc[i] != NULL; i++ )
626
    {
Laurent Aimar's avatar
Laurent Aimar committed
627 628 629 630 631 632 633 634 635 636 637
        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;
638
    }
Laurent Aimar's avatar
Laurent Aimar committed
639
    return 0;
640 641
}

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

Laurent Aimar's avatar
Laurent Aimar committed
652 653 654 655 656 657 658 659 660 661 662 663 664 665
/*****************************************************************************
 *
 *****************************************************************************/
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 );
}

666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
/*****************************************************************************
 *
 *****************************************************************************/
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
681
    p_picture->p_release_sys = NULL;
682 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
    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;
}

914 915 916 917 918
/*****************************************************************************
 *
 *****************************************************************************/
picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_aspect )
{
ivoire's avatar
ivoire committed
919
    picture_t *p_picture = calloc( 1, sizeof(*p_picture) );
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
    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
943
    assert( p_picture->p_release_sys == NULL );
944

945
    free( p_picture->p_q );
946 947 948 949 950 951 952 953 954 955
    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 )
{
956 957 958
    int i;

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

962 963 964 965 966 967
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 );
968

969 970 971 972 973 974 975 976 977 978 979 980
    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;
981

982 983 984 985 986 987 988 989
        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;
990 991 992
        }
    }
}
Laurent Aimar's avatar
Laurent Aimar committed
993

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

1019 1020 1021 1022
    /* 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 )
1023
    {
1024 1025
        i_original_width = fmt_in.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
        i_original_height = fmt_in.i_height;
1026 1027 1028
    }
    else
    {
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
        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;
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
    }

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

/*****************************************************************************
 *
 *****************************************************************************/