vout_pictures.c 35.7 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
#include <vlc_picture_pool.h>
43

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

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

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

    vlc_mutex_unlock( &p_vout->picture_lock );
}

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

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

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
145
                p_vout->i_heap_size++;
gbazin's avatar
 
gbazin committed
146 147 148
                p_vout->render.i_last_used_pic =
                    ( p_vout->render.i_last_used_pic + i_pic + 1 )
                    % I_RENDERPICTURES;
Sam Hocevar's avatar
 
Sam Hocevar committed
149
                vlc_mutex_unlock( &p_vout->picture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
150
                return( p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
151

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

            default:
                break;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
163 164 165 166 167
    }

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

Sam Hocevar's avatar
 
Sam Hocevar committed
176
        if( p_freepic->i_planes )
Sam Hocevar's avatar
 
Sam Hocevar committed
177 178
        {
            /* Copy picture information, set some default values */
Sam Hocevar's avatar
 
Sam Hocevar committed
179 180
            p_freepic->i_status   = RESERVED_PICTURE;
            p_freepic->i_type     = MEMORY_PICTURE;
181
            p_freepic->b_slow     = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
182

Sam Hocevar's avatar
 
Sam Hocevar committed
183
            p_freepic->i_refcount = 0;
184
            p_freepic->b_force = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
185

Sam Hocevar's avatar
 
Sam Hocevar committed
186
            p_freepic->b_progressive        = b_progressive;
187
            p_freepic->i_nb_fields          = i_nb_fields;
Sam Hocevar's avatar
 
Sam Hocevar committed
188
            p_freepic->b_top_field_first    = b_top_field_first;
Sam Hocevar's avatar
 
Sam Hocevar committed
189

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

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

        vlc_mutex_unlock( &p_vout->picture_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
203
        return( p_freepic );
Sam Hocevar's avatar
 
Sam Hocevar committed
204 205 206 207 208 209 210 211 212
    }

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

213 214 215 216 217 218 219 220 221 222 223 224
/* */
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 );
}

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

247 248
    vout_DropPicture( p_vout, p_pic );
}
Sam Hocevar's avatar
 
Sam Hocevar committed
249

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

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

    vlc_mutex_unlock( &p_vout->picture_lock );
}

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

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

308 309 310 311 312 313 314 315
    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
316 317 318 319

    vlc_mutex_unlock( &p_vout->picture_lock );
}

320 321 322
/**
 * Render a picture
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
323 324 325
 * 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.
326
 */
327
picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
328
                               subpicture_t *p_subpic, mtime_t render_date )
Sam Hocevar's avatar
 
Sam Hocevar committed
329
{
Sam Hocevar's avatar
 
Sam Hocevar committed
330
    if( p_pic == NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
331
        return NULL;
332

333
    if( p_pic->i_type == DIRECT_PICTURE && !p_subpic )
Sam Hocevar's avatar
 
Sam Hocevar committed
334
    {
335 336 337
        /* 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
338
        return p_pic;
Sam Hocevar's avatar
 
Sam Hocevar committed
339 340
    }

341 342 343 344 345 346 347
    /* It is either because:
     *  - the picture is not a direct buffer
     *  - we have to render subtitles (we can never do it on the given
     *  picture even if not referenced).
     */
    picture_t *p_render;
    if( p_subpic != NULL && PP_OUTPUTPICTURE[0]->b_slow )
348 349 350 351
    {
        /* The picture buffer is in slow memory. We'll use
         * the "2 * VOUT_MAX_PICTURES + 1" picture as a temporary
         * one for subpictures rendering. */
352 353
        p_render = &p_vout->p_picture[2 * VOUT_MAX_PICTURES];
        if( p_render->i_status == FREE_PICTURE )
354 355
        {
            vout_AllocatePicture( VLC_OBJECT(p_vout),
356
                                  p_render, p_vout->fmt_out.i_chroma,
357 358
                                  p_vout->fmt_out.i_width,
                                  p_vout->fmt_out.i_height,
Laurent Aimar's avatar
Laurent Aimar committed
359 360
                                  p_vout->fmt_out.i_sar_num,
                                  p_vout->fmt_out.i_sar_den );
361 362
            p_render->i_type = MEMORY_PICTURE;
            p_render->i_status = RESERVED_PICTURE;
363 364 365 366
        }
    }
    else
    {
367 368 369 370 371 372 373 374 375 376 377
        /* We can directly render into a direct buffer */
        p_render = PP_OUTPUTPICTURE[0];
    }
    /* Copy or convert */
    if( p_vout->p->b_direct )
    {
        picture_Copy( p_render, p_pic );
    }
    else
    {
        p_vout->p->p_chroma->p_owner = (filter_owner_sys_t *)p_render;
378
        p_vout->p->p_chroma->pf_video_filter( p_vout->p->p_chroma, p_pic );
379 380 381
    }
    /* Render the subtitles if present */
    if( p_subpic )
382
        spu_RenderSubpictures( p_vout->p_spu,
383
                               p_render, &p_vout->fmt_out,
384
                               p_subpic, &p_vout->fmt_in, render_date );
385 386 387
    /* Copy in case we used a temporary fast buffer */
    if( p_render != PP_OUTPUTPICTURE[0] )
        picture_Copy( PP_OUTPUTPICTURE[0], p_render );
Sam Hocevar's avatar
 
Sam Hocevar committed
388

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

392 393 394
/**
 * Calculate image window coordinates
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
395 396
 * This function will be accessed by plugins. It calculates the relative
 * position of the output window and the image window.
397
 */
398
void vout_PlacePicture( const vout_thread_t *p_vout,
399
                        unsigned int i_width, unsigned int i_height,
400 401 402 403
                        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
404
{
Laurent Aimar's avatar
Laurent Aimar committed
405
    if( i_width <= 0 || i_height <= 0 )
gbazin's avatar
 
gbazin committed
406 407
    {
        *pi_width = *pi_height = *pi_x = *pi_y = 0;
gbazin's avatar
 
gbazin committed
408
        return;
gbazin's avatar
 
gbazin committed
409
    }
gbazin's avatar
 
gbazin committed
410

Laurent Aimar's avatar
Laurent Aimar committed
411
    if( p_vout->b_autoscale )
Sam Hocevar's avatar
 
Sam Hocevar committed
412 413 414 415
    {
        *pi_width = i_width;
        *pi_height = i_height;
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
416
    else
417
    {
Laurent Aimar's avatar
Laurent Aimar committed
418 419
        int i_zoom = p_vout->i_zoom;
        /* be realistic, scaling factor confined between .2 and 10. */
420 421
        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
422

423 424 425 426 427 428 429 430 431 432 433 434 435 436
        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;
        }
437 438 439 440 441
#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
442 443
        *pi_width = i_original_width * i_zoom / ZOOM_FP_FACTOR ;
        *pi_height = i_original_height * i_zoom / ZOOM_FP_FACTOR ;
444
#endif
445
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
446

Laurent Aimar's avatar
Laurent Aimar committed
447
    int64_t i_scaled_width = p_vout->fmt_in.i_visible_width * (int64_t)p_vout->fmt_in.i_sar_num *
448
                              *pi_height / p_vout->fmt_in.i_visible_height / p_vout->fmt_in.i_sar_den;
Laurent Aimar's avatar
Laurent Aimar committed
449
    int64_t i_scaled_height = p_vout->fmt_in.i_visible_height * (int64_t)p_vout->fmt_in.i_sar_den *
450 451 452
                               *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
453
    {
454 455 456
        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
457
    }
458 459 460

    if( i_scaled_width > *pi_width )
        *pi_height = i_scaled_height;
Sam Hocevar's avatar
 
Sam Hocevar committed
461
    else
462
        *pi_width = i_scaled_width;
Sam Hocevar's avatar
 
Sam Hocevar committed
463

gbazin's avatar
 
gbazin committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
    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
487 488
}

489
#undef vout_AllocatePicture
490 491 492
/**
 * Allocate a new picture in the heap.
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
493 494 495
 * 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.
496
 */
497 498 499 500
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_sar_num, int i_sar_den )
Sam Hocevar's avatar
 
Sam Hocevar committed
501
{
Pierre's avatar
Pierre committed
502
    VLC_UNUSED(p_this);
503
    int i_index, i_width_aligned, i_height_aligned;
504 505 506 507

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

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

    /* Calculate how big the new image should be */
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541

    /*
     * bytes = width_aligned * height_aligned * bpp / 8
     * We need to check for an integer overflow at each multiplication since
     * height & width (and bpp?) could be arbitrary large
     */

    size_t i_bytes = 0;
    /* i_width_aligned is a multiple of 16, so we can divide by 8 now */
    size_t i_width_aligned_divided = i_width_aligned / 8;
    if( i_width_aligned_divided <= (SIZE_MAX/i_height_aligned) )
    {
        size_t i_pixels_divided = i_width_aligned_divided * i_height_aligned;
        size_t i_bpp = p_pic->format.i_bits_per_pixel;
        if( i_pixels_divided <= (SIZE_MAX/i_bpp) )
        {
            i_bytes = i_pixels_divided * i_bpp;
        }
    }

    if( i_bytes == 0 )
    {
        p_pic->i_planes = 0;
        return VLC_ENOMEM;
    }
gbazin's avatar
 
gbazin committed
542 543 544 545 546 547

    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;
548
        return VLC_EGENERIC;
gbazin's avatar
 
gbazin committed
549 550 551 552 553 554 555
    }

    /* 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++ )
    {
556 557
        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
558
    }
559 560

    return VLC_SUCCESS;
gbazin's avatar
 
gbazin committed
561 562
}

563 564 565
/**
 * Compare two chroma values
 *
566
 * This function returns 1 if the two fourcc values given as argument are
gbazin's avatar
 
gbazin committed
567
 * the same format (eg. UYVY/UYNV) or almost the same format (eg. I420/YV12)
568
 */
569 570
int vout_ChromaCmp( vlc_fourcc_t i_chroma, vlc_fourcc_t i_amorhc )
{
Laurent Aimar's avatar
Laurent Aimar committed
571
    static const vlc_fourcc_t p_I420[] = {
572
        VLC_CODEC_I420, VLC_CODEC_YV12, VLC_CODEC_J420, 0
573 574
    };
    static const vlc_fourcc_t p_I422[] = {
575
        VLC_CODEC_I422, VLC_CODEC_J422, 0
576 577
    };
    static const vlc_fourcc_t p_I440[] = {
578
        VLC_CODEC_I440, VLC_CODEC_J440, 0
579 580
    };
    static const vlc_fourcc_t p_I444[] = {
581
        VLC_CODEC_I444, VLC_CODEC_J444, 0
Laurent Aimar's avatar
Laurent Aimar committed
582 583
    };
    static const vlc_fourcc_t *pp_fcc[] = {
584
        p_I420, p_I422, p_I440, p_I444, NULL
Laurent Aimar's avatar
Laurent Aimar committed
585 586
    };

587 588 589 590
    /* */
    i_chroma = vlc_fourcc_GetCodec( VIDEO_ES, i_chroma );
    i_amorhc = vlc_fourcc_GetCodec( VIDEO_ES, i_amorhc );

591 592 593 594 595
    /* 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
596
    for( int i = 0; pp_fcc[i] != NULL; i++ )
597
    {
Laurent Aimar's avatar
Laurent Aimar committed
598 599 600 601 602 603 604 605 606 607 608
        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;
609
    }
Laurent Aimar's avatar
Laurent Aimar committed
610
    return 0;
611 612
}

613 614 615 616 617 618 619 620 621
/*****************************************************************************
 *
 *****************************************************************************/
static void PictureReleaseCallback( picture_t *p_picture )
{
    if( --p_picture->i_refcount > 0 )
        return;
    picture_Delete( p_picture );
}
622

Laurent Aimar's avatar
Laurent Aimar committed
623 624 625 626 627 628 629 630 631 632 633 634 635 636
/*****************************************************************************
 *
 *****************************************************************************/
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 );
}

637 638 639
/*****************************************************************************
 *
 *****************************************************************************/
640 641
int picture_Setup( picture_t *p_picture, vlc_fourcc_t i_chroma,
                   int i_width, int i_height, int i_sar_num, int i_sar_den )
642 643 644 645 646 647 648 649 650 651 652
{
    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
653
    p_picture->p_release_sys = NULL;
654 655 656 657 658 659
    p_picture->i_refcount = 0;

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

660
    video_format_Setup( &p_picture->format, i_chroma, i_width, i_height,
661
                        i_sar_num, i_sar_den );
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685

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

686
    case VLC_CODEC_YV9:
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
    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;
797
        p_picture->p->i_pixel_pitch = 1;
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
        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;
818
        p_picture->p->i_pixel_pitch = 2;
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
        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;
}

886 887 888
/*****************************************************************************
 *
 *****************************************************************************/
889
picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_resource_t *p_resource )
890
{
891 892 893 894
    video_format_t fmt = *p_fmt;

    /* It is needed to be sure all informations are filled */
    video_format_Setup( &fmt, p_fmt->i_chroma,
895
                              p_fmt->i_width, p_fmt->i_height,
Laurent Aimar's avatar
Laurent Aimar committed
896
                              p_fmt->i_sar_num, p_fmt->i_sar_den );
897 898

    /* */
ivoire's avatar
ivoire committed
899
    picture_t *p_picture = calloc( 1, sizeof(*p_picture) );
900 901 902
    if( !p_picture )
        return NULL;

903
    if( p_resource )
904
    {
905 906
        if( picture_Setup( p_picture, fmt.i_chroma, fmt.i_width, fmt.i_height,
                           fmt.i_sar_num, fmt.i_sar_den ) )
907 908 909 910 911
        {
            free( p_picture );
            return NULL;
        }
        p_picture->p_sys = p_resource->p_sys;
912

913 914 915 916 917 918 919 920 921
        for( int i = 0; i < p_picture->i_planes; i++ )
        {
            p_picture->p[i].p_pixels = p_resource->p[i].p_pixels;
            p_picture->p[i].i_lines  = p_resource->p[i].i_lines;
            p_picture->p[i].i_pitch  = p_resource->p[i].i_pitch;
        }
    }
    else
    {
922 923 924
        if( vout_AllocatePicture( (vlc_object_t *)NULL, p_picture,
                                  fmt.i_chroma, fmt.i_width, fmt.i_height,
                                  fmt.i_sar_num, fmt.i_sar_den ) )
925 926 927 928 929 930 931
        {
            free( p_picture );
            return NULL;
        }
    }
    /* */
    p_picture->format = fmt;
932 933 934 935 936 937
    p_picture->i_refcount = 1;
    p_picture->pf_release = PictureReleaseCallback;
    p_picture->i_status = RESERVED_PICTURE;

    return p_picture;
}
938 939 940 941
picture_t *picture_NewFromFormat( const video_format_t *p_fmt )
{
    return picture_NewFromResource( p_fmt, NULL );
}
942
picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_sar_num, int i_sar_den )
943 944 945 946
{
    video_format_t fmt;

    memset( &fmt, 0, sizeof(fmt) );
947
    video_format_Setup( &fmt, i_chroma, i_width, i_height,
948
                        i_sar_num, i_sar_den );
949 950 951

    return picture_NewFromFormat( &fmt );
}
952 953 954 955 956 957 958

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

961
    free( p_picture->p_q );
962 963 964 965 966 967 968 969 970 971
    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 )
{
972 973 974
    int i;

    for( i = 0; i < p_src->i_planes ; i++ )
975 976
        plane_CopyPixels( p_dst->p+i, p_src->p+i );
}
977

978 979 980 981 982 983
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 );
984

985 986 987 988 989 990 991 992 993 994 995 996
    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;
997

998 999 1000 1001 1002 1003 1004 1005
        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;
1006 1007 1008
        }
    }
}
Laurent Aimar's avatar
Laurent Aimar committed
1009

1010 1011 1012
/*****************************************************************************
 *
 *****************************************************************************/
1013 1014 1015 1016 1017
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,
1018
                    int i_override_width, int i_override_height )
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
{
    /* */
    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;

1035 1036 1037 1038
    /* 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 )
1039
    {
1040 1041
        i_original_width = fmt_in.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
        i_original_height = fmt_in.i_height;
1042 1043 1044
    }
    else
    {
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;
    }

    /* */
1050 1051