decoder.c 36.6 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 <stdlib.h>
30
#include <vlc/vlc.h>
Laurent Aimar's avatar
Laurent Aimar committed
31

zorglub's avatar
zorglub committed
32
33
34
35
36
37
38
39
40
41
#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
42
#include "input_internal.h"
43

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

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

gbazin's avatar
   
gbazin committed
50
51
52
53
54
55
/* 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
56
57
static void vout_link_picture( decoder_t *, picture_t * );
static void vout_unlink_picture( decoder_t *, picture_t * );
gbazin's avatar
   
gbazin committed
58

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

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

64
65
struct decoder_owner_sys_t
{
66
67
    vlc_bool_t      b_own_thread;

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

70
71
    input_thread_t  *p_input;

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

    vout_thread_t   *p_vout;

77
78
79
    vout_thread_t   *p_spu_vout;
    int              i_spu_channel;

80
81
    sout_instance_t         *p_sout;
    sout_packetizer_input_t *p_sout_input;
82

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

86
87
88
89
90
91
92
93
94
95
    /* 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;
};


zorglub's avatar
zorglub committed
96
97
98
99
100
101
102
/**
 * 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
103
104
decoder_t *input_DecoderNew( input_thread_t *p_input,
                             es_format_t *fmt, vlc_bool_t b_force_decoder )
105
{
106
107
    decoder_t   *p_dec = NULL;
    vlc_value_t val;
108

109
    /* If we are in sout mode, search for packetizer module */
zorglub's avatar
zorglub committed
110
    if( p_input->p->p_sout && !b_force_decoder )
111
    {
112
        /* Create the decoder configuration structure */
Laurent Aimar's avatar
Laurent Aimar committed
113
        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_PACKETIZER );
114
        if( p_dec == NULL )
gbazin's avatar
   
gbazin committed
115
        {
116
            msg_Err( p_input, "could not create packetizer" );
117
118
            intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"), 
                            _("VLC could not open the packetizer module.") );
119
            return NULL;
gbazin's avatar
   
gbazin committed
120
        }
121
    }
122
    else
123
    {
gbazin's avatar
   
gbazin committed
124
        /* Create the decoder configuration structure */
Laurent Aimar's avatar
Laurent Aimar committed
125
        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER );
gbazin's avatar
   
gbazin committed
126
127
128
        if( p_dec == NULL )
        {
            msg_Err( p_input, "could not create decoder" );
129
130
            intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"), 
                            _("VLC could not open the decoder module.") );
gbazin's avatar
   
gbazin committed
131
132
            return NULL;
        }
133
134
    }

135
    if( !p_dec->p_module )
Sam Hocevar's avatar
   
Sam Hocevar committed
136
    {
gbazin's avatar
   
gbazin committed
137
138
        msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
                 "VLC probably does not support this sound or video format.",
139
                 (char*)&p_dec->fmt_in.i_codec );
140
        intf_UserFatal( p_dec, VLC_FALSE, _("No suitable decoder module "
141
            "for format"), _("VLC probably does not support the \"%4.4s\" "
142
143
            "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
144
145
146

        DeleteDecoder( p_dec );
        vlc_object_destroy( p_dec );
147
        return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
148
149
    }

zorglub's avatar
zorglub committed
150
    if( p_input->p->p_sout && p_input->p->input.b_can_pace_control &&
Laurent Aimar's avatar
Laurent Aimar committed
151
        !b_force_decoder )
152
153
154
155
156
157
158
159
160
    {
        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;
    }
161

162
    if( p_dec->p_owner->b_own_thread )
Henri Fallon's avatar
   
Henri Fallon committed
163
    {
164
        int i_priority;
Laurent Aimar's avatar
Laurent Aimar committed
165
        if( fmt->i_cat == AUDIO_ES )
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
            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 ) )
        {
            msg_Err( p_dec, "cannot spawn decoder thread \"%s\"",
                             p_dec->p_module->psz_object_name );
            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
181
182
    }

183
    return p_dec;
184
185
}

zorglub's avatar
zorglub committed
186
187
188
189
190
191
192
/**
 * 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
193
void input_DecoderDelete( decoder_t *p_dec )
194
{
195
    p_dec->b_die = VLC_TRUE;
196

197
    if( p_dec->p_owner->b_own_thread )
198
    {
199
200
201
        /* 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
202
        input_DecoderDecode( p_dec, p_block );
203

204
        vlc_thread_join( p_dec );
205
206
207

        /* Don't module_Unneed() here because of the dll loader that wants
         * close() in the same thread than open()/decode() */
208
209
210
    }
    else
    {
211
212
213
        /* Flush */
        input_DecoderDecode( p_dec, NULL );

214
215
        module_Unneed( p_dec, p_dec->p_module );
    }
216

gbazin's avatar
   
gbazin committed
217
218
219
220
221
    /* Delete decoder configuration */
    DeleteDecoder( p_dec );

    /* Delete the decoder */
    vlc_object_destroy( p_dec );
222
}
zorglub's avatar
zorglub committed
223
224

/**
225
 * Put a block_t in the decoder's fifo.
zorglub's avatar
zorglub committed
226
227
228
229
 *
 * \param p_dec the decoder object
 * \param p_block the data block
 */
Laurent Aimar's avatar
Laurent Aimar committed
230
void input_DecoderDecode( decoder_t * p_dec, block_t *p_block )
231
{
232
233
    if( p_dec->p_owner->b_own_thread )
    {
zorglub's avatar
zorglub committed
234
        if( p_dec->p_owner->p_input->p->b_out_pace_control )
235
236
        {
            /* FIXME !!!!! */
237
238
            while( !p_dec->b_die && !p_dec->b_error &&
                   p_dec->p_owner->p_fifo->i_depth > 10 )
239
240
241
242
            {
                msleep( 1000 );
            }
        }
243
244
245
246
247
        else if( p_dec->p_owner->p_fifo->i_size > 50000000 /* 50 MB */ )
        {
            /* 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
248
                      "consumed quickly enough), resetting fifo!" );
249
250
251
252
            block_FifoEmpty( p_dec->p_owner->p_fifo );
        }

        block_FifoPut( p_dec->p_owner->p_fifo, p_block );
253
254
255
    }
    else
    {
256
        if( p_dec->b_error || (p_block && p_block->i_buffer <= 0) )
257
        {
258
            if( p_block ) block_Release( p_block );
259
260
261
262
263
264
        }
        else
        {
            DecoderDecode( p_dec, p_block );
        }
    }
265
}
266

Laurent Aimar's avatar
Laurent Aimar committed
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
void input_DecoderDiscontinuity( decoder_t * p_dec )
{
    block_t *p_null;

    /* Empty the fifo */
    if( p_dec->p_owner->b_own_thread )
    {
        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;
    memset( p_null->p_buffer, 0, p_null->i_buffer );

    input_DecoderDecode( p_dec, p_null );
}

Laurent Aimar's avatar
   
Laurent Aimar committed
285
286
287
288
289
290
291
292
293
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
{
    if( p_dec->p_owner->b_own_thread && p_dec->p_owner->p_fifo->i_depth > 0 )
    {
        return VLC_FALSE;
    }
    return VLC_TRUE;
}

Laurent Aimar's avatar
Laurent Aimar committed
294
295
296
297
298
void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end )
{
    p_dec->p_owner->i_preroll_end = i_preroll_end;
}

Laurent Aimar's avatar
Laurent Aimar committed
299
#if 0
zorglub's avatar
zorglub committed
300
/**
301
 * Create a NULL packet for padding in case of a data loss
zorglub's avatar
zorglub committed
302
303
304
305
306
 *
 * \param p_input the input thread
 * \param p_es es descriptor
 * \return nothing
 */
307
308
static void input_NullPacket( input_thread_t * p_input,
                              es_descriptor_t * p_es )
309
{
Laurent Aimar's avatar
Laurent Aimar committed
310
#if 0
311
312
    block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
    if( p_block )
313
    {
314
        memset( p_block->p_buffer, 0, PADDING_PACKET_SIZE );
gbazin's avatar
   
gbazin committed
315
        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
316

317
        block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block );
318
    }
Laurent Aimar's avatar
Laurent Aimar committed
319
#endif
320
321
}

zorglub's avatar
zorglub committed
322
323
324
325
326
327
/**
 * Send a NULL packet to the decoders
 *
 * \param p_input the input thread
 * \return nothing
 */
328
void input_EscapeDiscontinuity( input_thread_t * p_input )
329
{
Laurent Aimar's avatar
Laurent Aimar committed
330
#if 0
331
    unsigned int i_es, i;
332

zorglub's avatar
zorglub committed
333
    for( i_es = 0; i_es < p_input->p->stream.i_selected_es_number; i_es++ )
334
    {
zorglub's avatar
zorglub committed
335
        es_descriptor_t * p_es = p_input->p->stream.pp_selected_es[i_es];
336

337
        if( p_es->p_dec != NULL )
338
339
340
341
342
343
344
        {
            for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
            {
                input_NullPacket( p_input, p_es );
            }
        }
    }
Laurent Aimar's avatar
Laurent Aimar committed
345
#endif
346
347
}

zorglub's avatar
zorglub committed
348
349
350
351
352
353
/**
 * Send a NULL packet to the audio decoders
 *
 * \param p_input the input thread
 * \return nothing
 */
354
void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
355
{
Laurent Aimar's avatar
Laurent Aimar committed
356
#if 0
357
    unsigned int i_es, i;
358

zorglub's avatar
zorglub committed
359
    for( i_es = 0; i_es < p_input->p->stream.i_selected_es_number; i_es++ )
360
    {
zorglub's avatar
zorglub committed
361
        es_descriptor_t * p_es = p_input->p->stream.pp_selected_es[i_es];
362

363
        if( p_es->p_dec != NULL && p_es->i_cat == AUDIO_ES )
364
        {
365
            for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
366
            {
367
                input_NullPacket( p_input, p_es );
368
369
370
            }
        }
    }
Laurent Aimar's avatar
Laurent Aimar committed
371
#endif
372
}
Laurent Aimar's avatar
Laurent Aimar committed
373
#endif
374

zorglub's avatar
zorglub committed
375
376
377
378
379
380
381
382
/**
 * 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
383
384
static decoder_t * CreateDecoder( input_thread_t *p_input,
                                  es_format_t *fmt, int i_object_type )
Sam Hocevar's avatar
   
Sam Hocevar committed
385
{
gbazin's avatar
   
gbazin committed
386
    decoder_t *p_dec;
Sam Hocevar's avatar
   
Sam Hocevar committed
387

gbazin's avatar
   
gbazin committed
388
    p_dec = vlc_object_create( p_input, i_object_type );
gbazin's avatar
   
gbazin committed
389
    if( p_dec == NULL )
Sam Hocevar's avatar
   
Sam Hocevar committed
390
    {
391
        msg_Err( p_input, "out of memory" );
Sam Hocevar's avatar
   
Sam Hocevar committed
392
393
394
        return NULL;
    }

gbazin's avatar
   
gbazin committed
395
396
397
398
    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
399

zorglub's avatar
zorglub committed
400
   /* Initialize the decoder fifo */
gbazin's avatar
   
gbazin committed
401
402
    p_dec->p_module = NULL;

403
    memset( &null_es_format, 0, sizeof(es_format_t) );
Laurent Aimar's avatar
Laurent Aimar committed
404
405
    es_format_Copy( &p_dec->fmt_in, fmt );
    es_format_Copy( &p_dec->fmt_out, &null_es_format );
gbazin's avatar
   
gbazin committed
406
407

    /* Allocate our private structure for the decoder */
Laurent Aimar's avatar
Laurent Aimar committed
408
    p_dec->p_owner = malloc( sizeof( decoder_owner_sys_t ) );
gbazin's avatar
   
gbazin committed
409
410
411
412
413
    if( p_dec->p_owner == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return NULL;
    }
414
    p_dec->p_owner->b_own_thread = VLC_TRUE;
Laurent Aimar's avatar
Laurent Aimar committed
415
    p_dec->p_owner->i_preroll_end = -1;
416
    p_dec->p_owner->p_input = p_input;
gbazin's avatar
   
gbazin committed
417
418
419
    p_dec->p_owner->p_aout = NULL;
    p_dec->p_owner->p_aout_input = NULL;
    p_dec->p_owner->p_vout = NULL;
420
421
    p_dec->p_owner->p_spu_vout = NULL;
    p_dec->p_owner->i_spu_channel = 0;
zorglub's avatar
zorglub committed
422
    p_dec->p_owner->p_sout = p_input->p->p_sout;
423
    p_dec->p_owner->p_sout_input = NULL;
424
    p_dec->p_owner->p_packetizer = NULL;
425

426
427
428
429
430
431
    /* decoder fifo */
    if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return NULL;
    }
432

gbazin's avatar
   
gbazin committed
433
434
435
436
437
    /* 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
438
439
    p_dec->pf_picture_link    = vout_link_picture;
    p_dec->pf_picture_unlink  = vout_unlink_picture;
440
441
    p_dec->pf_spu_buffer_new  = spu_new_buffer;
    p_dec->pf_spu_buffer_del  = spu_del_buffer;
gbazin's avatar
   
gbazin committed
442

gbazin's avatar
   
gbazin committed
443
444
    vlc_object_attach( p_dec, p_input );

445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
    /* 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
462
463
464
            es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_out,
                            &null_es_format );

465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
            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 );
            }
        }
    }

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

zorglub's avatar
zorglub committed
483
484
485
486
487
488
/**
 * The decoding main loop
 *
 * \param p_dec the decoder
 * \return 0
 */
gbazin's avatar
   
gbazin committed
489
490
static int DecoderThread( decoder_t * p_dec )
{
491
    block_t *p_block;
gbazin's avatar
   
gbazin committed
492
493

    /* The decoder's main loop */
494
    while( !p_dec->b_die && !p_dec->b_error )
gbazin's avatar
   
gbazin committed
495
    {
496
        if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL )
gbazin's avatar
   
gbazin committed
497
        {
498
            p_dec->b_error = 1;
gbazin's avatar
   
gbazin committed
499
500
            break;
        }
501
        if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS )
502
503
504
505
        {
            break;
        }
    }
gbazin's avatar
   
gbazin committed
506

507
508
509
510
    while( !p_dec->b_die )
    {
        /* Trash all received PES packets */
        p_block = block_FifoGet( p_dec->p_owner->p_fifo );
511
        if( p_block ) block_Release( p_block );
512
    }
gbazin's avatar
   
gbazin committed
513

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

518
519
    return 0;
}
gbazin's avatar
   
gbazin committed
520

zorglub's avatar
zorglub committed
521
522
523
524
525
526
527
/**
 * Decode a block
 *
 * \param p_dec the decoder object
 * \param p_block the block to decode
 * \return VLC_SUCCESS or an error code
 */
528
529
static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
{
530
    int i_rate = p_block ? p_block->i_rate : 1000;
531

532
    if( p_block && p_block->i_buffer <= 0 )
533
534
535
536
537
538
539
540
541
    {
        block_Release( p_block );
        return VLC_SUCCESS;
    }

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

542
543
        while( ( p_sout_block =
                     p_dec->pf_packetize( p_dec, p_block ? &p_block : 0 ) ) )
544
        {
545
            if( !p_dec->p_owner->p_sout_input )
546
547
            {
                es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out );
Laurent Aimar's avatar
Laurent Aimar committed
548

549
                p_dec->p_owner->sout.i_group = p_dec->fmt_in.i_group;
Laurent Aimar's avatar
Laurent Aimar committed
550
                p_dec->p_owner->sout.i_id = p_dec->fmt_in.i_id;
551
552
                if( p_dec->fmt_in.psz_language )
                {
553
554
                    if( p_dec->p_owner->sout.psz_language )
                        free( p_dec->p_owner->sout.psz_language );
555
556
                    p_dec->p_owner->sout.psz_language =
                        strdup( p_dec->fmt_in.psz_language );
557
                }
gbazin's avatar
   
gbazin committed
558

559
                p_dec->p_owner->p_sout_input =
560
561
                    sout_InputNew( p_dec->p_owner->p_sout,
                                   &p_dec->p_owner->sout );
562

563
                if( p_dec->p_owner->p_sout_input == NULL )
gbazin's avatar
   
gbazin committed
564
                {
565
566
                    msg_Err( p_dec, "cannot create packetizer output (%4.4s)",
                             (char *)&p_dec->p_owner->sout.i_codec );
567
                    p_dec->b_error = VLC_TRUE;
gbazin's avatar
   
gbazin committed
568

569
                    while( p_sout_block )
570
                    {
571
                        block_t *p_next = p_sout_block->p_next;
572
573
                        block_Release( p_sout_block );
                        p_sout_block = p_next;
574
                    }
575
576
577
                    break;
                }
            }
gbazin's avatar
   
gbazin committed
578

579
580
            while( p_sout_block )
            {
581
                block_t *p_next = p_sout_block->p_next;
gbazin's avatar
   
gbazin committed
582

583
                p_sout_block->p_next = NULL;
584
                p_sout_block->i_rate = i_rate;
gbazin's avatar
   
gbazin committed
585

586
                sout_InputSendBuffer( p_dec->p_owner->p_sout_input,
587
                                      p_sout_block );
gbazin's avatar
   
gbazin committed
588

589
                p_sout_block = p_next;
gbazin's avatar
   
gbazin committed
590
            }
591
592
593

            /* 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
594
                p_dec->p_owner->p_input->p->b_out_pace_control )
595
            {
596
                msg_Dbg( p_dec, "switching to sync mode" );
zorglub's avatar
zorglub committed
597
                p_dec->p_owner->p_input->p->b_out_pace_control = VLC_FALSE;
598
599
            }
            else if( p_dec->p_owner->p_sout->i_out_pace_nocontrol <= 0 &&
zorglub's avatar
zorglub committed
600
                     !p_dec->p_owner->p_input->p->b_out_pace_control )
601
            {
602
                msg_Dbg( p_dec, "switching to async mode" );
zorglub's avatar
zorglub committed
603
                p_dec->p_owner->p_input->p->b_out_pace_control = VLC_TRUE;
604
            }
gbazin's avatar
   
gbazin committed
605
        }
606
607
608
609
610
    }
    else if( p_dec->fmt_in.i_cat == AUDIO_ES )
    {
        aout_buffer_t *p_aout_buf;

611
612
613
614
615
616
617
618
        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 =
                    p_packetizer->pf_packetize( p_packetizer, &p_block )) )
            {
619
620
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
621
622
                    es_format_Clean( &p_dec->fmt_in );
                    es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out );
623
624
                }

625
                while( p_packetized_block )
626
                {
627
628
                    block_t *p_next = p_packetized_block->p_next;
                    p_packetized_block->p_next = NULL;
629
                    p_packetized_block->i_rate = i_rate;
630
631
632
633

                    while( (p_aout_buf = p_dec->pf_decode_audio( p_dec,
                                                       &p_packetized_block )) )
                    {
634
                        input_thread_t *p_i =(input_thread_t*)(p_dec->p_parent);
zorglub's avatar
zorglub committed
635
                        vlc_mutex_lock( &p_i->p->counters.counters_lock );
636
                        stats_UpdateInteger( p_dec,
zorglub's avatar
zorglub committed
637
638
                               p_i->p->counters.p_decoded_audio, 1, NULL );
                        vlc_mutex_unlock( &p_i->p->counters.counters_lock );
639
640
641

                        /* FIXME the best would be to handle the case
                         * start_date < preroll < end_date
Laurent Aimar's avatar
Laurent Aimar committed
642
643
644
645
646
647
648
649
650
651
652
653
654
655
                         * but that's not easy with non raw audio stream */
                        if( p_dec->p_owner->i_preroll_end > 0 &&
                            p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
                        {
                            aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
                                                  p_dec->p_owner->p_aout_input, p_aout_buf );
                        }
                        else
                        {
                            p_dec->p_owner->i_preroll_end = -1;
                            aout_DecPlay( p_dec->p_owner->p_aout,
                                          p_dec->p_owner->p_aout_input,
                                          p_aout_buf );
                        }
656
657
658
                    }

                    p_packetized_block = p_next;
659
660
661
662
                }
            }
        }
        else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
663
        {
664
            input_thread_t *p_i = (input_thread_t*)(p_dec->p_parent);
zorglub's avatar
zorglub committed
665
            vlc_mutex_lock( &p_i->p->counters.counters_lock );
666
            stats_UpdateInteger( p_dec,
zorglub's avatar
zorglub committed
667
668
                               p_i->p->counters.p_decoded_audio, 1, NULL );
            vlc_mutex_unlock( &p_i->p->counters.counters_lock );
669

Laurent Aimar's avatar
Laurent Aimar committed
670
671
672
673
674
675
676
677
678
679
680
681
682
            if( p_dec->p_owner->i_preroll_end > 0 &&
                p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
            {
                aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
                                      p_dec->p_owner->p_aout_input, p_aout_buf );
            }
            else
            {
                p_dec->p_owner->i_preroll_end = -1;
                aout_DecPlay( p_dec->p_owner->p_aout,
                              p_dec->p_owner->p_aout_input,
                              p_aout_buf );
            }
683
        }
gbazin's avatar
   
gbazin committed
684
    }
685
    else if( p_dec->fmt_in.i_cat == VIDEO_ES )
686
    {
687
688
        picture_t *p_pic;

689
690
691
692
693
694
695
696
        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 =
                    p_packetizer->pf_packetize( p_packetizer, &p_block )) )
            {
697
698
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
699
700
                    es_format_Clean( &p_dec->fmt_in );
                    es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out );
701
702
                }

703
                while( p_packetized_block )
704
                {
705
706
                    block_t *p_next = p_packetized_block->p_next;
                    p_packetized_block->p_next = NULL;
707
                    p_packetized_block->i_rate = i_rate;
708
709
710
711

                    while( (p_pic = p_dec->pf_decode_video( p_dec,
                                                       &p_packetized_block )) )
                    {
712
                        input_thread_t *p_i =(input_thread_t*)(p_dec->p_parent);
zorglub's avatar
zorglub committed
713
                        vlc_mutex_lock( &p_i->p->counters.counters_lock );
714
                        stats_UpdateInteger( p_dec,
zorglub's avatar
zorglub committed
715
716
                               p_i->p->counters.p_decoded_video, 1, NULL );
                        vlc_mutex_unlock( &p_i->p->counters.counters_lock );
717

Laurent Aimar's avatar
Laurent Aimar committed
718
719
720
721
722
723
724
725
726
727
728
729
                        if( p_dec->p_owner->i_preroll_end > 0 &&
                            p_pic->date < p_dec->p_owner->i_preroll_end )
                        {
                            vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
                        }
                        else
                        {
                            p_dec->p_owner->i_preroll_end = -1;
                            vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
                                              p_pic->date );
                            vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
                        }
730
731
732
                    }

                    p_packetized_block = p_next;
733
734
735
736
                }
            }
        }
        else while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
737
        {
738
            input_thread_t *p_i = (input_thread_t*)(p_dec->p_parent);
zorglub's avatar
zorglub committed
739
            vlc_mutex_lock( &p_i->p->counters.counters_lock );
740
            stats_UpdateInteger( p_dec,
zorglub's avatar
zorglub committed
741
742
                               p_i->p->counters.p_decoded_video, 1, NULL );
            vlc_mutex_unlock( &p_i->p->counters.counters_lock );
743

Laurent Aimar's avatar
Laurent Aimar committed
744
745
746
747
748
749
750
751
752
753
754
            if( p_dec->p_owner->i_preroll_end > 0 &&
                p_pic->date < p_dec->p_owner->i_preroll_end )
            {
                vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
            }
            else
            {
                p_dec->p_owner->i_preroll_end = -1;
                vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date );
                vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
            }
755
        }
756
    }
757
758
    else if( p_dec->fmt_in.i_cat == SPU_ES )
    {
759
760
761
762
        vout_thread_t *p_vout;
        subpicture_t *p_spu;
        while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) )
        {
763
            input_thread_t *p_i = (input_thread_t*)(p_dec->p_parent);
zorglub's avatar
zorglub committed
764
            vlc_mutex_lock( &p_i->p->counters.counters_lock );
765
            stats_UpdateInteger( p_dec,
zorglub's avatar
zorglub committed
766
767
                               p_i->p->counters.p_decoded_sub, 1, NULL );
            vlc_mutex_unlock( &p_i->p->counters.counters_lock );
768

Laurent Aimar's avatar
Laurent Aimar committed
769
770
771
772
773
774
775
776
777
            if( p_dec->p_owner->i_preroll_end > 0 &&
                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_dec->p_owner->p_vout->p_spu, p_spu );
                continue;
            }

            p_dec->p_owner->i_preroll_end = -1;
778
779
780
            p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
            if( p_vout )
            {
781
                spu_DisplaySubpicture( p_vout->p_spu, p_spu );
782
783
784
                vlc_object_release( p_vout );
            }
        }
785
786
787
    }
    else
    {
zorglub's avatar
zorglub committed
788
        msg_Err( p_dec, "unknown ES format" );
789
790
        p_dec->b_error = 1;
    }
791

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

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

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

811
    /* Cleanup */
gbazin's avatar
   
gbazin committed
812
813
814
815
816
817
818
    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
819
#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
gbazin's avatar
   
gbazin committed
820
821
822
823
        /* 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
824
825
826
827
            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
828
        }
gbazin's avatar
   
gbazin committed
829
#undef p_pic
gbazin's avatar
   
gbazin committed
830
831

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

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

841
842
843
844
845
846
847
    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 )
        {
848
849
            spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR,
                         p_dec->p_owner->i_spu_channel );
850
851
852
853
            vlc_object_release( p_vout );
        }
    }

854
855
856
857
858
859
860
861
862
863
864
865
    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
866

867
868
    vlc_object_detach( p_dec );

gbazin's avatar
   
gbazin committed
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
    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 )
    {
894
895
896
        audio_sample_format_t format;
        int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" );

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

        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) )
        {
904
            if ( i_force_dolby == 1 )
905
906
907
908
            {
                format.i_original_channels = format.i_original_channels |
                                             AOUT_CHAN_DOLBYSTEREO;
            }
909
            else /* i_force_dolby == 2 */
910
911
912
913
914
915
            {
                format.i_original_channels = format.i_original_channels &
                                             ~AOUT_CHAN_DOLBYSTEREO;
            }
        }

gbazin's avatar
   
gbazin committed
916
        p_sys->p_aout_input =
917
            aout_DecNew( p_dec, &p_sys->p_aout, &format );
gbazin's avatar
   
gbazin committed
918
919
920
        if( p_sys->p_aout_input == NULL )
        {
            msg_Err( p_dec, "failed to create audio output" );
gbazin's avatar
   
gbazin committed
921
            p_dec->b_error = VLC_TRUE;
gbazin's avatar
   
gbazin committed
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
957
            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;
        }

958
959
960
        if( !p_dec->fmt_out.video.i_visible_width ||
            !p_dec->fmt_out.video.i_visible_height )
        {
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
            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;
            }
976
977
        }

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

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
997
998
999
        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,
1000
                     p_dec->fmt_out.video.i_sar_den, 50000 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1001

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

        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
1020
1021
1022
1023
1024
    }

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

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

#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++ )
        {
1037
1038
1039
1040
1041
            if( p_pic->i_status == READY_PICTURE )
            {
                if( i_ready_pic++ > 0 ) break;
                else continue;
            }
gbazin's avatar
   
gbazin committed
1042

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

1047
1048
            if( !p_pic->i_refcount && p_pic->i_status != RESERVED_PICTURE )
                break;
gbazin's avatar
   
gbazin committed
1049
1050
1051
        }
        if( i_pic == p_dec->p_owner->p_vout->render.i_pictures )
        {
zorglub's avatar
zorglub committed
1052
            msg_Err( p_dec, "decoder is leaking pictures, resetting the heap" );
gbazin's avatar
   
gbazin committed
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065

            /* Just free all the pictures */
            for( i_pic = 0; i_pic <