decoder.c 36.4 KB
Newer Older
1
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
2
 * decoder.c: Functions for the management of decoders
3
 *****************************************************************************
4
 * Copyright (C) 1999-2004 the VideoLAN team
5
 * $Id$
6
7
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
Laurent Aimar's avatar
Laurent Aimar committed
9
 *          Laurent Aimar <fenrir@via.ecp.fr>
10
11
12
13
14
 *
 * 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.
15
 *
16
17
18
19
20
21
22
 * 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
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24
25
26
27
28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
29
#include <vlc/vlc.h>
Laurent Aimar's avatar
Laurent Aimar committed
30

zorglub's avatar
zorglub committed
31
32
33
34
35
36
37
38
39
40
#include <vlc_block.h>
#include <vlc_vout.h>
#include <vlc_aout.h>
#include <vlc_sout.h>
#include <vlc_codec.h>
#include <vlc_osd.h>

#include <vlc_interface.h>
#include "audio_output/aout_internal.h"
#include "stream_output/stream_output.h"
Laurent Aimar's avatar
Laurent Aimar committed
41
#include "input_internal.h"
42

Laurent Aimar's avatar
Laurent Aimar committed
43
44
static decoder_t * CreateDecoder( input_thread_t *, es_format_t *, int );
static void        DeleteDecoder( decoder_t * );
45

gbazin's avatar
   
gbazin committed
46
static int         DecoderThread( decoder_t * );
47
static int         DecoderDecode( decoder_t * p_dec, block_t *p_block );
Sam Hocevar's avatar
   
Sam Hocevar committed
48

gbazin's avatar
   
gbazin committed
49
50
51
52
53
54
/* Buffers allocation callbacks for the decoders */
static aout_buffer_t *aout_new_buffer( decoder_t *, int );
static void aout_del_buffer( decoder_t *, aout_buffer_t * );

static picture_t *vout_new_buffer( decoder_t * );
static void vout_del_buffer( decoder_t *, picture_t * );
gbazin's avatar
   
gbazin committed
55
56
static void vout_link_picture( decoder_t *, picture_t * );
static void vout_unlink_picture( decoder_t *, picture_t * );
gbazin's avatar
   
gbazin committed
57

58
59
60
static subpicture_t *spu_new_buffer( decoder_t * );
static void spu_del_buffer( decoder_t *, subpicture_t * );

61
static es_format_t null_es_format;
gbazin's avatar
   
gbazin committed
62

63
64
struct decoder_owner_sys_t
{
65
66
    vlc_bool_t      b_own_thread;

Laurent Aimar's avatar
Laurent Aimar committed
67
68
    int64_t         i_preroll_end;

69
70
    input_thread_t  *p_input;

71
72
73
74
75
    aout_instance_t *p_aout;
    aout_input_t    *p_aout_input;

    vout_thread_t   *p_vout;

76
77
78
    vout_thread_t   *p_spu_vout;
    int              i_spu_channel;

79
80
    sout_instance_t         *p_sout;
    sout_packetizer_input_t *p_sout_input;
81

82
83
84
    /* Some decoders require already packetized data (ie. not truncated) */
    decoder_t *p_packetizer;

85
86
87
88
89
90
91
92
93
    /* Current format in use by the output */
    video_format_t video;
    audio_format_t audio;
    es_format_t    sout;

    /* fifo */
    block_fifo_t *p_fifo;
};

94
95
/* decoder_GetInputAttachment:
 */
Laurent Aimar's avatar
Laurent Aimar committed
96
97
input_attachment_t *decoder_GetInputAttachment( decoder_t *p_dec,
                                                const char *psz_name )
98
99
100
101
102
103
{
    input_attachment_t *p_attachment;
    if( input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENT, &p_attachment, psz_name ) )
        return NULL;
    return p_attachment;
}
Laurent Aimar's avatar
Laurent Aimar committed
104
105
106
107
108
109
110
111
112
/* decoder_GetInputAttachments:
 */
int decoder_GetInputAttachments( decoder_t *p_dec,
                                 input_attachment_t ***ppp_attachment,
                                 int *pi_attachment )
{
    return input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENTS,
                          ppp_attachment, pi_attachment );
}
113
114
115
116
117
118
/* decoder_GetDisplayDate:
 */
mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
{
    return i_ts;
}
119

zorglub's avatar
zorglub committed
120
121
122
123
124
125
126
/**
 * Spawns a new decoder thread
 *
 * \param p_input the input thread
 * \param p_es the es descriptor
 * \return the spawned decoder object
 */
Laurent Aimar's avatar
Laurent Aimar committed
127
128
decoder_t *input_DecoderNew( input_thread_t *p_input,
                             es_format_t *fmt, vlc_bool_t b_force_decoder )
129
{
130
131
    decoder_t   *p_dec = NULL;
    vlc_value_t val;
132

133
    /* If we are in sout mode, search for packetizer module */
zorglub's avatar
zorglub committed
134
    if( p_input->p->p_sout && !b_force_decoder )
135
    {
136
        /* Create the decoder configuration structure */
Laurent Aimar's avatar
Laurent Aimar committed
137
        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_PACKETIZER );
138
        if( p_dec == NULL )
gbazin's avatar
   
gbazin committed
139
        {
140
            msg_Err( p_input, "could not create packetizer" );
141
            intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"),
142
                            _("VLC could not open the packetizer module.") );
143
            return NULL;
gbazin's avatar
   
gbazin committed
144
        }
145
    }
146
    else
147
    {
gbazin's avatar
   
gbazin committed
148
        /* Create the decoder configuration structure */
Laurent Aimar's avatar
Laurent Aimar committed
149
        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER );
gbazin's avatar
   
gbazin committed
150
151
152
        if( p_dec == NULL )
        {
            msg_Err( p_input, "could not create decoder" );
153
            intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"),
154
                            _("VLC could not open the decoder module.") );
gbazin's avatar
   
gbazin committed
155
156
            return NULL;
        }
157
158
    }

159
    if( !p_dec->p_module )
Sam Hocevar's avatar
   
Sam Hocevar committed
160
    {
gbazin's avatar
   
gbazin committed
161
162
        msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
                 "VLC probably does not support this sound or video format.",
163
                 (char*)&p_dec->fmt_in.i_codec );
164
        intf_UserFatal( p_dec, VLC_FALSE, _("No suitable decoder module "
165
            "for format"), _("VLC probably does not support the \"%4.4s\" "
166
167
            "audio or video format. Unfortunately there is no way for you "
            "to fix this."), (char*)&p_dec->fmt_in.i_codec );
gbazin's avatar
   
gbazin committed
168
169
170

        DeleteDecoder( p_dec );
        vlc_object_destroy( p_dec );
171
        return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
172
173
    }

zorglub's avatar
zorglub committed
174
    if( p_input->p->p_sout && p_input->p->input.b_can_pace_control &&
Laurent Aimar's avatar
Laurent Aimar committed
175
        !b_force_decoder )
176
177
178
179
180
181
182
183
184
    {
        msg_Dbg( p_input, "stream out mode -> no decoder thread" );
        p_dec->p_owner->b_own_thread = VLC_FALSE;
    }
    else
    {
        var_Get( p_input, "minimize-threads", &val );
        p_dec->p_owner->b_own_thread = !val.b_bool;
    }
185

186
    if( p_dec->p_owner->b_own_thread )
Henri Fallon's avatar
   
Henri Fallon committed
187
    {
188
        int i_priority;
Laurent Aimar's avatar
Laurent Aimar committed
189
        if( fmt->i_cat == AUDIO_ES )
190
191
192
193
194
195
196
197
            i_priority = VLC_THREAD_PRIORITY_AUDIO;
        else
            i_priority = VLC_THREAD_PRIORITY_VIDEO;

        /* Spawn the decoder thread */
        if( vlc_thread_create( p_dec, "decoder", DecoderThread,
                               i_priority, VLC_FALSE ) )
        {
198
            msg_Err( p_dec, "cannot spawn decoder thread" );
199
200
201
202
203
            module_Unneed( p_dec, p_dec->p_module );
            DeleteDecoder( p_dec );
            vlc_object_destroy( p_dec );
            return NULL;
        }
Henri Fallon's avatar
   
Henri Fallon committed
204
205
    }

206
    return p_dec;
207
208
}

zorglub's avatar
zorglub committed
209
210
211
212
213
214
215
/**
 * Kills a decoder thread and waits until it's finished
 *
 * \param p_input the input thread
 * \param p_es the es descriptor
 * \return nothing
 */
Laurent Aimar's avatar
Laurent Aimar committed
216
void input_DecoderDelete( decoder_t *p_dec )
217
{
218
    vlc_object_kill( p_dec );
219

220
    if( p_dec->p_owner->b_own_thread )
221
    {
222
223
224
        /* Make sure the thread leaves the function by
         * sending it an empty block. */
        block_t *p_block = block_New( p_dec, 0 );
Laurent Aimar's avatar
Laurent Aimar committed
225
        input_DecoderDecode( p_dec, p_block );
226

227
        vlc_thread_join( p_dec );
228
229
230

        /* Don't module_Unneed() here because of the dll loader that wants
         * close() in the same thread than open()/decode() */
231
232
233
    }
    else
    {
234
235
236
        /* Flush */
        input_DecoderDecode( p_dec, NULL );

237
238
        module_Unneed( p_dec, p_dec->p_module );
    }
239

gbazin's avatar
   
gbazin committed
240
241
242
243
244
    /* Delete decoder configuration */
    DeleteDecoder( p_dec );

    /* Delete the decoder */
    vlc_object_destroy( p_dec );
245
}
zorglub's avatar
zorglub committed
246
247

/**
248
 * Put a block_t in the decoder's fifo.
zorglub's avatar
zorglub committed
249
250
251
252
 *
 * \param p_dec the decoder object
 * \param p_block the data block
 */
Laurent Aimar's avatar
Laurent Aimar committed
253
void input_DecoderDecode( decoder_t * p_dec, block_t *p_block )
254
{
255
256
    if( p_dec->p_owner->b_own_thread )
    {
zorglub's avatar
zorglub committed
257
        if( p_dec->p_owner->p_input->p->b_out_pace_control )
258
259
        {
            /* FIXME !!!!! */
260
            while( !p_dec->b_die && !p_dec->b_error &&
261
                   block_FifoCount( p_dec->p_owner->p_fifo ) > 10 )
262
263
264
265
            {
                msleep( 1000 );
            }
        }
266
        else if( block_FifoSize( p_dec->p_owner->p_fifo ) > 50000000 /* 50 MB */ )
267
268
269
270
        {
            /* FIXME: ideally we would check the time amount of data
             * in the fifo instead of its size. */
            msg_Warn( p_dec, "decoder/packetizer fifo full (data not "
trax's avatar
trax committed
271
                      "consumed quickly enough), resetting fifo!" );
272
273
274
275
            block_FifoEmpty( p_dec->p_owner->p_fifo );
        }

        block_FifoPut( p_dec->p_owner->p_fifo, p_block );
276
277
278
    }
    else
    {
279
        if( p_dec->b_error || (p_block && p_block->i_buffer <= 0) )
280
        {
281
            if( p_block ) block_Release( p_block );
282
283
284
285
286
287
        }
        else
        {
            DecoderDecode( p_dec, p_block );
        }
    }
288
}
289

290
void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush )
Laurent Aimar's avatar
Laurent Aimar committed
291
292
293
294
{
    block_t *p_null;

    /* Empty the fifo */
295
    if( p_dec->p_owner->b_own_thread && b_flush )
Laurent Aimar's avatar
Laurent Aimar committed
296
297
298
299
300
        block_FifoEmpty( p_dec->p_owner->p_fifo );

    /* Send a special block */
    p_null = block_New( p_dec, 128 );
    p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY;
301
302
303
    /* FIXME check for p_packetizer or b_packitized from es_format_t of input ? */
    if( p_dec->p_owner->p_packetizer && b_flush )
        p_null->i_flags |= BLOCK_FLAG_CORRUPTED;
Laurent Aimar's avatar
Laurent Aimar committed
304
305
306
307
308
    memset( p_null->p_buffer, 0, p_null->i_buffer );

    input_DecoderDecode( p_dec, p_null );
}

Laurent Aimar's avatar
   
Laurent Aimar committed
309
310
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
{
311
312
    if( p_dec->p_owner->b_own_thread
     && block_FifoCount( p_dec->p_owner->p_fifo ) > 0 )
Laurent Aimar's avatar
   
Laurent Aimar committed
313
314
315
316
317
318
    {
        return VLC_FALSE;
    }
    return VLC_TRUE;
}

zorglub's avatar
zorglub committed
319
320
321
322
323
324
325
326
/**
 * Create a decoder object
 *
 * \param p_input the input thread
 * \param p_es the es descriptor
 * \param i_object_type Object type as define in include/vlc_objects.h
 * \return the decoder object
 */
Laurent Aimar's avatar
Laurent Aimar committed
327
328
static decoder_t * CreateDecoder( input_thread_t *p_input,
                                  es_format_t *fmt, int i_object_type )
Sam Hocevar's avatar
   
Sam Hocevar committed
329
{
gbazin's avatar
   
gbazin committed
330
    decoder_t *p_dec;
Sam Hocevar's avatar
   
Sam Hocevar committed
331

gbazin's avatar
   
gbazin committed
332
    p_dec = vlc_object_create( p_input, i_object_type );
gbazin's avatar
   
gbazin committed
333
    if( p_dec == NULL )
Sam Hocevar's avatar
   
Sam Hocevar committed
334
    {
335
        msg_Err( p_input, "out of memory" );
Sam Hocevar's avatar
   
Sam Hocevar committed
336
337
338
        return NULL;
    }

gbazin's avatar
   
gbazin committed
339
340
341
342
    p_dec->pf_decode_audio = 0;
    p_dec->pf_decode_video = 0;
    p_dec->pf_decode_sub = 0;
    p_dec->pf_packetize = 0;
gbazin's avatar
   
gbazin committed
343

344
    /* Initialize the decoder fifo */
gbazin's avatar
   
gbazin committed
345
346
    p_dec->p_module = NULL;

347
    memset( &null_es_format, 0, sizeof(es_format_t) );
Laurent Aimar's avatar
Laurent Aimar committed
348
349
    es_format_Copy( &p_dec->fmt_in, fmt );
    es_format_Copy( &p_dec->fmt_out, &null_es_format );
gbazin's avatar
   
gbazin committed
350
351

    /* Allocate our private structure for the decoder */
Laurent Aimar's avatar
Laurent Aimar committed
352
    p_dec->p_owner = malloc( sizeof( decoder_owner_sys_t ) );
gbazin's avatar
   
gbazin committed
353
354
355
356
357
    if( p_dec->p_owner == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return NULL;
    }
358
    p_dec->p_owner->b_own_thread = VLC_TRUE;
Laurent Aimar's avatar
Laurent Aimar committed
359
    p_dec->p_owner->i_preroll_end = -1;
360
    p_dec->p_owner->p_input = p_input;
gbazin's avatar
   
gbazin committed
361
362
363
    p_dec->p_owner->p_aout = NULL;
    p_dec->p_owner->p_aout_input = NULL;
    p_dec->p_owner->p_vout = NULL;
364
365
    p_dec->p_owner->p_spu_vout = NULL;
    p_dec->p_owner->i_spu_channel = 0;
zorglub's avatar
zorglub committed
366
    p_dec->p_owner->p_sout = p_input->p->p_sout;
367
    p_dec->p_owner->p_sout_input = NULL;
368
    p_dec->p_owner->p_packetizer = NULL;
369

370
371
372
373
374
375
    /* decoder fifo */
    if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return NULL;
    }
376

gbazin's avatar
   
gbazin committed
377
378
379
380
381
    /* Set buffers allocation callbacks for the decoders */
    p_dec->pf_aout_buffer_new = aout_new_buffer;
    p_dec->pf_aout_buffer_del = aout_del_buffer;
    p_dec->pf_vout_buffer_new = vout_new_buffer;
    p_dec->pf_vout_buffer_del = vout_del_buffer;
gbazin's avatar
   
gbazin committed
382
383
    p_dec->pf_picture_link    = vout_link_picture;
    p_dec->pf_picture_unlink  = vout_unlink_picture;
384
385
    p_dec->pf_spu_buffer_new  = spu_new_buffer;
    p_dec->pf_spu_buffer_del  = spu_del_buffer;
gbazin's avatar
   
gbazin committed
386

gbazin's avatar
   
gbazin committed
387
388
    vlc_object_attach( p_dec, p_input );

389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
    /* Find a suitable decoder/packetizer module */
    if( i_object_type == VLC_OBJECT_DECODER )
        p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 );
    else
        p_dec->p_module = module_Need( p_dec, "packetizer", "$packetizer", 0 );

    /* Check if decoder requires already packetized data */
    if( i_object_type == VLC_OBJECT_DECODER &&
        p_dec->b_need_packetized && !p_dec->fmt_in.b_packetized )
    {
        p_dec->p_owner->p_packetizer =
            vlc_object_create( p_input, VLC_OBJECT_PACKETIZER );
        if( p_dec->p_owner->p_packetizer )
        {
            es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_in,
                            &p_dec->fmt_in );

Laurent Aimar's avatar
Laurent Aimar committed
406
407
408
            es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_out,
                            &null_es_format );

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
            vlc_object_attach( p_dec->p_owner->p_packetizer, p_input );

            p_dec->p_owner->p_packetizer->p_module =
                module_Need( p_dec->p_owner->p_packetizer,
                             "packetizer", "$packetizer", 0 );

            if( !p_dec->p_owner->p_packetizer->p_module )
            {
                es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in );
                vlc_object_detach( p_dec->p_owner->p_packetizer );
                vlc_object_destroy( p_dec->p_owner->p_packetizer );
            }
        }
    }

424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
    /* Copy ourself the input replay gain */
    if( fmt->i_cat == AUDIO_ES )
    {
        int i;
        for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
        {
            if( !p_dec->fmt_out.audio_replay_gain.pb_peak[i] )
            {
                p_dec->fmt_out.audio_replay_gain.pb_peak[i] = fmt->audio_replay_gain.pb_peak[i];
                p_dec->fmt_out.audio_replay_gain.pf_peak[i] = fmt->audio_replay_gain.pf_peak[i];
            }
            if( !p_dec->fmt_out.audio_replay_gain.pb_gain[i] )
            {
                p_dec->fmt_out.audio_replay_gain.pb_gain[i] = fmt->audio_replay_gain.pb_gain[i];
                p_dec->fmt_out.audio_replay_gain.pf_gain[i] = fmt->audio_replay_gain.pf_gain[i];
            }
        }
    }
gbazin's avatar
   
gbazin committed
442
443
444
    return p_dec;
}

zorglub's avatar
zorglub committed
445
446
447
448
449
450
/**
 * The decoding main loop
 *
 * \param p_dec the decoder
 * \return 0
 */
gbazin's avatar
   
gbazin committed
451
452
static int DecoderThread( decoder_t * p_dec )
{
453
    block_t *p_block;
gbazin's avatar
   
gbazin committed
454
455

    /* The decoder's main loop */
456
    while( !p_dec->b_die && !p_dec->b_error )
gbazin's avatar
   
gbazin committed
457
    {
458
        if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL )
gbazin's avatar
   
gbazin committed
459
        {
460
            p_dec->b_error = 1;
gbazin's avatar
   
gbazin committed
461
462
            break;
        }
463
        if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS )
464
465
466
467
        {
            break;
        }
    }
gbazin's avatar
   
gbazin committed
468

469
470
471
472
    while( !p_dec->b_die )
    {
        /* Trash all received PES packets */
        p_block = block_FifoGet( p_dec->p_owner->p_fifo );
473
        if( p_block ) block_Release( p_block );
474
    }
gbazin's avatar
   
gbazin committed
475

476
477
    /* We do it here because of the dll loader that wants close() in the
     * same thread than open()/decode() */
478
    module_Unneed( p_dec, p_dec->p_module );
gbazin's avatar
   
gbazin committed
479

480
481
    return 0;
}
gbazin's avatar
   
gbazin committed
482

Laurent Aimar's avatar
Laurent Aimar committed
483
484
static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p )
{
485
486
487
    if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) )
        *pi_preroll = INT64_MAX;
    else if( p->i_pts > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
488
489
490
491
492
493
494
        *pi_preroll = __MIN( *pi_preroll, p->i_pts );
    else if( p->i_dts > 0 )
        *pi_preroll = __MIN( *pi_preroll, p->i_dts );
}
static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
{
    input_thread_t *p_input = p_dec->p_owner->p_input;
495
    const int i_rate = p_block->i_rate;
Laurent Aimar's avatar
Laurent Aimar committed
496
497
498
499
500
501
502
503
    aout_buffer_t *p_aout_buf;

    while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
    {
        vlc_mutex_lock( &p_input->p->counters.counters_lock );
        stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_audio, 1, NULL );
        vlc_mutex_unlock( &p_input->p->counters.counters_lock );

504
        if( p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
Laurent Aimar's avatar
Laurent Aimar committed
505
506
507
        {
            aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
                                  p_dec->p_owner->p_aout_input, p_aout_buf );
508
            continue;
Laurent Aimar's avatar
Laurent Aimar committed
509
        }
510
511

        if( p_dec->p_owner->i_preroll_end > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
512
        {
513
514
            /* FIXME TODO flush audio output (don't know how to do that) */
            msg_Dbg( p_dec, "End of audio preroll" );
Laurent Aimar's avatar
Laurent Aimar committed
515
516
            p_dec->p_owner->i_preroll_end = -1;
        }
517
518
        aout_DecPlay( p_dec->p_owner->p_aout,
                      p_dec->p_owner->p_aout_input,
519
                      p_aout_buf, i_rate );
Laurent Aimar's avatar
Laurent Aimar committed
520
521
    }
}
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
static void VoutDisplayedPicture( 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;
    }
    else if( p_pic->i_refcount > 0 )
    {
        p_pic->i_status = DISPLAYED_PICTURE;
    }
    else
    {
        p_pic->i_status = DESTROYED_PICTURE;
        p_vout->i_heap_size--;
    }

    vlc_mutex_unlock( &p_vout->picture_lock );
}
static void VoutFlushPicture( vout_thread_t *p_vout )
{
    int i;
    vlc_mutex_lock( &p_vout->picture_lock );
    for( i = 0; i < p_vout->render.i_pictures; i++ )
    {
        picture_t *p_pic = p_vout->render.pp_picture[i];

551
552
        if( p_pic->i_status == READY_PICTURE ||
            p_pic->i_status == DISPLAYED_PICTURE )
553
554
555
556
557
558
559
560
        {
            /* We cannot change picture status if it is in READY_PICTURE state,
             * Just make sure they won't be displayed */
            p_pic->date = 1;
        }
    }
    vlc_mutex_unlock( &p_vout->picture_lock );
}
Laurent Aimar's avatar
Laurent Aimar committed
561
562
563
564
565
566
567
568
569
570
571
static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
{
    input_thread_t *p_input = p_dec->p_owner->p_input;
    picture_t *p_pic;

    while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
    {
        vlc_mutex_lock( &p_input->p->counters.counters_lock );
        stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_video, 1, NULL );
        vlc_mutex_unlock( &p_input->p->counters.counters_lock );

572
        if( p_pic->date < p_dec->p_owner->i_preroll_end )
Laurent Aimar's avatar
Laurent Aimar committed
573
        {
574
575
            VoutDisplayedPicture( p_dec->p_owner->p_vout, p_pic );
            continue;
Laurent Aimar's avatar
Laurent Aimar committed
576
        }
577
578

        if( p_dec->p_owner->i_preroll_end > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
579
        {
580
581
582
583
            msg_Dbg( p_dec, "End of video preroll" );
            if( p_dec->p_owner->p_vout )
                VoutFlushPicture( p_dec->p_owner->p_vout );
            /* */
Laurent Aimar's avatar
Laurent Aimar committed
584
585
            p_dec->p_owner->i_preroll_end = -1;
        }
586
587
588
589

        vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
                          p_pic->date );
        vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
Laurent Aimar's avatar
Laurent Aimar committed
590
591
592
    }
}

593
594
595
596
597
598
599
/**
 * Decode a block
 *
 * \param p_dec the decoder object
 * \param p_block the block to decode
 * \return VLC_SUCCESS or an error code
 */
600
601
static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
{
Laurent Aimar's avatar
Laurent Aimar committed
602
    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
603
    const int i_rate = p_block ? p_block->i_rate : INPUT_RATE_DEFAULT;
604

605
    if( p_block && p_block->i_buffer <= 0 )
606
607
608
609
610
611
612
613
614
    {
        block_Release( p_block );
        return VLC_SUCCESS;
    }

    if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER )
    {
        block_t *p_sout_block;

615
616
        while( ( p_sout_block =
                     p_dec->pf_packetize( p_dec, p_block ? &p_block : 0 ) ) )
617
        {
618
            if( !p_dec->p_owner->p_sout_input )
619
620
            {
                es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out );
Laurent Aimar's avatar
Laurent Aimar committed
621

622
                p_dec->p_owner->sout.i_group = p_dec->fmt_in.i_group;
Laurent Aimar's avatar
Laurent Aimar committed
623
                p_dec->p_owner->sout.i_id = p_dec->fmt_in.i_id;
624
625
                if( p_dec->fmt_in.psz_language )
                {
626
627
                    if( p_dec->p_owner->sout.psz_language )
                        free( p_dec->p_owner->sout.psz_language );
628
629
                    p_dec->p_owner->sout.psz_language =
                        strdup( p_dec->fmt_in.psz_language );
630
                }
gbazin's avatar
   
gbazin committed
631

632
                p_dec->p_owner->p_sout_input =
633
634
                    sout_InputNew( p_dec->p_owner->p_sout,
                                   &p_dec->p_owner->sout );
635

636
                if( p_dec->p_owner->p_sout_input == NULL )
gbazin's avatar
   
gbazin committed
637
                {
638
639
                    msg_Err( p_dec, "cannot create packetizer output (%4.4s)",
                             (char *)&p_dec->p_owner->sout.i_codec );
640
                    p_dec->b_error = VLC_TRUE;
gbazin's avatar
   
gbazin committed
641

642
                    while( p_sout_block )
643
                    {
644
                        block_t *p_next = p_sout_block->p_next;
645
646
                        block_Release( p_sout_block );
                        p_sout_block = p_next;
647
                    }
648
649
650
                    break;
                }
            }
gbazin's avatar
   
gbazin committed
651

652
653
            while( p_sout_block )
            {
654
                block_t *p_next = p_sout_block->p_next;
gbazin's avatar
   
gbazin committed
655

656
                p_sout_block->p_next = NULL;
657
                p_sout_block->i_rate = i_rate;
gbazin's avatar
   
gbazin committed
658

659
                sout_InputSendBuffer( p_dec->p_owner->p_sout_input,
660
                                      p_sout_block );
gbazin's avatar
   
gbazin committed
661

662
                p_sout_block = p_next;
gbazin's avatar
   
gbazin committed
663
            }
664
665
666

            /* For now it's enough, as only sout inpact on this flag */
            if( p_dec->p_owner->p_sout->i_out_pace_nocontrol > 0 &&
zorglub's avatar
zorglub committed
667
                p_dec->p_owner->p_input->p->b_out_pace_control )
668
            {
669
                msg_Dbg( p_dec, "switching to sync mode" );
zorglub's avatar
zorglub committed
670
                p_dec->p_owner->p_input->p->b_out_pace_control = VLC_FALSE;
671
672
            }
            else if( p_dec->p_owner->p_sout->i_out_pace_nocontrol <= 0 &&
zorglub's avatar
zorglub committed
673
                     !p_dec->p_owner->p_input->p->b_out_pace_control )
674
            {
675
                msg_Dbg( p_dec, "switching to async mode" );
zorglub's avatar
zorglub committed
676
                p_dec->p_owner->p_input->p->b_out_pace_control = VLC_TRUE;
677
            }
gbazin's avatar
   
gbazin committed
678
        }
679
680
681
    }
    else if( p_dec->fmt_in.i_cat == AUDIO_ES )
    {
682
683
        if( p_block )
            DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
684

685
686
687
688
689
690
        if( p_dec->p_owner->p_packetizer )
        {
            block_t *p_packetized_block;
            decoder_t *p_packetizer = p_dec->p_owner->p_packetizer;

            while( (p_packetized_block =
691
                    p_packetizer->pf_packetize( p_packetizer, p_block ? &p_block : NULL )) )
692
            {
693
694
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
695
696
                    es_format_Clean( &p_dec->fmt_in );
                    es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out );
697
698
                }

699
                while( p_packetized_block )
700
                {
701
702
                    block_t *p_next = p_packetized_block->p_next;
                    p_packetized_block->p_next = NULL;
703
                    p_packetized_block->i_rate = i_rate;
704

Laurent Aimar's avatar
Laurent Aimar committed
705
                    DecoderDecodeAudio( p_dec, p_packetized_block );
706
707

                    p_packetized_block = p_next;
708
709
710
                }
            }
        }
711
        else if( p_block )
712
        {
Laurent Aimar's avatar
Laurent Aimar committed
713
            DecoderDecodeAudio( p_dec, p_block );
714
        }
gbazin's avatar
   
gbazin committed
715
    }
716
    else if( p_dec->fmt_in.i_cat == VIDEO_ES )
717
    {
718
719
        if( p_block )
            DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
720

721
722
723
724
725
726
        if( p_dec->p_owner->p_packetizer )
        {
            block_t *p_packetized_block;
            decoder_t *p_packetizer = p_dec->p_owner->p_packetizer;

            while( (p_packetized_block =
727
                    p_packetizer->pf_packetize( p_packetizer, p_block ? &p_block : NULL )) )
728
            {
729
730
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
731
732
                    es_format_Clean( &p_dec->fmt_in );
                    es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out );
733
734
                }

735
                while( p_packetized_block )
736
                {
737
738
                    block_t *p_next = p_packetized_block->p_next;
                    p_packetized_block->p_next = NULL;
739
                    p_packetized_block->i_rate = i_rate;
740

Laurent Aimar's avatar
Laurent Aimar committed
741
                    DecoderDecodeVideo( p_dec, p_packetized_block );
742
743

                    p_packetized_block = p_next;
744
745
746
                }
            }
        }
747
        else if( p_block )
748
        {
Laurent Aimar's avatar
Laurent Aimar committed
749
            DecoderDecodeVideo( p_dec, p_block );
750
        }
751
    }
752
753
    else if( p_dec->fmt_in.i_cat == SPU_ES )
    {
Laurent Aimar's avatar
Laurent Aimar committed
754
        input_thread_t *p_input = p_dec->p_owner->p_input;
755
756
        vout_thread_t *p_vout;
        subpicture_t *p_spu;
757

758
759
        if( p_block )
            DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
760

761
        while( (p_spu = p_dec->pf_decode_sub( p_dec, p_block ? &p_block : NULL ) ) )
762
        {
Laurent Aimar's avatar
Laurent Aimar committed
763
764
765
            vlc_mutex_lock( &p_input->p->counters.counters_lock );
            stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_sub, 1, NULL );
            vlc_mutex_unlock( &p_input->p->counters.counters_lock );
766

Laurent Aimar's avatar
Laurent Aimar committed
767
768
            p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
            if( p_vout && p_sys->p_spu_vout == p_vout )
Laurent Aimar's avatar
Laurent Aimar committed
769
            {
Laurent Aimar's avatar
Laurent Aimar committed
770
771
772
773
774
775
                /* Prerool does not work very well with subtitle */
                if( p_spu->i_start < p_dec->p_owner->i_preroll_end &&
                    ( p_spu->i_stop <= 0 || p_spu->i_stop < p_dec->p_owner->i_preroll_end ) )
                    spu_DestroySubpicture( p_vout->p_spu, p_spu );
                else
                    spu_DisplaySubpicture( p_vout->p_spu, p_spu );
Laurent Aimar's avatar
Laurent Aimar committed
776
            }
Laurent Aimar's avatar
Laurent Aimar committed
777
            else
778
            {
Laurent Aimar's avatar
Laurent Aimar committed
779
                msg_Warn( p_dec, "no vout found, leaking subpicture" );
780
            }
Laurent Aimar's avatar
Laurent Aimar committed
781
782
            if( p_vout )
                vlc_object_release( p_vout );
783
        }
784
785
786
    }
    else
    {
zorglub's avatar
zorglub committed
787
        msg_Err( p_dec, "unknown ES format" );
788
789
        p_dec->b_error = 1;
    }
790

791
    return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS;
Sam Hocevar's avatar
   
Sam Hocevar committed
792
793
}

zorglub's avatar
zorglub committed
794
795
796
797
798
799
/**
 * Destroys a decoder object
 *
 * \param p_dec the decoder object
 * \return nothing
 */
gbazin's avatar
   
gbazin committed
800
static void DeleteDecoder( decoder_t * p_dec )
Sam Hocevar's avatar
   
Sam Hocevar committed
801
{
802
    msg_Dbg( p_dec, "killing decoder fourcc `%4.4s', %u PES in FIFO",
803
             (char*)&p_dec->fmt_in.i_codec,
804
             (unsigned)block_FifoCount( p_dec->p_owner->p_fifo ) );
805

Sam Hocevar's avatar
   
Sam Hocevar committed
806
    /* Free all packets still in the decoder fifo. */
807
808
    block_FifoEmpty( p_dec->p_owner->p_fifo );
    block_FifoRelease( p_dec->p_owner->p_fifo );
Sam Hocevar's avatar
   
Sam Hocevar committed
809

810
    /* Cleanup */
gbazin's avatar
   
gbazin committed
811
812
813
814
815
816
817
    if( p_dec->p_owner->p_aout_input )
        aout_DecDelete( p_dec->p_owner->p_aout, p_dec->p_owner->p_aout_input );

    if( p_dec->p_owner->p_vout )
    {
        int i_pic;

gbazin's avatar
   
gbazin committed
818
#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
gbazin's avatar
   
gbazin committed
819
820
821
822
        /* Hack to make sure all the the pictures are freed by the decoder */
        for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
             i_pic++ )
        {
gbazin's avatar
   
gbazin committed
823
824
825
826
            if( p_pic->i_status == RESERVED_PICTURE )
                vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
            if( p_pic->i_refcount > 0 )
                vout_UnlinkPicture( p_dec->p_owner->p_vout, p_pic );
gbazin's avatar
   
gbazin committed
827
        }
gbazin's avatar
   
gbazin committed
828
#undef p_pic
gbazin's avatar
   
gbazin committed
829
830

        /* We are about to die. Reattach video output to p_vlc. */
831
        vout_Request( p_dec, p_dec->p_owner->p_vout, 0 );
gbazin's avatar
   
gbazin committed
832
833
    }

834
    if( p_dec->p_owner->p_sout_input )
gbazin's avatar
   
gbazin committed
835
    {
836
        sout_InputDelete( p_dec->p_owner->p_sout_input );
837
        es_format_Clean( &p_dec->p_owner->sout );
gbazin's avatar
   
gbazin committed
838
839
    }

840
841
842
843
844
845
846
    if( p_dec->fmt_in.i_cat == SPU_ES )
    {
        vout_thread_t *p_vout;

        p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
        if( p_vout )
        {
847
848
            spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR,
                         p_dec->p_owner->i_spu_channel );
849
850
851
852
            vlc_object_release( p_vout );
        }
    }

853
854
855
856
857
858
859
860
861
862
863
864
    es_format_Clean( &p_dec->fmt_in );
    es_format_Clean( &p_dec->fmt_out );

    if( p_dec->p_owner->p_packetizer )
    {
        module_Unneed( p_dec->p_owner->p_packetizer,
                       p_dec->p_owner->p_packetizer->p_module );
        es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in );
        es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_out );
        vlc_object_detach( p_dec->p_owner->p_packetizer );
        vlc_object_destroy( p_dec->p_owner->p_packetizer );
    }
gbazin's avatar
   
gbazin committed
865

866
867
    vlc_object_detach( p_dec );

gbazin's avatar
   
gbazin committed
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
    free( p_dec->p_owner );
}

/*****************************************************************************
 * Buffers allocation callbacks for the decoders
 *****************************************************************************/
static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
{
    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
    aout_buffer_t *p_buffer;

    if( p_sys->p_aout_input != NULL &&
        ( p_dec->fmt_out.audio.i_rate != p_sys->audio.i_rate ||
          p_dec->fmt_out.audio.i_original_channels !=
              p_sys->audio.i_original_channels ||
          p_dec->fmt_out.audio.i_bytes_per_frame !=
              p_sys->audio.i_bytes_per_frame ) )
    {
        /* Parameters changed, restart the aout */
        aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
        p_sys->p_aout_input = NULL;
    }

    if( p_sys->p_aout_input == NULL )
    {
893
894
895
        audio_sample_format_t format;
        int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" );

gbazin's avatar
   
gbazin committed
896
897
        p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
        p_sys->audio = p_dec->fmt_out.audio;
898
899
900
901
902

        memcpy( &format, &p_sys->audio, sizeof( audio_sample_format_t ) );
        if ( i_force_dolby && (format.i_original_channels&AOUT_CHAN_PHYSMASK)
                                    == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
        {
903
            if ( i_force_dolby == 1 )
904
905
906
907
            {
                format.i_original_channels = format.i_original_channels |
                                             AOUT_CHAN_DOLBYSTEREO;
            }
908
            else /* i_force_dolby == 2 */
909
910
911
912
913
914
            {
                format.i_original_channels = format.i_original_channels &
                                             ~AOUT_CHAN_DOLBYSTEREO;
            }
        }

gbazin's avatar
   
gbazin committed
915
        p_sys->p_aout_input =
916
            aout_DecNew( p_dec, &p_sys->p_aout, &format, &p_dec->fmt_out.audio_replay_gain );
gbazin's avatar
   
gbazin committed
917
918
919
        if( p_sys->p_aout_input == NULL )
        {
            msg_Err( p_dec, "failed to create audio output" );
gbazin's avatar
   
gbazin committed
920
            p_dec->b_error = VLC_TRUE;
gbazin's avatar
   
gbazin committed
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
            return NULL;
        }
        p_dec->fmt_out.audio.i_bytes_per_frame =
            p_sys->audio.i_bytes_per_frame;
    }

    p_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
                                  i_samples );

    return p_buffer;
}

static void aout_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
{
    aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
                          p_dec->p_owner->p_aout_input, p_buffer );
}

static picture_t *vout_new_buffer( decoder_t *p_dec )
{
    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
    picture_t *p_pic;

    if( p_sys->p_vout == NULL ||
        p_dec->fmt_out.video.i_width != p_sys->video.i_width ||
        p_dec->fmt_out.video.i_height != p_sys->video.i_height ||
        p_dec->fmt_out.video.i_chroma != p_sys->video.i_chroma ||
        p_dec->fmt_out.video.i_aspect != p_sys->video.i_aspect )
    {
        if( !p_dec->fmt_out.video.i_width ||
            !p_dec->fmt_out.video.i_height )
        {
            /* Can't create a new vout without display size */
            return NULL;
        }

957
958
959
        if( !p_dec->fmt_out.video.i_visible_width ||
            !p_dec->fmt_out.video.i_visible_height )
        {
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
            if( p_dec->fmt_in.video.i_visible_width &&
                p_dec->fmt_in.video.i_visible_height )
            {
                p_dec->fmt_out.video.i_visible_width =
                    p_dec->fmt_in.video.i_visible_width;
                p_dec->fmt_out.video.i_visible_height =
                    p_dec->fmt_in.video.i_visible_height;
            }
            else
            {
                p_dec->fmt_out.video.i_visible_width =
                    p_dec->fmt_out.video.i_width;
                p_dec->fmt_out.video.i_visible_height =
                    p_dec->fmt_out.video.i_height;
            }
975
976
        }

977
978
        if( p_dec->fmt_out.video.i_visible_height == 1088 &&
            var_CreateGetBool( p_dec, "hdtv-fix" ) )
979
        {
980
            p_dec->fmt_out.video.i_visible_height = 1080;
zorglub's avatar
zorglub committed
981
982
            p_dec->fmt_out.video.i_sar_num *= 135;
            p_dec->fmt_out.video.i_sar_den *= 136;
983
            msg_Warn( p_dec, "Fixing broken HDTV stream (display_height=1088)");
984
985
        }

986
987
988
        if( !p_dec->fmt_out.video.i_sar_num ||
            !p_dec->fmt_out.video.i_sar_den )
        {
zorglub's avatar
zorglub committed
989
            p_dec->fmt_out.video.i_sar_num = p_dec->fmt_out.video.i_aspect *
990
              p_dec->fmt_out.video.i_visible_height;
991
992

            p_dec->fmt_out.video.i_sar_den = VOUT_ASPECT_FACTOR *
993
              p_dec->fmt_out.video.i_visible_width;
994
995
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
996
997
998
        vlc_ureduce( &p_dec->fmt_out.video.i_sar_num,
                     &p_dec->fmt_out.video.i_sar_den,
                     p_dec->fmt_out.video.i_sar_num,
999
                     p_dec->fmt_out.video.i_sar_den, 50000 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1000

gbazin's avatar
   
gbazin committed
1001
1002
1003
1004
        p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
        p_sys->video = p_dec->fmt_out.video;

        p_sys->p_vout = vout_Request( p_dec, p_sys->p_vout,
1005
                                      &p_dec->fmt_out.video );
gbazin's avatar
   
gbazin committed
1006
1007
1008
        if( p_sys->p_vout == NULL )
        {
            msg_Err( p_dec, "failed to create video output" );
gbazin's avatar
   
gbazin committed
1009
            p_dec->b_error = VLC_TRUE;
gbazin's avatar
   
gbazin committed
1010
1011
            return NULL;
        }
1012
1013
1014
1015
1016
1017
1018

        if( p_sys->video.i_rmask )
            p_sys->p_vout->render.i_rmask = p_sys->video.i_rmask;
        if( p_sys->video.i_gmask )
            p_sys->p_vout->render.i_gmask = p_sys->video.i_gmask;
        if( p_sys->video.i_bmask )
            p_sys->p_vout->render.i_bmask = p_sys->video.i_bmask;
gbazin's avatar
   
gbazin committed
1019
1020
1021
1022
1023
    }

    /* Get a new picture */
    while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
    {
gbazin's avatar
   
gbazin committed
1024
        int i_pic, i_ready_pic = 0;
gbazin's avatar
   
gbazin committed
1025

gbazin's avatar
   
gbazin committed
1026
1027
1028
1029
        if( p_dec->b_die || p_dec->b_error )
        {
            return NULL;
        }
gbazin's avatar
   
gbazin committed
1030
1031
1032
1033
1034
1035

#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
        /* Check the decoder doesn't leak pictures */
        for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
             i_pic++ )
        {
1036
1037
1038
1039
1040
            if( p_pic->i_status == READY_PICTURE )
            {
                if( i_ready_pic++ > 0 ) break;
                else continue;
            }
gbazin's avatar
   
gbazin committed
1041

gbazin's avatar
   
gbazin committed
1042
            if( p_pic->i_status != DISPLAYED_PICTURE &&
gbazin's avatar
   
gbazin committed
1043
1044
                p_pic->i_status != RESERVED_PICTURE &&
                p_pic->i_status != READY_PICTURE ) break;
gbazin's avatar
   
gbazin committed
1045

1046
1047
            if( !p_pic->i_refcount && p_pic->i_status != RESERVED_PICTURE )
                break;
gbazin's avatar
   
gbazin committed
1048
1049
1050
        }
        if(