decoder.c 36.7 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

gbazin's avatar
   
gbazin committed
32
#include <vlc/decoder.h>
gbazin's avatar
   
gbazin committed
33
#include <vlc/vout.h>
Laurent Aimar's avatar
Laurent Aimar committed
34
#include <vlc/input.h>
35
#include <vlc_interaction.h>
gbazin's avatar
   
gbazin committed
36
37

#include "stream_output.h"
Laurent Aimar's avatar
Laurent Aimar committed
38
#include "input_internal.h"
39

Laurent Aimar's avatar
Laurent Aimar committed
40
41
static decoder_t * CreateDecoder( input_thread_t *, es_format_t *, int );
static void        DeleteDecoder( decoder_t * );
42

gbazin's avatar
   
gbazin committed
43
static int         DecoderThread( decoder_t * );
44
static int         DecoderDecode( decoder_t * p_dec, block_t *p_block );
Sam Hocevar's avatar
   
Sam Hocevar committed
45

gbazin's avatar
   
gbazin committed
46
47
48
49
50
51
/* 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
52
53
static void vout_link_picture( decoder_t *, picture_t * );
static void vout_unlink_picture( decoder_t *, picture_t * );
gbazin's avatar
   
gbazin committed
54

55
56
57
static subpicture_t *spu_new_buffer( decoder_t * );
static void spu_del_buffer( decoder_t *, subpicture_t * );

gbazin's avatar
   
gbazin committed
58
59
static es_format_t null_es_format = {0};

60
61
struct decoder_owner_sys_t
{
62
63
    vlc_bool_t      b_own_thread;

Laurent Aimar's avatar
Laurent Aimar committed
64
65
    int64_t         i_preroll_end;

66
67
    input_thread_t  *p_input;

68
69
70
71
72
    aout_instance_t *p_aout;
    aout_input_t    *p_aout_input;

    vout_thread_t   *p_vout;

73
74
75
    vout_thread_t   *p_spu_vout;
    int              i_spu_channel;

76
77
    sout_instance_t         *p_sout;
    sout_packetizer_input_t *p_sout_input;
78

79
80
81
    /* Some decoders require already packetized data (ie. not truncated) */
    decoder_t *p_packetizer;

82
83
84
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;
};


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

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

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

        DeleteDecoder( p_dec );
        vlc_object_destroy( p_dec );
143
        return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
144
145
    }

Laurent Aimar's avatar
Laurent Aimar committed
146
147
    if( p_input->p_sout && p_input->input.b_can_pace_control &&
        !b_force_decoder )
148
149
150
151
152
153
154
155
156
    {
        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;
    }
157

158
    if( p_dec->p_owner->b_own_thread )
Henri Fallon's avatar
   
Henri Fallon committed
159
    {
160
        int i_priority;
Laurent Aimar's avatar
Laurent Aimar committed
161
        if( fmt->i_cat == AUDIO_ES )
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
            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
177
178
    }

179
    return p_dec;
180
181
}

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

193
    if( p_dec->p_owner->b_own_thread )
194
    {
195
196
197
        /* 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
198
        input_DecoderDecode( p_dec, p_block );
199

200
        vlc_thread_join( p_dec );
201
202
203

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

210
211
        module_Unneed( p_dec, p_dec->p_module );
    }
212

gbazin's avatar
   
gbazin committed
213
214
215
216
217
    /* Delete decoder configuration */
    DeleteDecoder( p_dec );

    /* Delete the decoder */
    vlc_object_destroy( p_dec );
218
}
zorglub's avatar
zorglub committed
219
220

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

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

Laurent Aimar's avatar
Laurent Aimar committed
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
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
281
282
283
284
285
286
287
288
289
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
290
291
292
293
294
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
295
#if 0
zorglub's avatar
zorglub committed
296
/**
297
 * Create a NULL packet for padding in case of a data loss
zorglub's avatar
zorglub committed
298
299
300
301
302
 *
 * \param p_input the input thread
 * \param p_es es descriptor
 * \return nothing
 */
303
304
static void input_NullPacket( input_thread_t * p_input,
                              es_descriptor_t * p_es )
305
{
Laurent Aimar's avatar
Laurent Aimar committed
306
#if 0
307
308
    block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
    if( p_block )
309
    {
310
        memset( p_block->p_buffer, 0, PADDING_PACKET_SIZE );
gbazin's avatar
   
gbazin committed
311
        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
312

313
        block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block );
314
    }
Laurent Aimar's avatar
Laurent Aimar committed
315
#endif
316
317
}

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

329
    for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
330
    {
331
        es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
332

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

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

355
    for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
356
    {
357
        es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
358

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

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

gbazin's avatar
   
gbazin committed
384
    p_dec = vlc_object_create( p_input, i_object_type );
gbazin's avatar
   
gbazin committed
385
    if( p_dec == NULL )
Sam Hocevar's avatar
   
Sam Hocevar committed
386
    {
387
        msg_Err( p_input, "out of memory" );
Sam Hocevar's avatar
   
Sam Hocevar committed
388
389
390
        return NULL;
    }

gbazin's avatar
   
gbazin committed
391
392
393
394
    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
395

zorglub's avatar
zorglub committed
396
   /* Initialize the decoder fifo */
gbazin's avatar
   
gbazin committed
397
398
    p_dec->p_module = NULL;

gbazin's avatar
   
gbazin committed
399

Laurent Aimar's avatar
Laurent Aimar committed
400
401
    es_format_Copy( &p_dec->fmt_in, fmt );
    es_format_Copy( &p_dec->fmt_out, &null_es_format );
gbazin's avatar
   
gbazin committed
402
403

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

422
423
424
425
426
427
    /* decoder fifo */
    if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return NULL;
    }
428

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

gbazin's avatar
   
gbazin committed
439
440
    vlc_object_attach( p_dec, p_input );

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

461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
            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
476
477
478
    return p_dec;
}

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

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

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

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

514
515
    return 0;
}
gbazin's avatar
   
gbazin committed
516

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

528
    if( p_block && p_block->i_buffer <= 0 )
529
530
531
532
533
534
535
536
537
    {
        block_Release( p_block );
        return VLC_SUCCESS;
    }

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

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

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

555
                p_dec->p_owner->p_sout_input =
556
557
                    sout_InputNew( p_dec->p_owner->p_sout,
                                   &p_dec->p_owner->sout );
558

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

565
                    while( p_sout_block )
566
                    {
567
                        block_t *p_next = p_sout_block->p_next;
568
569
                        block_Release( p_sout_block );
                        p_sout_block = p_next;
570
                    }
571
572
573
                    break;
                }
            }
gbazin's avatar
   
gbazin committed
574

575
576
            while( p_sout_block )
            {
577
                block_t *p_next = p_sout_block->p_next;
gbazin's avatar
   
gbazin committed
578

579
                p_sout_block->p_next = NULL;
580
                p_sout_block->i_rate = i_rate;
gbazin's avatar
   
gbazin committed
581

582
                sout_InputSendBuffer( p_dec->p_owner->p_sout_input,
583
                                      p_sout_block );
gbazin's avatar
   
gbazin committed
584

585
                p_sout_block = p_next;
gbazin's avatar
   
gbazin committed
586
            }
587
588
589
590
591
592
593
594
595
596
597
598
599
600

            /* For now it's enough, as only sout inpact on this flag */
            if( p_dec->p_owner->p_sout->i_out_pace_nocontrol > 0 &&
                p_dec->p_owner->p_input->b_out_pace_control )
            {
                msg_Dbg( p_dec, "switching to synch mode" );
                p_dec->p_owner->p_input->b_out_pace_control = VLC_FALSE;
            }
            else if( p_dec->p_owner->p_sout->i_out_pace_nocontrol <= 0 &&
                     !p_dec->p_owner->p_input->b_out_pace_control )
            {
                msg_Dbg( p_dec, "switching to asynch mode" );
                p_dec->p_owner->p_input->b_out_pace_control = VLC_TRUE;
            }
gbazin's avatar
   
gbazin committed
601
        }
602
603
604
605
606
    }
    else if( p_dec->fmt_in.i_cat == AUDIO_ES )
    {
        aout_buffer_t *p_aout_buf;

607
608
609
610
611
612
613
614
        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 )) )
            {
615
616
617
618
619
620
621
622
623
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
                    p_dec->fmt_in.i_extra = p_packetizer->fmt_out.i_extra;
                    p_dec->fmt_in.p_extra = malloc( p_dec->fmt_in.i_extra );
                    memcpy( p_dec->fmt_in.p_extra,
                            p_packetizer->fmt_out.p_extra,
                            p_dec->fmt_in.i_extra );
                }

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

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

                        /* FIXME the best would be to handle the case
                         * start_date < preroll < end_date
Laurent Aimar's avatar
Laurent Aimar committed
641
642
643
644
645
646
647
648
649
650
651
652
653
654
                         * 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 );
                        }
655
656
657
                    }

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

Laurent Aimar's avatar
Laurent Aimar committed
669
670
671
672
673
674
675
676
677
678
679
680
681
            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 );
            }
682
        }
gbazin's avatar
   
gbazin committed
683
    }
684
    else if( p_dec->fmt_in.i_cat == VIDEO_ES )
685
    {
686
687
        picture_t *p_pic;

688
689
690
691
692
693
694
695
        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 )) )
            {
696
697
698
699
700
701
702
703
704
                if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra )
                {
                    p_dec->fmt_in.i_extra = p_packetizer->fmt_out.i_extra;
                    p_dec->fmt_in.p_extra = malloc( p_dec->fmt_in.i_extra );
                    memcpy( p_dec->fmt_in.p_extra,
                            p_packetizer->fmt_out.p_extra,
                            p_dec->fmt_in.i_extra );
                }

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

                    while( (p_pic = p_dec->pf_decode_video( p_dec,
                                                       &p_packetized_block )) )
                    {
714
715
716
717
718
719
                        input_thread_t *p_i =(input_thread_t*)(p_dec->p_parent);
                        vlc_mutex_lock( &p_i->counters.counters_lock );
                        stats_UpdateInteger( p_dec,
                               p_i->counters.p_decoded_video, 1, NULL );
                        vlc_mutex_unlock( &p_i->counters.counters_lock );

Laurent Aimar's avatar
Laurent Aimar committed
720
721
722
723
724
725
726
727
728
729
730
731
                        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 );
                        }
732
733
734
                    }

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

Laurent Aimar's avatar
Laurent Aimar committed
746
747
748
749
750
751
752
753
754
755
756
            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 );
            }
757
        }
758
    }
759
760
    else if( p_dec->fmt_in.i_cat == SPU_ES )
    {
761
762
763
764
        vout_thread_t *p_vout;
        subpicture_t *p_spu;
        while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) )
        {
765
766
767
768
769
770
            input_thread_t *p_i = (input_thread_t*)(p_dec->p_parent);
            vlc_mutex_lock( &p_i->counters.counters_lock );
            stats_UpdateInteger( p_dec,
                               p_i->counters.p_decoded_sub, 1, NULL );
            vlc_mutex_unlock( &p_i->counters.counters_lock );

Laurent Aimar's avatar
Laurent Aimar committed
771
772
773
774
775
776
777
778
779
            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;
780
781
782
            p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
            if( p_vout )
            {
783
                spu_DisplaySubpicture( p_vout->p_spu, p_spu );
784
785
786
                vlc_object_release( p_vout );
            }
        }
787
788
789
    }
    else
    {
zorglub's avatar
zorglub committed
790
        msg_Err( p_dec, "unknown ES format" );
791
792
        p_dec->b_error = 1;
    }
793

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

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

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

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

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

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

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

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

869
870
    vlc_object_detach( p_dec );

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

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

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

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

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

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

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

            p_dec->fmt_out.video.i_sar_den = VOUT_ASPECT_FACTOR *
996
              p_dec->fmt_out.video.i_visible_width;
997
998
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
999
1000
        vlc_ureduce( &p_dec->fmt_out.video.i_sar_num,
                     &p_dec->fmt_out.video.i_sar_den,