decoder.c 41.2 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
    /* 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;
92
93
94
95
96
97

    /* CC */
    vlc_bool_t b_cc_supported;
    vlc_mutex_t lock_cc;
    vlc_bool_t pb_cc_present[4];
    decoder_t *pp_cc[4];
98
99
};

100
101
102
103
104
105
/* */
static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec )
{
    msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
             "VLC probably does not support this sound or video format.",
             (char*)&codec );
106
107
108
    intf_UserFatal( p_dec, VLC_FALSE, _("No suitable decoder module"), 
                    _("VLC does not support the audio or video format \"%4.4s\". "
                      "Unfortunately there is no way for you to fix this."), (char*)&codec );
109
110
}

111
112
/* decoder_GetInputAttachment:
 */
Laurent Aimar's avatar
Laurent Aimar committed
113
114
input_attachment_t *decoder_GetInputAttachment( decoder_t *p_dec,
                                                const char *psz_name )
115
116
117
118
119
120
{
    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
121
122
123
124
125
126
127
128
129
/* 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 );
}
130
131
132
133
134
135
/* decoder_GetDisplayDate:
 */
mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
{
    return i_ts;
}
136

zorglub's avatar
zorglub committed
137
138
139
140
141
142
143
/**
 * 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
144
145
decoder_t *input_DecoderNew( input_thread_t *p_input,
                             es_format_t *fmt, vlc_bool_t b_force_decoder )
146
{
147
148
    decoder_t   *p_dec = NULL;
    vlc_value_t val;
149

150
    /* If we are in sout mode, search for packetizer module */
zorglub's avatar
zorglub committed
151
    if( p_input->p->p_sout && !b_force_decoder )
152
    {
153
        /* Create the decoder configuration structure */
Laurent Aimar's avatar
Laurent Aimar committed
154
        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_PACKETIZER );
155
        if( p_dec == NULL )
gbazin's avatar
   
gbazin committed
156
        {
157
            msg_Err( p_input, "could not create packetizer" );
158
            intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"),
159
                            _("VLC could not open the packetizer module.") );
160
            return NULL;
gbazin's avatar
   
gbazin committed
161
        }
162
    }
163
    else
164
    {
gbazin's avatar
   
gbazin committed
165
        /* Create the decoder configuration structure */
Laurent Aimar's avatar
Laurent Aimar committed
166
        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER );
gbazin's avatar
   
gbazin committed
167
168
169
        if( p_dec == NULL )
        {
            msg_Err( p_input, "could not create decoder" );
170
            intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"),
171
                            _("VLC could not open the decoder module.") );
gbazin's avatar
   
gbazin committed
172
173
            return NULL;
        }
174
175
    }

176
    if( !p_dec->p_module )
Sam Hocevar's avatar
   
Sam Hocevar committed
177
    {
178
        DecoderUnsupportedCodec( p_dec, fmt->i_codec );
gbazin's avatar
   
gbazin committed
179
180
181

        DeleteDecoder( p_dec );
        vlc_object_destroy( p_dec );
182
        return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
183
184
    }

zorglub's avatar
zorglub committed
185
    if( p_input->p->p_sout && p_input->p->input.b_can_pace_control &&
Laurent Aimar's avatar
Laurent Aimar committed
186
        !b_force_decoder )
187
188
189
190
191
192
193
194
195
    {
        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;
    }
196

197
    if( p_dec->p_owner->b_own_thread )
Henri Fallon's avatar
   
Henri Fallon committed
198
    {
199
        int i_priority;
Laurent Aimar's avatar
Laurent Aimar committed
200
        if( fmt->i_cat == AUDIO_ES )
201
202
203
204
205
206
207
208
            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 ) )
        {
209
            msg_Err( p_dec, "cannot spawn decoder thread" );
210
211
212
213
214
            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
215
216
    }

217
    return p_dec;
218
219
}

zorglub's avatar
zorglub committed
220
221
222
223
224
225
226
/**
 * 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
227
void input_DecoderDelete( decoder_t *p_dec )
228
{
229
    vlc_object_kill( p_dec );
230

231
    if( p_dec->p_owner->b_own_thread )
232
    {
233
234
235
        /* 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
236
        input_DecoderDecode( p_dec, p_block );
237

238
        vlc_thread_join( p_dec );
239
240
241

        /* Don't module_Unneed() here because of the dll loader that wants
         * close() in the same thread than open()/decode() */
242
243
244
    }
    else
    {
245
246
247
        /* Flush */
        input_DecoderDecode( p_dec, NULL );

248
249
        module_Unneed( p_dec, p_dec->p_module );
    }
250

251
252
253
254
255
256
257
258
    /* */
    if( p_dec->p_owner->b_cc_supported )
    {
        int i;
        for( i = 0; i < 4; i++ )
            input_DecoderSetCcState( p_dec, VLC_FALSE, i );
    }

gbazin's avatar
   
gbazin committed
259
260
261
262
263
    /* Delete decoder configuration */
    DeleteDecoder( p_dec );

    /* Delete the decoder */
    vlc_object_destroy( p_dec );
264
}
zorglub's avatar
zorglub committed
265
266

/**
267
 * Put a block_t in the decoder's fifo.
zorglub's avatar
zorglub committed
268
269
270
271
 *
 * \param p_dec the decoder object
 * \param p_block the data block
 */
Laurent Aimar's avatar
Laurent Aimar committed
272
void input_DecoderDecode( decoder_t * p_dec, block_t *p_block )
273
{
274
275
    if( p_dec->p_owner->b_own_thread )
    {
zorglub's avatar
zorglub committed
276
        if( p_dec->p_owner->p_input->p->b_out_pace_control )
277
278
        {
            /* FIXME !!!!! */
279
            while( !p_dec->b_die && !p_dec->b_error &&
280
                   block_FifoCount( p_dec->p_owner->p_fifo ) > 10 )
281
282
283
284
            {
                msleep( 1000 );
            }
        }
285
        else if( block_FifoSize( p_dec->p_owner->p_fifo ) > 50000000 /* 50 MB */ )
286
287
288
289
        {
            /* 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
290
                      "consumed quickly enough), resetting fifo!" );
291
292
293
294
            block_FifoEmpty( p_dec->p_owner->p_fifo );
        }

        block_FifoPut( p_dec->p_owner->p_fifo, p_block );
295
296
297
    }
    else
    {
298
        if( p_dec->b_error || (p_block && p_block->i_buffer <= 0) )
299
        {
300
            if( p_block ) block_Release( p_block );
301
302
303
304
305
306
        }
        else
        {
            DecoderDecode( p_dec, p_block );
        }
    }
307
}
308

309
void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush )
Laurent Aimar's avatar
Laurent Aimar committed
310
311
312
313
{
    block_t *p_null;

    /* Empty the fifo */
314
    if( p_dec->p_owner->b_own_thread && b_flush )
Laurent Aimar's avatar
Laurent Aimar committed
315
316
317
318
319
        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;
320
321
322
    /* 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
323
324
325
326
327
    memset( p_null->p_buffer, 0, p_null->i_buffer );

    input_DecoderDecode( p_dec, p_null );
}

Laurent Aimar's avatar
   
Laurent Aimar committed
328
329
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
{
330
331
    if( p_dec->p_owner->b_own_thread
     && block_FifoCount( p_dec->p_owner->p_fifo ) > 0 )
Laurent Aimar's avatar
   
Laurent Aimar committed
332
333
334
335
336
337
    {
        return VLC_FALSE;
    }
    return VLC_TRUE;
}

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
void input_DecoderIsCcPresent( decoder_t *p_dec, vlc_bool_t pb_present[4] )
{
    int i;

    vlc_mutex_lock( &p_dec->p_owner->lock_cc );
    for( i = 0; i < 4; i++ )
        pb_present[i] =  p_dec->p_owner->pb_cc_present[i];
    vlc_mutex_unlock( &p_dec->p_owner->lock_cc );
}
int input_DecoderSetCcState( decoder_t *p_dec, vlc_bool_t b_decode, int i_channel )
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;

    //msg_Warn( p_dec, "input_DecoderSetCcState: %d @%d", b_decode, i_channel );

    if( i_channel < 0 || i_channel >= 4 || !p_owner->pb_cc_present[i_channel] )
        return VLC_EGENERIC;

    if( b_decode )
    {
        static const vlc_fourcc_t fcc[4] = {
            VLC_FOURCC('c', 'c', '1', ' '),
            VLC_FOURCC('c', 'c', '2', ' '),
            VLC_FOURCC('c', 'c', '3', ' '),
            VLC_FOURCC('c', 'c', '4', ' '),
        };
        decoder_t *p_cc;
        es_format_t fmt;

        es_format_Init( &fmt, SPU_ES, fcc[i_channel] );
        p_cc = CreateDecoder( p_owner->p_input, &fmt, VLC_OBJECT_DECODER );
        if( !p_cc )
        {
            msg_Err( p_dec, "could not create decoder" );
            intf_UserFatal( p_dec, VLC_FALSE, _("Streaming / Transcoding failed"),
                            _("VLC could not open the decoder module.") );
            return VLC_EGENERIC;
        }
        else if( !p_cc->p_module )
        {
            DecoderUnsupportedCodec( p_dec, fcc[i_channel] );
            DeleteDecoder( p_cc );
            vlc_object_destroy( p_cc );
            return VLC_EGENERIC;
        }

        vlc_mutex_lock( &p_owner->lock_cc );
        p_dec->p_owner->pp_cc[i_channel] = p_cc;
        vlc_mutex_unlock( &p_owner->lock_cc );
    }
    else
    {
        decoder_t *p_cc;

        vlc_mutex_lock( &p_owner->lock_cc );
        p_cc = p_dec->p_owner->pp_cc[i_channel];
        p_dec->p_owner->pp_cc[i_channel] = NULL;
        vlc_mutex_unlock( &p_dec->p_owner->lock_cc );

        if( p_cc )
        {
            vlc_object_kill( p_cc );
            module_Unneed( p_cc, p_cc->p_module );
            DeleteDecoder( p_cc );
            vlc_object_destroy( p_cc );
        }
    }
    return VLC_SUCCESS;
}
int input_DecoderGetCcState( decoder_t *p_dec, vlc_bool_t *pb_decode, int i_channel )
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;

    *pb_decode = VLC_FALSE;
    if( i_channel < 0 || i_channel >= 4 || !p_owner->pb_cc_present[i_channel] )
        return VLC_EGENERIC;

    vlc_mutex_lock( &p_owner->lock_cc );
    *pb_decode = p_dec->p_owner->pp_cc[i_channel] != NULL;
    vlc_mutex_unlock( &p_dec->p_owner->lock_cc );
    return VLC_EGENERIC;
}

zorglub's avatar
zorglub committed
421
422
423
424
425
426
427
428
/**
 * 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
429
430
static decoder_t * CreateDecoder( input_thread_t *p_input,
                                  es_format_t *fmt, int i_object_type )
Sam Hocevar's avatar
   
Sam Hocevar committed
431
{
gbazin's avatar
   
gbazin committed
432
    decoder_t *p_dec;
433
434
    decoder_owner_sys_t *p_owner;
    int i;
Sam Hocevar's avatar
   
Sam Hocevar committed
435

gbazin's avatar
   
gbazin committed
436
    p_dec = vlc_object_create( p_input, i_object_type );
gbazin's avatar
   
gbazin committed
437
    if( p_dec == NULL )
Sam Hocevar's avatar
   
Sam Hocevar committed
438
    {
439
        msg_Err( p_input, "out of memory" );
Sam Hocevar's avatar
   
Sam Hocevar committed
440
441
442
        return NULL;
    }

gbazin's avatar
   
gbazin committed
443
444
445
    p_dec->pf_decode_audio = 0;
    p_dec->pf_decode_video = 0;
    p_dec->pf_decode_sub = 0;
446
    p_dec->pf_get_cc = 0;
gbazin's avatar
   
gbazin committed
447
    p_dec->pf_packetize = 0;
gbazin's avatar
   
gbazin committed
448

449
    /* Initialize the decoder fifo */
gbazin's avatar
   
gbazin committed
450
451
    p_dec->p_module = NULL;

452
    memset( &null_es_format, 0, sizeof(es_format_t) );
Laurent Aimar's avatar
Laurent Aimar committed
453
454
    es_format_Copy( &p_dec->fmt_in, fmt );
    es_format_Copy( &p_dec->fmt_out, &null_es_format );
gbazin's avatar
   
gbazin committed
455
456

    /* Allocate our private structure for the decoder */
457
    p_dec->p_owner = p_owner = malloc( sizeof( decoder_owner_sys_t ) );
gbazin's avatar
   
gbazin committed
458
459
460
461
462
    if( p_dec->p_owner == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return NULL;
    }
463
    p_dec->p_owner->b_own_thread = VLC_TRUE;
Laurent Aimar's avatar
Laurent Aimar committed
464
    p_dec->p_owner->i_preroll_end = -1;
465
    p_dec->p_owner->p_input = p_input;
gbazin's avatar
   
gbazin committed
466
467
468
    p_dec->p_owner->p_aout = NULL;
    p_dec->p_owner->p_aout_input = NULL;
    p_dec->p_owner->p_vout = NULL;
469
470
    p_dec->p_owner->p_spu_vout = NULL;
    p_dec->p_owner->i_spu_channel = 0;
zorglub's avatar
zorglub committed
471
    p_dec->p_owner->p_sout = p_input->p->p_sout;
472
    p_dec->p_owner->p_sout_input = NULL;
473
    p_dec->p_owner->p_packetizer = NULL;
474

475
476
477
478
479
480
    /* decoder fifo */
    if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return NULL;
    }
481

gbazin's avatar
   
gbazin committed
482
483
484
485
486
    /* 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
487
488
    p_dec->pf_picture_link    = vout_link_picture;
    p_dec->pf_picture_unlink  = vout_unlink_picture;
489
490
    p_dec->pf_spu_buffer_new  = spu_new_buffer;
    p_dec->pf_spu_buffer_del  = spu_del_buffer;
gbazin's avatar
   
gbazin committed
491

gbazin's avatar
   
gbazin committed
492
493
    vlc_object_attach( p_dec, p_input );

494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
    /* 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
511
512
513
            es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_out,
                            &null_es_format );

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
            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 );
            }
        }
    }

529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
    /* Copy ourself the input replay gain */
    if( fmt->i_cat == AUDIO_ES )
    {
        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];
            }
        }
    }
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
    /* */
    p_owner->b_cc_supported = VLC_FALSE;
    if( i_object_type == VLC_OBJECT_DECODER )
    {
        if( p_owner->p_packetizer && p_owner->p_packetizer->pf_get_cc )
            p_owner->b_cc_supported = VLC_TRUE;
        if( p_dec->pf_get_cc )
            p_owner->b_cc_supported = VLC_TRUE;
    }

    vlc_mutex_init( p_dec, &p_owner->lock_cc );
    for( i = 0; i < 4; i++ )
    {
        p_owner->pb_cc_present[i] = VLC_FALSE;
        p_owner->pp_cc[i] = NULL;
    }
gbazin's avatar
   
gbazin committed
562
563
564
    return p_dec;
}

zorglub's avatar
zorglub committed
565
566
567
568
569
570
/**
 * The decoding main loop
 *
 * \param p_dec the decoder
 * \return 0
 */
gbazin's avatar
   
gbazin committed
571
572
static int DecoderThread( decoder_t * p_dec )
{
573
    block_t *p_block;
gbazin's avatar
   
gbazin committed
574
575

    /* The decoder's main loop */
576
    while( !p_dec->b_die && !p_dec->b_error )
gbazin's avatar
   
gbazin committed
577
    {
578
        if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL )
gbazin's avatar
   
gbazin committed
579
        {
580
            p_dec->b_error = 1;
gbazin's avatar
   
gbazin committed
581
582
            break;
        }
583
        if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS )
584
585
586
587
        {
            break;
        }
    }
gbazin's avatar
   
gbazin committed
588

589
590
591
592
    while( !p_dec->b_die )
    {
        /* Trash all received PES packets */
        p_block = block_FifoGet( p_dec->p_owner->p_fifo );
593
        if( p_block ) block_Release( p_block );
594
    }
gbazin's avatar
   
gbazin committed
595

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

600
601
    return 0;
}
gbazin's avatar
   
gbazin committed
602

Laurent Aimar's avatar
Laurent Aimar committed
603
604
static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p )
{
605
606
607
    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
608
609
610
611
612
613
614
        *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;
615
    const int i_rate = p_block->i_rate;
Laurent Aimar's avatar
Laurent Aimar committed
616
617
618
619
620
621
622
623
    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 );

624
        if( p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
Laurent Aimar's avatar
Laurent Aimar committed
625
626
627
        {
            aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
                                  p_dec->p_owner->p_aout_input, p_aout_buf );
628
            continue;
Laurent Aimar's avatar
Laurent Aimar committed
629
        }
630
631

        if( p_dec->p_owner->i_preroll_end > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
632
        {
633
634
            /* 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
635
636
            p_dec->p_owner->i_preroll_end = -1;
        }
637
638
        aout_DecPlay( p_dec->p_owner->p_aout,
                      p_dec->p_owner->p_aout_input,
639
                      p_aout_buf, i_rate );
Laurent Aimar's avatar
Laurent Aimar committed
640
641
    }
}
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
{
    block_t *p_cc;
    vlc_bool_t pb_present[4];
    int i;
    int i_cc_decoder;

    assert( p_dec_cc->pf_get_cc != NULL );

    /* Do not try retreiving CC if not wanted (sout) or cannot be retreived */
    if( !p_dec->p_owner->b_cc_supported )
        return;

    p_cc = p_dec_cc->pf_get_cc( p_dec_cc, pb_present );
    if( !p_cc )
        return;

    vlc_mutex_lock( &p_dec->p_owner->lock_cc );
    for( i = 0, i_cc_decoder = 0; i < 4; i++ )
    {
        p_dec->p_owner->pb_cc_present[i] |= pb_present[i];
        if( p_dec->p_owner->pp_cc[i] )
            i_cc_decoder++;
    }

    for( i = 0; i < 4; i++ )
    {
        if( !p_dec->p_owner->pp_cc[i] )
            continue;

        if( i_cc_decoder > 1 )
            DecoderDecode( p_dec->p_owner->pp_cc[i], block_Duplicate( p_cc ) );
        else
            DecoderDecode( p_dec->p_owner->pp_cc[i], p_cc );
        i_cc_decoder--;
    }
    vlc_mutex_unlock( &p_dec->p_owner->lock_cc );
}
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
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];

709
710
        if( p_pic->i_status == READY_PICTURE ||
            p_pic->i_status == DISPLAYED_PICTURE )
711
712
713
714
715
716
717
718
        {
            /* 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
719
720
721
722
723
724
725
726
727
728
729
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 );

730
        if( p_pic->date < p_dec->p_owner->i_preroll_end )
Laurent Aimar's avatar
Laurent Aimar committed
731
        {
732
733
            VoutDisplayedPicture( p_dec->p_owner->p_vout, p_pic );
            continue;
Laurent Aimar's avatar
Laurent Aimar committed
734
        }
735
736

        if( p_dec->p_owner->i_preroll_end > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
737
        {
738
739
740
741
            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
742
743
            p_dec->p_owner->i_preroll_end = -1;
        }
744

745
746
747
        if( ( !p_dec->p_owner->p_packetizer || !p_dec->p_owner->p_packetizer->pf_get_cc ) && p_dec->pf_get_cc )
            DecoderGetCc( p_dec, p_dec );

748
749
750
        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
751
752
753
    }
}

754
755
756
757
758
759
760
/**
 * Decode a block
 *
 * \param p_dec the decoder object
 * \param p_block the block to decode
 * \return VLC_SUCCESS or an error code
 */
761
762
static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
{
Laurent Aimar's avatar
Laurent Aimar committed
763
    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
764
    const int i_rate = p_block ? p_block->i_rate : INPUT_RATE_DEFAULT;
765

766
    if( p_block && p_block->i_buffer <= 0 )
767
768
769
770
771
772
773
774
775
    {
        block_Release( p_block );
        return VLC_SUCCESS;
    }

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

776
777
        while( ( p_sout_block =
                     p_dec->pf_packetize( p_dec, p_block ? &p_block : 0 ) ) )
778
        {
779
            if( !p_dec->p_owner->p_sout_input )
780
781
            {
                es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out );
Laurent Aimar's avatar
Laurent Aimar committed
782

783
                p_dec->p_owner->sout.i_group = p_dec->fmt_in.i_group;
Laurent Aimar's avatar
Laurent Aimar committed
784
                p_dec->p_owner->sout.i_id = p_dec->fmt_in.i_id;
785
786
                if( p_dec->fmt_in.psz_language )
                {
787
788
                    if( p_dec->p_owner->sout.psz_language )
                        free( p_dec->p_owner->sout.psz_language );
789
790
                    p_dec->p_owner->sout.psz_language =
                        strdup( p_dec->fmt_in.psz_language );
791
                }
gbazin's avatar
   
gbazin committed
792

793
                p_dec->p_owner->p_sout_input =
794
795
                    sout_InputNew( p_dec->p_owner->p_sout,
                                   &p_dec->p_owner->sout );
796

797
                if( p_dec->p_owner->p_sout_input == NULL )
gbazin's avatar
   
gbazin committed
798
                {
799
800
                    msg_Err( p_dec, "cannot create packetizer output (%4.4s)",
                             (char *)&p_dec->p_owner->sout.i_codec );
801
                    p_dec->b_error = VLC_TRUE;
gbazin's avatar
   
gbazin committed
802

803
                    while( p_sout_block )
804
                    {
805
                        block_t *p_next = p_sout_block->p_next;
806
807
                        block_Release( p_sout_block );
                        p_sout_block = p_next;
808
                    }
809
810
811
                    break;
                }
            }
gbazin's avatar
   
gbazin committed
812

813
814
            while( p_sout_block )
            {
815
                block_t *p_next = p_sout_block->p_next;
gbazin's avatar
   
gbazin committed
816

817
                p_sout_block->p_next = NULL;
818
                p_sout_block->i_rate = i_rate;
gbazin's avatar
   
gbazin committed
819

820
                sout_InputSendBuffer( p_dec->p_owner->p_sout_input,
821
                                      p_sout_block );
gbazin's avatar
   
gbazin committed
822

823
                p_sout_block = p_next;
gbazin's avatar
   
gbazin committed
824
            }
825
826
827

            /* 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
828
                p_dec->p_owner->p_input->p->b_out_pace_control )
829
            {
830
                msg_Dbg( p_dec, "switching to sync mode" );
zorglub's avatar
zorglub committed
831
                p_dec->p_owner->p_input->p->b_out_pace_control = VLC_FALSE;
832
833
            }
            else if( p_dec->p_owner->p_sout->i_out_pace_nocontrol <= 0 &&
zorglub's avatar
zorglub committed
834
                     !p_dec->p_owner->p_input->p->b_out_pace_control )
835
            {
836
                msg_Dbg( p_dec, "switching to async mode" );
zorglub's avatar
zorglub committed
837
                p_dec->p_owner->p_input->p->b_out_pace_control = VLC_TRUE;
838
            }
gbazin's avatar
   
gbazin committed
839
        }
840
841
842
    }
    else if( p_dec->fmt_in.i_cat == AUDIO_ES )
    {
843
844
        if( p_block )
            DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
845

846
847
848
849
850
851
        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 =
852
                    p_packetizer->pf_packetize( p_packetizer, p_block ? &p_block : NULL )) )
853
            {
854
855
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
856
857
                    es_format_Clean( &p_dec->fmt_in );
                    es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out );
858
859
                }

860
                while( p_packetized_block )
861
                {
862
863
                    block_t *p_next = p_packetized_block->p_next;
                    p_packetized_block->p_next = NULL;
864
                    p_packetized_block->i_rate = i_rate;
865

Laurent Aimar's avatar
Laurent Aimar committed
866
                    DecoderDecodeAudio( p_dec, p_packetized_block );
867
868

                    p_packetized_block = p_next;
869
870
871
                }
            }
        }
872
        else if( p_block )
873
        {
Laurent Aimar's avatar
Laurent Aimar committed
874
            DecoderDecodeAudio( p_dec, p_block );
875
        }
gbazin's avatar
   
gbazin committed
876
    }
877
    else if( p_dec->fmt_in.i_cat == VIDEO_ES )
878
    {
879
880
        if( p_block )
            DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
881

882
883
884
885
886
887
        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 =
888
                    p_packetizer->pf_packetize( p_packetizer, p_block ? &p_block : NULL )) )
889
            {
890
891
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
892
893
                    es_format_Clean( &p_dec->fmt_in );
                    es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out );
894
                }
895
896
                if( p_packetizer->pf_get_cc )
                    DecoderGetCc( p_dec, p_packetizer );
897

898
                while( p_packetized_block )
899
                {
900
901
                    block_t *p_next = p_packetized_block->p_next;
                    p_packetized_block->p_next = NULL;
902
                    p_packetized_block->i_rate = i_rate;
903

Laurent Aimar's avatar
Laurent Aimar committed
904
                    DecoderDecodeVideo( p_dec, p_packetized_block );
905
906

                    p_packetized_block = p_next;
907
908
909
                }
            }
        }
910
        else if( p_block )
911
        {
Laurent Aimar's avatar
Laurent Aimar committed
912
            DecoderDecodeVideo( p_dec, p_block );
913
        }
914
    }
915
916
    else if( p_dec->fmt_in.i_cat == SPU_ES )
    {
Laurent Aimar's avatar
Laurent Aimar committed
917
        input_thread_t *p_input = p_dec->p_owner->p_input;
918
919
        vout_thread_t *p_vout;
        subpicture_t *p_spu;
920

921
922
        if( p_block )
            DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
923

924
        while( (p_spu = p_dec->pf_decode_sub( p_dec, p_block ? &p_block : NULL ) ) )
925
        {
Laurent Aimar's avatar
Laurent Aimar committed
926
927
928
            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 );
929

Laurent Aimar's avatar
Laurent Aimar committed
930
931
            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
932
            {
Laurent Aimar's avatar
Laurent Aimar committed
933
934
935
936
937
938
                /* 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
939
            }
Laurent Aimar's avatar
Laurent Aimar committed
940
            else
941
            {
Laurent Aimar's avatar
Laurent Aimar committed
942
                msg_Warn( p_dec, "no vout found, leaking subpicture" );
943
            }
Laurent Aimar's avatar
Laurent Aimar committed
944
945
            if( p_vout )
                vlc_object_release( p_vout );
946
        }
947
948
949
    }
    else
    {
zorglub's avatar
zorglub committed
950
        msg_Err( p_dec, "unknown ES format" );
951
952
        p_dec->b_error = 1;
    }
953

954
    return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS;
Sam Hocevar's avatar
   
Sam Hocevar committed
955
956
}

zorglub's avatar
zorglub committed
957
958
959
960
961
962
/**
 * Destroys a decoder object
 *
 * \param p_dec the decoder object
 * \return nothing
 */
gbazin's avatar
   
gbazin committed
963
static void DeleteDecoder( decoder_t * p_dec )
Sam Hocevar's avatar
   
Sam Hocevar committed
964
{
965
    msg_Dbg( p_dec, "killing decoder fourcc `%4.4s', %u PES in FIFO",
966
             (char*)&p_dec->fmt_in.i_codec,
967
             (unsigned)block_FifoCount( p_dec->p_owner->p_fifo ) );
968

Sam Hocevar's avatar
   
Sam Hocevar committed
969
    /* Free all packets still in the decoder fifo. */
970
971
    block_FifoEmpty( p_dec->p_owner->p_fifo );
    block_FifoRelease( p_dec->p_owner->p_fifo );
Sam Hocevar's avatar
   
Sam Hocevar committed
972

973
    /* Cleanup */
gbazin's avatar
   
gbazin committed
974
975
976
977
978
979
980
    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
981
#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
gbazin's avatar
   
gbazin committed
982
983
984
985
        /* 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
986
987
988
989
            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
990
        }
gbazin's avatar
   
gbazin committed
991
#undef p_pic
gbazin's avatar
   
gbazin committed
992
993

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

997
    if( p_dec->p_owner->p_sout_input )
gbazin's avatar
   
gbazin committed
998
    {
999
        sout_InputDelete( p_dec->p_owner->p_sout_input );
1000
        es_format_Clean( &p_dec->p_owner->sout );
gbazin's avatar
   
gbazin committed
1001
1002
    }

1003
1004
1005
1006
1007
1008
1009
    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 )
        {
1010
1011
            spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR,
                         p_dec->p_owner->i_spu_channel );
1012
1013
1014
1015
            vlc_object_release( p_vout );
        }
    }

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
    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
1028

1029
1030
    vlc_mutex_destroy( &p_dec->p_owner->lock_cc );

1031
1032
    vlc_object_detach( p_dec );

gbazin's avatar
   
gbazin committed
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
    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 )
    {
1058
1059
1060
        audio_sample_format_t format;
        int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" );

gbazin's avatar
   
gbazin committed
1061
1062
        p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
        p_sys->audio = p_dec->fmt_out.audio;
1063
1064
1065
1066
1067

        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) )
        {
1068
            if ( i_force_dolby == 1 )
1069
1070
1071
1072
            {
                format.i_original_channels = format.i_original_channels |
                                             AOUT_CHAN_DOLBYSTEREO;
            }
1073
            else /* i_force_dolby == 2 */
1074
1075
1076
1077
1078
1079
            {
                format.i_original_channels = format.i_original_channels &
                                             ~AOUT_CHAN_DOLBYSTEREO;
            }
        }

gbazin's avatar
   
gbazin committed
1080
        p_sys->p_aout_input =
1081
            aout_DecNew( p_dec, &p_sys->p_aout, &format, &p_dec->fmt_out.audio_replay_gain );
gbazin's avatar
   
gbazin committed
1082
1083
1084
        if( p_sys->p_aout_input == NULL )
        {
            msg_Err( p_dec, "failed to create audio output" );
gbazin's avatar
   
gbazin committed
1085
            p_dec->b_error = VLC_TRUE;
gbazin's avatar
   
gbazin committed
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
            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;
        }

1122
1123
1124
        if( !p_dec->fmt_out.video.i_visible_width ||
            !p_dec->fmt_out.video.i_visible_height )
        {
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
            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;