video_output.c 47.2 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * video_output.c : video output thread
3
 *
Michel Kaempf's avatar
Michel Kaempf committed
4
5
 * This module describes the programming interface for video output threads.
 * It includes functions allowing to open a new thread, send pictures to a
6
7
 * thread, and destroy a previously oppened video output thread.
 *****************************************************************************
8
 * Copyright (C) 2000-2004 the VideoLAN team
gbazin's avatar
gbazin committed
9
 * $Id$
10
 *
Sam Hocevar's avatar
   
Sam Hocevar committed
11
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
12
 *          Gildas Bazin <gbazin@videolan.org>
13
14
15
16
17
 *
 * 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.
Sam Hocevar's avatar
Sam Hocevar committed
18
 *
19
20
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
23
 *
24
25
26
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
27
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
28

29
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
30
 * Preamble
31
 *****************************************************************************/
32
#include <stdlib.h>                                                /* free() */
Vincent Seguin's avatar
Vincent Seguin committed
33

34
#include <vlc/vlc.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
35

36
37
#ifdef HAVE_SYS_TIMES_H
#   include <sys/times.h>
38
#endif
39

40
#include "vlc_video.h"
Michel Kaempf's avatar
Michel Kaempf committed
41
#include "video_output.h"
42
#include "vlc_spu.h"
gbazin's avatar
   
gbazin committed
43
#include <vlc/input.h>                 /* for input_thread_t and i_pts_delay */
44
#include "vlc_playlist.h"
45

46
47
48
49
#if defined( SYS_DARWIN )
#include "darwin_specific.h"
#endif

50
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
51
 * Local prototypes
52
 *****************************************************************************/
53
54
55
56
57
static int      InitThread        ( vout_thread_t * );
static void     RunThread         ( vout_thread_t * );
static void     ErrorThread       ( vout_thread_t * );
static void     EndThread         ( vout_thread_t * );
static void     DestroyThread     ( vout_thread_t * );
Sam Hocevar's avatar
   
Sam Hocevar committed
58

59
static void     AspectRatio       ( int, int *, int * );
60
61
static int      BinaryLog         ( uint32_t );
static void     MaskToShift       ( int *, int *, uint32_t );
Michel Kaempf's avatar
Michel Kaempf committed
62

gbazin's avatar
   
gbazin committed
63
/* Object variables callbacks */
gbazin's avatar
   
gbazin committed
64
65
static int DeinterlaceCallback( vlc_object_t *, char const *,
                                vlc_value_t, vlc_value_t, void * );
66
67
static int FilterCallback( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
gbazin's avatar
   
gbazin committed
68

69
70
71
/* From vout_intf.c */
int vout_Snapshot( vout_thread_t *, picture_t * );

72
/*****************************************************************************
73
74
75
76
77
 * vout_Request: find a video output thread, create one, or destroy one.
 *****************************************************************************
 * This function looks for a video output thread matching the current
 * properties. If not found, it spawns a new one.
 *****************************************************************************/
78
79
vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout,
                               video_format_t *p_fmt )
80
{
81
    if( !p_fmt )
82
    {
gbazin's avatar
   
gbazin committed
83
        /* Reattach video output to input before bailing out */
84
85
        if( p_vout )
        {
86
            vlc_object_t *p_playlist;
87

88
89
            p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
                                          FIND_ANYWHERE );
gbazin's avatar
   
gbazin committed
90

91
            if( p_playlist )
92
            {
93
                spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
94
                vlc_object_detach( p_vout );
95
                vlc_object_attach( p_vout, p_playlist );
96

97
                vlc_object_release( p_playlist );
98
99
100
            }
            else
            {
zorglub's avatar
zorglub committed
101
                msg_Dbg( p_this, "cannot find playlist, destroying vout" );
102
103
104
                vlc_object_detach( p_vout );
                vout_Destroy( p_vout );
            }
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
        }
        return NULL;
    }

    /* If a video output was provided, lock it, otherwise look for one. */
    if( p_vout )
    {
        vlc_object_yield( p_vout );
    }
    else
    {
        p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );

        if( !p_vout )
        {
120
            playlist_t *p_playlist;
gbazin's avatar
   
gbazin committed
121

122
123
124
            p_playlist = vlc_object_find( p_this,
                                          VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
            if( p_playlist )
gbazin's avatar
   
gbazin committed
125
            {
126
                vlc_mutex_lock( &p_playlist->gc_lock );
127
128
                p_vout = vlc_object_find( p_playlist,
                                          VLC_OBJECT_VOUT, FIND_CHILD );
129
                /* only first children of p_input for unused vout */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
130
                if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist )
131
132
133
134
                {
                    vlc_object_release( p_vout );
                    p_vout = NULL;
                }
135
                vlc_mutex_unlock( &p_playlist->gc_lock );
136
                vlc_object_release( p_playlist );
gbazin's avatar
   
gbazin committed
137
            }
138
139
140
141
142
143
        }
    }

    /* If we now have a video output, check it has the right properties */
    if( p_vout )
    {
gbazin's avatar
   
gbazin committed
144
        char *psz_filter_chain;
145
        vlc_value_t val;
gbazin's avatar
   
gbazin committed
146

147
        /* We don't directly check for the "vout-filter" variable for obvious
gbazin's avatar
   
gbazin committed
148
149
150
         * performance reasons. */
        if( p_vout->b_filter_change )
        {
151
            var_Get( p_vout, "vout-filter", &val );
152
            psz_filter_chain = val.psz_string;
gbazin's avatar
   
gbazin committed
153
154
155
156
157
158
159
160
161
162
163
164

            if( psz_filter_chain && !*psz_filter_chain )
            {
                free( psz_filter_chain );
                psz_filter_chain = NULL;
            }
            if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
            {
                free( p_vout->psz_filter_chain );
                p_vout->psz_filter_chain = NULL;
            }

165
            if( !psz_filter_chain && !p_vout->psz_filter_chain )
gbazin's avatar
   
gbazin committed
166
167
168
169
            {
                p_vout->b_filter_change = VLC_FALSE;
            }

gbazin's avatar
   
gbazin committed
170
            if( psz_filter_chain ) free( psz_filter_chain );
gbazin's avatar
   
gbazin committed
171
172
        }

173
174
175
        if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
            ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
            ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
176
            ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
gbazin's avatar
   
gbazin committed
177
            p_vout->b_filter_change )
178
179
180
181
182
183
184
185
186
187
188
        {
            /* We are not interested in this format, close this vout */
            vlc_object_detach( p_vout );
            vlc_object_release( p_vout );
            vout_Destroy( p_vout );
            p_vout = NULL;
        }
        else
        {
            /* This video output is cool! Hijack it. */
            vlc_object_detach( p_vout );
189
            spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
190
191
192
193
194
195
196
197
198
            vlc_object_attach( p_vout, p_this );
            vlc_object_release( p_vout );
        }
    }

    if( !p_vout )
    {
        msg_Dbg( p_this, "no usable vout present, spawning one" );

199
        p_vout = vout_Create( p_this, p_fmt );
200
201
202
203
204
205
206
    }

    return p_vout;
}

/*****************************************************************************
 * vout_Create: creates a new video output thread
207
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
208
209
 * This function creates a new video output thread, and returns a pointer
 * to its description. On error, it returns NULL.
210
 *****************************************************************************/
211
vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
Michel Kaempf's avatar
Michel Kaempf committed
212
{
gbazin's avatar
   
gbazin committed
213
214
215
216
    vout_thread_t  * p_vout;                            /* thread descriptor */
    input_thread_t * p_input_thread;
    int              i_index;                               /* loop variable */
    char           * psz_plugin;
217
    vlc_value_t      val, text;
Michel Kaempf's avatar
Michel Kaempf committed
218

219
220
    unsigned int i_width = p_fmt->i_width;
    unsigned int i_height = p_fmt->i_height;
221
222
223
    vlc_fourcc_t i_chroma = p_fmt->i_chroma;
    unsigned int i_aspect = p_fmt->i_aspect;

224
    /* Allocate descriptor */
225
    p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
226
    if( p_vout == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
227
    {
228
        msg_Err( p_parent, "out of memory" );
229
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
230
    }
231

232
    /* Initialize pictures - translation tables and functions
gbazin's avatar
   
gbazin committed
233
     * will be initialized later in InitThread */
234
    for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
gbazin's avatar
   
gbazin committed
235
236
237
238
239
    {
        p_vout->p_picture[i_index].pf_lock = NULL;
        p_vout->p_picture[i_index].pf_unlock = NULL;
        p_vout->p_picture[i_index].i_status = FREE_PICTURE;
        p_vout->p_picture[i_index].i_type   = EMPTY_PICTURE;
240
        p_vout->p_picture[i_index].b_slow   = 0;
gbazin's avatar
   
gbazin committed
241
242
243
244
245
246
247
    }

    /* No images in the heap */
    p_vout->i_heap_size = 0;

    /* Initialize the rendering heap */
    I_RENDERPICTURES = 0;
248
249
250

    vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
                 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
251
252
    p_vout->fmt_render        = *p_fmt;   /* FIXME palette */
    p_vout->fmt_in            = *p_fmt;   /* FIXME palette */
253

gbazin's avatar
   
gbazin committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
    p_vout->render.i_width    = i_width;
    p_vout->render.i_height   = i_height;
    p_vout->render.i_chroma   = i_chroma;
    p_vout->render.i_aspect   = i_aspect;

    p_vout->render.i_rmask    = 0;
    p_vout->render.i_gmask    = 0;
    p_vout->render.i_bmask    = 0;

    p_vout->render.i_last_used_pic = -1;
    p_vout->render.b_allow_modify_pics = 1;

    /* Zero the output heap */
    I_OUTPUTPICTURES = 0;
    p_vout->output.i_width    = 0;
    p_vout->output.i_height   = 0;
    p_vout->output.i_chroma   = 0;
    p_vout->output.i_aspect   = 0;

    p_vout->output.i_rmask    = 0;
    p_vout->output.i_gmask    = 0;
    p_vout->output.i_bmask    = 0;

    /* Initialize misc stuff */
    p_vout->i_changes    = 0;
    p_vout->f_gamma      = 0;
    p_vout->b_grayscale  = 0;
    p_vout->b_info       = 0;
    p_vout->b_interface  = 0;
    p_vout->b_scale      = 1;
    p_vout->b_fullscreen = 0;
gbazin's avatar
   
gbazin committed
285
    p_vout->i_alignment  = 0;
gbazin's avatar
   
gbazin committed
286
287
288
    p_vout->render_time  = 10;
    p_vout->c_fps_samples = 0;
    p_vout->b_filter_change = 0;
289
    p_vout->pf_control = 0;
290
    p_vout->p_parent_intf = 0;
291
    p_vout->i_par_num = p_vout->i_par_den = 1;
gbazin's avatar
   
gbazin committed
292
293
294
295
296

    /* Initialize locks */
    vlc_mutex_init( p_vout, &p_vout->picture_lock );
    vlc_mutex_init( p_vout, &p_vout->change_lock );

297
298
299
300
301
302
303
    /* Mouse coordinates */
    var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
    var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
    var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
    var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
    var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );

304
    /* Initialize subpicture unit */
305
    p_vout->p_spu = spu_Create( p_vout );
306
    spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
307

gbazin's avatar
   
gbazin committed
308
309
310
    /* Attach the new object now so we can use var inheritance below */
    vlc_object_attach( p_vout, p_parent );

311
312
    spu_Init( p_vout->p_spu );

313
314
    /* Take care of some "interface/control" related initialisations */
    vout_IntfInit( p_vout );
gbazin's avatar
   
gbazin committed
315

gbazin's avatar
   
gbazin committed
316
317
318
    /* If the parent is not a VOUT object, that means we are at the start of
     * the video output pipe */
    if( p_parent->i_object_type != VLC_OBJECT_VOUT )
Sam Hocevar's avatar
   
Sam Hocevar committed
319
    {
320
        /* Look for the default filter configuration */
321
322
        var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
        var_Get( p_vout, "vout-filter", &val );
gbazin's avatar
   
gbazin committed
323
        p_vout->psz_filter_chain = val.psz_string;
gbazin's avatar
   
gbazin committed
324
325
326
327
328
329
    }
    else
    {
        /* continue the parent's filter chain */
        char *psz_end;

330
        psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ':' );
gbazin's avatar
   
gbazin committed
331
332
333
334
335
336
        if( psz_end && *(psz_end+1) )
            p_vout->psz_filter_chain = strdup( psz_end+1 );
        else p_vout->psz_filter_chain = NULL;
    }

    /* Choose the video output module */
gbazin's avatar
   
gbazin committed
337
    if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
gbazin's avatar
   
gbazin committed
338
    {
gbazin's avatar
   
gbazin committed
339
340
341
        var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
        var_Get( p_vout, "vout", &val );
        psz_plugin = val.psz_string;
gbazin's avatar
   
gbazin committed
342
343
344
345
346
347
348
    }
    else
    {
        /* the filter chain is a string list of filters separated by double
         * colons */
        char *psz_end;

349
        psz_end = strchr( p_vout->psz_filter_chain, ':' );
gbazin's avatar
   
gbazin committed
350
351
352
353
        if( psz_end )
            psz_plugin = strndup( p_vout->psz_filter_chain,
                                  psz_end - p_vout->psz_filter_chain );
        else psz_plugin = strdup( p_vout->psz_filter_chain );
Sam Hocevar's avatar
   
Sam Hocevar committed
354
355
    }

gbazin's avatar
   
gbazin committed
356
    /* Create the vout thread */
gbazin's avatar
   
gbazin committed
357
    p_vout->p_module = module_Need( p_vout,
gbazin's avatar
   
gbazin committed
358
359
        ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
        "video filter" : "video output", psz_plugin, 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
360

gbazin's avatar
   
gbazin committed
361
    if( psz_plugin ) free( psz_plugin );
Sam Hocevar's avatar
   
Sam Hocevar committed
362
363
    if( p_vout->p_module == NULL )
    {
364
        msg_Err( p_vout, "no suitable vout module" );
365
        vlc_object_detach( p_vout );
366
        vlc_object_destroy( p_vout );
367
        return NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
368
    }
gbazin's avatar
   
gbazin committed
369

gbazin's avatar
   
gbazin committed
370
    /* Create a few object variables for interface interaction */
gbazin's avatar
   
gbazin committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
    var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
    text.psz_string = _("Deinterlace");
    var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
    val.psz_string = ""; text.psz_string = _("Disable");
    var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
    val.psz_string = "discard"; text.psz_string = _("Discard");
    var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
    val.psz_string = "blend"; text.psz_string = _("Blend");
    var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
    val.psz_string = "mean"; text.psz_string = _("Mean");
    var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
    val.psz_string = "bob"; text.psz_string = _("Bob");
    var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
    val.psz_string = "linear"; text.psz_string = _("Linear");
    var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
386
387
388
    val.psz_string = "x"; text.psz_string = "X";
    var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );

gbazin's avatar
   
gbazin committed
389
390
391
    if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
    {
        var_Set( p_vout, "deinterlace", val );
gbazin's avatar
   
gbazin committed
392
        if( val.psz_string ) free( val.psz_string );
gbazin's avatar
   
gbazin committed
393
    }
gbazin's avatar
   
gbazin committed
394
395
    var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );

396

397
    var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
398
    text.psz_string = _("Filters");
399
400
    var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
    var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
401

gbazin's avatar
   
gbazin committed
402
403
    /* Calculate delay created by internal caching */
    p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
gbazin's avatar
   
gbazin committed
404
                                           VLC_OBJECT_INPUT, FIND_ANYWHERE );
gbazin's avatar
   
gbazin committed
405
406
    if( p_input_thread )
    {
gbazin's avatar
   
gbazin committed
407
        p_vout->i_pts_delay = p_input_thread->i_pts_delay;
gbazin's avatar
   
gbazin committed
408
409
410
411
        vlc_object_release( p_input_thread );
    }
    else
    {
gbazin's avatar
   
gbazin committed
412
        p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
gbazin's avatar
   
gbazin committed
413
414
    }

415
    if( vlc_thread_create( p_vout, "video output", RunThread,
gbazin's avatar
   
gbazin committed
416
                           VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
417
    {
418
        msg_Err( p_vout, "out of memory" );
419
        module_Unneed( p_vout, p_vout->p_module );
420
421
422
423
424
425
426
427
428
429
430
        vlc_object_detach( p_vout );
        vlc_object_destroy( p_vout );
        return NULL;
    }

    if( p_vout->b_error )
    {
        msg_Err( p_vout, "video output creation failed" );

        /* Make sure the thread is destroyed */
        p_vout->b_die = VLC_TRUE;
431

432
433
434
        vlc_thread_join( p_vout );

        vlc_object_detach( p_vout );
435
436
        vlc_object_destroy( p_vout );
        return NULL;
437
    }
Michel Kaempf's avatar
Michel Kaempf committed
438

439
    return p_vout;
Michel Kaempf's avatar
Michel Kaempf committed
440
441
}

442
/*****************************************************************************
443
 * vout_Destroy: destroys a previously created video output
444
445
 *****************************************************************************
 * Destroy a terminated thread.
Michel Kaempf's avatar
Michel Kaempf committed
446
 * The function will request a destruction of the specified thread. If pi_error
447
 * is NULL, it will return once the thread is destroyed. Else, it will be
Michel Kaempf's avatar
Michel Kaempf committed
448
 * update using one of the THREAD_* constants.
449
 *****************************************************************************/
450
void vout_Destroy( vout_thread_t *p_vout )
zorglub's avatar
zorglub committed
451
{
452
    vlc_object_t *p_playlist;
zorglub's avatar
zorglub committed
453

Michel Kaempf's avatar
Michel Kaempf committed
454
    /* Request thread destruction */
455
    p_vout->b_die = VLC_TRUE;
456
    vlc_thread_join( p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
457

458
459
    var_Destroy( p_vout, "intf-change" );

zorglub's avatar
zorglub committed
460
    p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
461
462
                                  FIND_ANYWHERE );

gbazin's avatar
   
gbazin committed
463
464
    if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );

465
    /* Free structure */
466
    vlc_object_destroy( p_vout );
467
468
469
470

    /* If it was the last vout, tell the interface to show up */
    if( p_playlist != NULL )
    {
zorglub's avatar
zorglub committed
471
        vout_thread_t *p_another_vout = vlc_object_find( p_playlist,
472
473
474
475
476
477
478
479
480
481
482
483
484
                                            VLC_OBJECT_VOUT, FIND_ANYWHERE );
        if( p_another_vout == NULL )
        {
            vlc_value_t val;
            val.b_bool = VLC_TRUE;
            var_Set( p_playlist, "intf-show", val );
        }
        else
        {
            vlc_object_release( p_another_vout );
        }
        vlc_object_release( p_playlist );
    }
Michel Kaempf's avatar
Michel Kaempf committed
485
486
}

487
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
488
 * InitThread: initialize video output thread
489
 *****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
490
491
492
 * This function is called from RunThread and performs the second step of the
 * initialization. It returns 0 on success. Note that the thread's flag are not
 * modified inside this function.
493
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
494
static int InitThread( vout_thread_t *p_vout )
Vincent Seguin's avatar
Vincent Seguin committed
495
{
496
    int i, i_aspect_x, i_aspect_y;
Sam Hocevar's avatar
   
Sam Hocevar committed
497

Sam Hocevar's avatar
   
Sam Hocevar committed
498
499
500
501
    vlc_mutex_lock( &p_vout->change_lock );

#ifdef STATS
    p_vout->c_loops = 0;
Vincent Seguin's avatar
Vincent Seguin committed
502
503
#endif

Sam Hocevar's avatar
   
Sam Hocevar committed
504
    /* Initialize output method, it allocates direct buffers for us */
Sam Hocevar's avatar
   
Sam Hocevar committed
505
    if( p_vout->pf_init( p_vout ) )
Vincent Seguin's avatar
Vincent Seguin committed
506
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
507
        vlc_mutex_unlock( &p_vout->change_lock );
508
        return VLC_EGENERIC;
Sam Hocevar's avatar
   
Sam Hocevar committed
509
510
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
511
    if( !I_OUTPUTPICTURES )
Sam Hocevar's avatar
   
Sam Hocevar committed
512
    {
513
514
        msg_Err( p_vout, "plugin was unable to allocate at least "
                         "one direct buffer" );
Sam Hocevar's avatar
   
Sam Hocevar committed
515
        p_vout->pf_end( p_vout );
Sam Hocevar's avatar
   
Sam Hocevar committed
516
        vlc_mutex_unlock( &p_vout->change_lock );
517
        return VLC_EGENERIC;
518
    }
Vincent Seguin's avatar
Vincent Seguin committed
519

gbazin's avatar
   
gbazin committed
520
521
522
523
524
525
526
527
528
    if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
    {
        msg_Err( p_vout, "plugin allocated too many direct buffers, "
                         "our internal buffers must have overflown." );
        p_vout->pf_end( p_vout );
        vlc_mutex_unlock( &p_vout->change_lock );
        return VLC_EGENERIC;
    }

529
    msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
Sam Hocevar's avatar
   
Sam Hocevar committed
530

531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );

    msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
             "chroma %4.4s, ar %i:%i, sar %i:%i",
             p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
             p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
             p_vout->fmt_render.i_visible_width,
             p_vout->fmt_render.i_visible_height,
             (char*)&p_vout->fmt_render.i_chroma,
             i_aspect_x, i_aspect_y,
             p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );

    AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );

    msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
             "chroma %4.4s, ar %i:%i, sar %i:%i",
             p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
             p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
             p_vout->fmt_in.i_visible_width,
             p_vout->fmt_in.i_visible_height,
             (char*)&p_vout->fmt_in.i_chroma,
             i_aspect_x, i_aspect_y,
             p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );

    if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
    {
        p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
            p_vout->output.i_width;
        p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
            p_vout->output.i_height;
        p_vout->fmt_out.i_x_offset =  p_vout->fmt_out.i_y_offset = 0;

        p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
        p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
    }
    if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
    {
        p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
            p_vout->fmt_out.i_height;
        p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
            p_vout->fmt_out.i_width;
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
574
575
    vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
                 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
576
577

    AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
Sam Hocevar's avatar
   
Sam Hocevar committed
578

579
580
    msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
             "chroma %4.4s, ar %i:%i, sar %i:%i",
581
             p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
582
583
584
585
586
             p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
             p_vout->fmt_out.i_visible_width,
             p_vout->fmt_out.i_visible_height,
             (char*)&p_vout->fmt_out.i_chroma,
             i_aspect_x, i_aspect_y,
587
             p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
Sam Hocevar's avatar
   
Sam Hocevar committed
588

Sam Hocevar's avatar
   
Sam Hocevar committed
589
590
591
592
593
594
595
596
    /* Calculate shifts from system-updated masks */
    MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
                 p_vout->output.i_rmask );
    MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
                 p_vout->output.i_gmask );
    MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
                 p_vout->output.i_bmask );

Sam Hocevar's avatar
   
Sam Hocevar committed
597
    /* Check whether we managed to create direct buffers similar to
598
     * the render buffers, ie same size and chroma */
Sam Hocevar's avatar
   
Sam Hocevar committed
599
600
    if( ( p_vout->output.i_width == p_vout->render.i_width )
     && ( p_vout->output.i_height == p_vout->render.i_height )
601
     && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
602
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
603
604
605
606
        /* Cool ! We have direct buffers, we can ask the decoder to
         * directly decode into them ! Map the first render buffers to
         * the first direct buffers, but keep the first direct buffer
         * for memcpy operations */
Sam Hocevar's avatar
   
Sam Hocevar committed
607
608
        p_vout->b_direct = 1;

Sam Hocevar's avatar
   
Sam Hocevar committed
609
610
        for( i = 1; i < VOUT_MAX_PICTURES; i++ )
        {
gbazin's avatar
   
gbazin committed
611
612
613
614
615
616
617
618
            if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
                I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
                p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
            {
                /* We have enough direct buffers so there's no need to
                 * try to use system memory buffers. */
                break;
            }
Sam Hocevar's avatar
   
Sam Hocevar committed
619
620
621
            PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
            I_RENDERPICTURES++;
        }
gbazin's avatar
   
gbazin committed
622
623
624
625

        msg_Dbg( p_vout, "direct render, mapping "
                 "render pictures 0-%i to system pictures 1-%i",
                 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
Sam Hocevar's avatar
   
Sam Hocevar committed
626
627
628
    }
    else
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
629
630
631
        /* Rats... Something is wrong here, we could not find an output
         * plugin able to directly render what we decode. See if we can
         * find a chroma plugin to do the conversion */
Sam Hocevar's avatar
   
Sam Hocevar committed
632
633
        p_vout->b_direct = 0;

Sam Hocevar's avatar
   
Sam Hocevar committed
634
        /* Choose the best module */
gbazin's avatar
   
gbazin committed
635
        p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
Sam Hocevar's avatar
   
Sam Hocevar committed
636

Sam Hocevar's avatar
   
Sam Hocevar committed
637
638
        if( p_vout->chroma.p_module == NULL )
        {
639
            msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
640
641
                     (char*)&p_vout->render.i_chroma,
                     (char*)&p_vout->output.i_chroma );
Sam Hocevar's avatar
   
Sam Hocevar committed
642
643
            p_vout->pf_end( p_vout );
            vlc_mutex_unlock( &p_vout->change_lock );
644
            return VLC_EGENERIC;
Sam Hocevar's avatar
   
Sam Hocevar committed
645
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
646

gbazin's avatar
   
gbazin committed
647
648
649
650
        msg_Dbg( p_vout, "indirect render, mapping "
                 "render pictures 0-%i to system pictures %i-%i",
                 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
                 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
Sam Hocevar's avatar
   
Sam Hocevar committed
651
652

        /* Append render buffers after the direct buffers */
Sam Hocevar's avatar
   
Sam Hocevar committed
653
        for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
Sam Hocevar's avatar
   
Sam Hocevar committed
654
655
656
        {
            PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
            I_RENDERPICTURES++;
gbazin's avatar
   
gbazin committed
657
658
659
660

            /* Check if we have enough render pictures */
            if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
                break;
Sam Hocevar's avatar
   
Sam Hocevar committed
661
662
        }
    }
Vincent Seguin's avatar
Vincent Seguin committed
663

Sam Hocevar's avatar
   
Sam Hocevar committed
664
665
666
667
668
669
670
671
672
673
674
    /* Link pictures back to their heap */
    for( i = 0 ; i < I_RENDERPICTURES ; i++ )
    {
        PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
    }

    for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
    {
        PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
    }

675
/* XXX XXX mark thread ready */
676
    return VLC_SUCCESS;
Vincent Seguin's avatar
Vincent Seguin committed
677
678
}

679
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
680
 * RunThread: video output thread
681
 *****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
682
683
684
 * Video output thread. This function does only returns when the thread is
 * terminated. It handles the pictures arriving in the video heap and the
 * display device events.
685
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
686
static void RunThread( vout_thread_t *p_vout)
Vincent Seguin's avatar
Vincent Seguin committed
687
{
Sam Hocevar's avatar
   
Sam Hocevar committed
688
    int             i_index;                                /* index in heap */
689
    int             i_idle_loops = 0;  /* loops without displaying a picture */
Sam Hocevar's avatar
   
Sam Hocevar committed
690
691
692
693
    mtime_t         current_date;                            /* current date */
    mtime_t         display_date;                            /* display date */

    picture_t *     p_picture;                            /* picture pointer */
694
    picture_t *     p_last_picture = NULL;                   /* last picture */
Sam Hocevar's avatar
   
Sam Hocevar committed
695
696
    picture_t *     p_directbuffer;              /* direct buffer to display */

697
    subpicture_t *  p_subpic = NULL;                   /* subpicture pointer */
Sam Hocevar's avatar
   
Sam Hocevar committed
698
699
700
701
702

    /*
     * Initialize thread
     */
    p_vout->b_error = InitThread( p_vout );
gbazin's avatar
   
gbazin committed
703
704
705
706

    /* signal the creation of the vout */
    vlc_thread_ready( p_vout );

Sam Hocevar's avatar
   
Sam Hocevar committed
707
708
709
    if( p_vout->b_error )
    {
        /* Destroy thread structures allocated by Create and InitThread */
710
        DestroyThread( p_vout );
Sam Hocevar's avatar
   
Sam Hocevar committed
711
712
        return;
    }
713

714
    /*
Sam Hocevar's avatar
Sam Hocevar committed
715
     * Main loop - it is not executed if an error occurred during
Sam Hocevar's avatar
   
Sam Hocevar committed
716
     * initialization
717
     */
Sam Hocevar's avatar
   
Sam Hocevar committed
718
    while( (!p_vout->b_die) && (!p_vout->b_error) )
719
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
720
        /* Initialize loop variables */
721
        p_picture = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
722
723
        display_date = 0;
        current_date = mdate();
Sam Hocevar's avatar
   
Sam Hocevar committed
724

725
#if 0
Sam Hocevar's avatar
   
Sam Hocevar committed
726
727
        p_vout->c_loops++;
        if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
728
        {
729
730
            msg_Dbg( p_vout, "picture heap: %d/%d",
                     I_RENDERPICTURES, p_vout->i_heap_size );
Sam Hocevar's avatar
   
Sam Hocevar committed
731
        }
732
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
733
734

        /*
735
736
737
         * Find the picture to display (the one with the earliest date).
         * This operation does not need lock, since only READY_PICTUREs
         * are handled. */
738
        for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
Sam Hocevar's avatar
   
Sam Hocevar committed
739
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
740
741
742
            if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
                && ( (p_picture == NULL) ||
                     (PP_RENDERPICTURE[i_index]->date < display_date) ) )
743
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
744
                p_picture = PP_RENDERPICTURE[i_index];
Sam Hocevar's avatar
   
Sam Hocevar committed
745
                display_date = p_picture->date;
746
747
            }
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
748

749
        if( p_picture )
750
        {
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
            /* If we met the last picture, parse again to see whether there is
             * a more appropriate one. */
            if( p_picture == p_last_picture )
            {
                for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
                {
                    if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
                        && (PP_RENDERPICTURE[i_index] != p_last_picture)
                        && ((p_picture == p_last_picture) ||
                            (PP_RENDERPICTURE[i_index]->date < display_date)) )
                    {
                        p_picture = PP_RENDERPICTURE[i_index];
                        display_date = p_picture->date;
                    }
                }
            }
767

768
769
770
771
772
773
774
775
776
777
778
779
780
781
            /* If we found better than the last picture, destroy it */
            if( p_last_picture && p_picture != p_last_picture )
            {
                vlc_mutex_lock( &p_vout->picture_lock );
                if( p_last_picture->i_refcount )
                {
                    p_last_picture->i_status = DISPLAYED_PICTURE;
                }
                else
                {
                    p_last_picture->i_status = DESTROYED_PICTURE;
                    p_vout->i_heap_size--;
                }
                vlc_mutex_unlock( &p_vout->picture_lock );
782
                p_last_picture = NULL;
783
784
            }

Sam Hocevar's avatar
   
Sam Hocevar committed
785
786
787
788
            /* Compute FPS rate */
            p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
                = display_date;

789
790
            /* XXX: config_GetInt is slow, but this kind of frame dropping
             * should not happen that often. */
791
            if( !p_picture->b_force &&
792
                p_picture != p_last_picture &&
793
794
                display_date < current_date + p_vout->render_time &&
                config_GetInt( p_vout, "skip-frames" ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
795
796
797
798
799
800
801
802
803
804
805
806
807
808
            {
                /* Picture is late: it will be destroyed and the thread
                 * will directly choose the next picture */
                vlc_mutex_lock( &p_vout->picture_lock );
                if( p_picture->i_refcount )
                {
                    /* 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 */
                    p_picture->i_status = DESTROYED_PICTURE;
Sam Hocevar's avatar
   
Sam Hocevar committed
809
                    p_vout->i_heap_size--;
Sam Hocevar's avatar
   
Sam Hocevar committed
810
                }
gbazin's avatar
   
gbazin committed
811
                msg_Warn( p_vout, "late picture skipped ("I64Fd")",
812
                                  current_date - display_date );
813
814
815
816
                vlc_mutex_unlock( &p_vout->picture_lock );

                continue;
            }
817

gbazin's avatar
   
gbazin committed
818
            if( display_date >
sigmunau's avatar
sigmunau committed
819
                current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
            {
                /* Picture is waaay too early: it will be destroyed */
                vlc_mutex_lock( &p_vout->picture_lock );
                if( p_picture->i_refcount )
                {
                    /* 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 */
                    p_picture->i_status = DESTROYED_PICTURE;
                    p_vout->i_heap_size--;
                }
835
                msg_Warn( p_vout, "vout warning: early picture skipped "
gbazin's avatar
   
gbazin committed
836
837
                          "("I64Fd")", display_date - current_date
                          - p_vout->i_pts_delay );
Sam Hocevar's avatar
   
Sam Hocevar committed
838
839
840
841
                vlc_mutex_unlock( &p_vout->picture_lock );

                continue;
            }
842

843
            if( display_date > current_date + VOUT_DISPLAY_DELAY )
Sam Hocevar's avatar
   
Sam Hocevar committed
844
845
846
847
848
849
850
851
            {
                /* A picture is ready to be rendered, but its rendering date
                 * is far from the current one so the thread will perform an
                 * empty loop as if no picture were found. The picture state
                 * is unchanged */
                p_picture    = NULL;
                display_date = 0;
            }
852
853
            else if( p_picture == p_last_picture )
            {
854
855
                /* We are asked to repeat the previous picture, but we first
                 * wait for a couple of idle loops */
856
857
858
859
860
861
862
                if( i_idle_loops < 4 )
                {
                    p_picture    = NULL;
                    display_date = 0;
                }
                else
                {
863
864
865
                    /* We set the display date to something high, otherwise
                     * we'll have lots of problems with late pictures */
                    display_date = current_date + p_vout->render_time;
866
867
868
869
870
871
872
                }
            }
        }

        if( p_picture == NULL )
        {
            i_idle_loops++;
873
874
        }

875
876
877
878
879
880
        if( p_picture && p_vout->b_snapshot )
        {
            p_vout->b_snapshot = VLC_FALSE;
            vout_Snapshot( p_vout, p_picture );
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
881
882
883
        /*
         * Check for subpictures to display
         */
hartman's avatar
hartman committed
884
885
886
887
        if( display_date > 0 )
        {
            p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date );
        }
888

Sam Hocevar's avatar
   
Sam Hocevar committed
889
890
891
892
893
        /*
         * Perform rendering
         */
        p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );

Sam Hocevar's avatar
   
Sam Hocevar committed
894
        /*
895
         * Call the plugin-specific rendering method if there is one
Sam Hocevar's avatar
   
Sam Hocevar committed
896
         */
gbazin's avatar
   
gbazin committed
897
        if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
Sam Hocevar's avatar
   
Sam Hocevar committed
898
899
900
901
902
        {
            /* Render the direct buffer returned by vout_RenderPicture */
            p_vout->pf_render( p_vout, p_directbuffer );
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
903
904
905
        /*
         * Sleep, wake up
         */
gbazin's avatar
   
gbazin committed
906
        if( display_date != 0 && p_directbuffer != NULL )
907
        {
sigmunau's avatar
sigmunau committed
908
909
910
911
912
913
914
915
916
917
918
            mtime_t current_render_time = mdate() - current_date;
            /* if render time is very large we don't include it in the mean */
            if( current_render_time < p_vout->render_time +
                VOUT_DISPLAY_DELAY )
            {
                /* Store render time using a sliding mean weighting to
                 * current value in a 3 to 1 ratio*/
                p_vout->render_time *= 3;
                p_vout->render_time += current_render_time;
                p_vout->render_time >>= 2;
            }
919
920
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
921
922
923
924
        /* Give back change lock */
        vlc_mutex_unlock( &p_vout->change_lock );

        /* Sleep a while or until a given date */
gbazin's avatar
   
gbazin committed
925
        if( display_date != 0 )
Sam Hocevar's avatar
Sam Hocevar committed
926
        {
gbazin's avatar
   
gbazin committed
927
928
929
930
931
932
            /* If there are filters in the chain, better give them the picture
             * in advance */
            if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
            {
                mwait( display_date - VOUT_MWAIT_TOLERANCE );
            }
933
934
935
        }
        else
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
936
            msleep( VOUT_IDLE_SLEEP );
937
        }
938

Sam Hocevar's avatar
   
Sam Hocevar committed
939
940
941
942
943
944
945
        /* On awakening, take back lock and send immediately picture
         * to display. */
        vlc_mutex_lock( &p_vout->change_lock );

        /*
         * Display the previously rendered picture
         */
gbazin's avatar
   
gbazin committed
946
        if( p_picture != NULL && p_directbuffer != NULL )
Sam Hocevar's avatar
   
Sam Hocevar committed
947
948
        {
            /* Display the direct buffer returned by vout_RenderPicture */
949
950
951
952
            if( p_vout->pf_display )
            {
                p_vout->pf_display( p_vout, p_directbuffer );
            }
Vincent Seguin's avatar
Vincent Seguin committed
953

954
955
956
957
            /* Tell the vout this was the last picture and that it does not
             * need to be forced anymore. */
            p_last_picture = p_picture;
            p_last_picture->b_force = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
958
        }
Vincent Seguin's avatar
Vincent Seguin committed
959

960
961
962
963
964
965
        if( p_picture != NULL )
        {
            /* Reinitialize idle loop count */
            i_idle_loops = 0;
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
966
967
968
        /*
         * Check events and manage thread
         */
969
        if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
970
        {
Sam Hocevar's avatar
Sam Hocevar committed
971
            /* A fatal error occurred, and the thread must terminate
gbazin's avatar
   
gbazin committed
972
973
             * immediately, without displaying anything - setting b_error to 1
             * causes the immediate end of the main while() loop. */
Sam Hocevar's avatar
   
Sam Hocevar committed
974
975
            p_vout->b_error = 1;
        }
gbazin's avatar
   
gbazin committed
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993

        if( p_vout->i_changes & VOUT_SIZE_CHANGE )
        {
            /* this must only happen when the vout plugin is incapable of
             * rescaling the picture itself. In this case we need to destroy
             * the current picture buffers and recreate new ones with the right
             * dimensions */
            int i;

            p_vout->i_changes &= ~VOUT_SIZE_CHANGE;

            p_vout->pf_end( p_vout );
            for( i = 0; i < I_OUTPUTPICTURES; i++ )
                 p_vout->p_picture[ i ].i_status = FREE_PICTURE;

            I_OUTPUTPICTURES = 0;
            if( p_vout->pf_init( p_vout ) )
            {
994
                msg_Err( p_vout, "cannot resize display" );
995
                /* FIXME: pf_end will be called again in EndThread() */
gbazin's avatar
   
gbazin committed
996
997
998
999
                p_vout->b_error = 1;
            }

            /* Need to reinitialise the chroma plugin */
1000
1001
1002
1003
1004
1005
            if( p_vout->chroma.p_module )
            {
                if( p_vout->chroma.p_module->pf_deactivate )
                    p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
                p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
            }
gbazin's avatar
   
gbazin committed
1006
        }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031

        if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
        {
            /* This happens when the picture buffers need to be recreated.
             * This is useful on multimonitor displays for instance.
             *
             * Warning: This only works when the vout creates only 1 picture
             * buffer!! */
            p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;

            if( !p_vout->b_direct )
            {
                module_Unneed( p_vout, p_vout->chroma.p_module );
            }

            vlc_mutex_lock( &p_vout->picture_lock );

            p_vout->pf_end( p_vout );

            I_OUTPUTPICTURES = I_RENDERPICTURES = 0;

            p_vout->b_error = InitThread( p_vout );

            vlc_mutex_unlock( &p_vout->picture_lock );
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
1032
    }
Vincent Seguin's avatar
Vincent Seguin committed
1033

Sam Hocevar's avatar
   
Sam Hocevar committed
1034
1035
1036