mpeg_system.c 58 KB
Newer Older
1
2
3
/*****************************************************************************
 * mpeg_system.c: TS, PS and PES management
 *****************************************************************************
4
 * Copyright (C) 1998-2001 VideoLAN
5
 * $Id: mpeg_system.c,v 1.71 2001/12/11 13:55:55 massiot Exp $
6
 *
7
8
9
10
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *          Michel Lespinasse <walken@via.ecp.fr>
 *          Benot Steiner <benny@via.ecp.fr>
 *          Samuel Hocevar <sam@via.ecp.fr>
Henri Fallon's avatar
   
Henri Fallon committed
11
 *          Henri Fallon <henri@via.ecp.fr>
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 *
 * 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.
 * 
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include "defs.h"

#include <stdlib.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
34
#include <string.h>                                    /* memcpy(), memset() */
Sam Hocevar's avatar
   
Sam Hocevar committed
35
#include <sys/types.h>                                              /* off_t */
36
37

#include "common.h"
38
#include "intf_msg.h"
39
40
41
42
43
44
#include "threads.h"
#include "mtime.h"

#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
45
#include "input_ext-plugins.h"
46
47
48
49
50

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

Henri Fallon's avatar
   
Henri Fallon committed
51
52
static void input_DecodePAT( input_thread_t *, es_descriptor_t *);
static void input_DecodePMT( input_thread_t *, es_descriptor_t *);
53
54
55
56
57

/*
 * PES Packet management
 */

58
59
60
61
62
/*****************************************************************************
 * MoveChunk
 *****************************************************************************
 * Small utility function used to parse discontinuous headers safely. Copies
 * i_buf_len bytes of data to a buffer and returns the size copied.
63
 * It also solves some alignment problems on non-IA-32, non-PPC processors.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
 * This is a variation on the theme of input_ext-dec.h:GetChunk().
 *****************************************************************************/
static __inline__ size_t MoveChunk( byte_t * p_dest,
                                    data_packet_t ** pp_data_src,
                                    byte_t ** pp_src,
                                    size_t i_buf_len )
{
    ptrdiff_t           i_available;

    if( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
            >= i_buf_len )
    {
        if( p_dest != NULL )
            memcpy( p_dest, *pp_src, i_buf_len );
        *pp_src += i_buf_len;
        return( i_buf_len );
    }
    else
    {
        size_t          i_init_len = i_buf_len;

        do
        {
            if( p_dest != NULL )
                memcpy( p_dest, *pp_src, i_available );
            *pp_data_src = (*pp_data_src)->p_next;
            i_buf_len -= i_available;
            p_dest += i_available;
            if( *pp_data_src == NULL )
            {
                *pp_src = NULL;
                return( i_init_len - i_buf_len );
            }
            *pp_src = (*pp_data_src)->p_payload_start;
        }
        while( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
                <= i_buf_len );

        if( i_buf_len )
        {
            if( p_dest != NULL )
                memcpy( p_dest, *pp_src, i_buf_len );
            *pp_src += i_buf_len;
        }
        return( i_init_len );
    }
}

112
113
114
115
116
/*****************************************************************************
 * input_ParsePES
 *****************************************************************************
 * Parse a finished PES packet and analyze its header.
 *****************************************************************************/
117
#define PES_HEADER_SIZE     7
118
119
void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
120
121
    data_packet_t * p_data;
    byte_t *        p_byte;
122
    byte_t          p_header[PES_HEADER_SIZE];
123
    int             i_done;
124
125
126

#define p_pes (p_es->p_pes)

Sam Hocevar's avatar
   
Sam Hocevar committed
127
    //intf_DbgMsg("End of PES packet %p", p_pes);
128
129
130
131

    /* Parse the header. The header has a variable length, but in order
     * to improve the algorithm, we will read the 14 bytes we may be
     * interested in */
132
133
    p_data = p_pes->p_first;
    p_byte = p_data->p_payload_start;
134
135
    i_done = 0;

136
137
    if( MoveChunk( p_header, &p_data, &p_byte, PES_HEADER_SIZE )
            != PES_HEADER_SIZE )
138
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
139
        intf_WarnMsg( 1, "input: PES packet too short to have a header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
140
        p_input->pf_delete_pes( p_input->p_method_data, p_pes );
141
142
143
144
145
        p_pes = NULL;
        return;
    }

    /* Get the PES size if defined */
146
147
    p_es->i_pes_real_size = U16_AT(p_header + 4);
    if( p_es->i_pes_real_size )
148
    {
149
        p_es->i_pes_real_size += 6;
150
    }
151
152
153
154
155
156

    /* First read the 6 header bytes common to all PES packets:
     * use them to test the PES validity */
    if( (p_header[0] || p_header[1] || (p_header[2] != 1)) )
    {
        /* packet_start_code_prefix != 0x000001 */
Sam Hocevar's avatar
   
Sam Hocevar committed
157
158
        intf_ErrMsg( "input error: data loss, "
                     "PES packet doesn't start with 0x000001" );
Sam Hocevar's avatar
   
Sam Hocevar committed
159
        p_input->pf_delete_pes( p_input->p_method_data, p_pes );
160
161
162
163
164
165
166
167
168
169
170
        p_pes = NULL;
    }
    else
    {
        int i_pes_header_size, i_payload_size;

        if ( p_es->i_pes_real_size &&
             (p_es->i_pes_real_size != p_pes->i_pes_size) )
        {
            /* PES_packet_length is set and != total received payload */
            /* Warn the decoder that the data may be corrupt. */
Sam Hocevar's avatar
   
Sam Hocevar committed
171
172
            intf_WarnMsg( 1, "input: packet corrupted, "
                             "PES sizes do not match" );
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
        }

        switch( p_es->i_stream_id )
        {
        case 0xBC:  /* Program stream map */
        case 0xBE:  /* Padding */
        case 0xBF:  /* Private stream 2 */
        case 0xB0:  /* ECM */
        case 0xB1:  /* EMM */
        case 0xFF:  /* Program stream directory */
        case 0xF2:  /* DSMCC stream */
        case 0xF8:  /* ITU-T H.222.1 type E stream */
            /* The payload begins immediately after the 6 bytes header, so
             * we have finished with the parsing */
            i_pes_header_size = 6;
            break;

        default:
191
192
193
            if( (p_header[6] & 0xC0) == 0x80 )
            {
                /* MPEG-2 : the PES header contains at least 3 more bytes. */
194
                size_t      i_max_len;
195
196
                boolean_t   b_has_pts, b_has_dts;
                byte_t      p_full_header[12];
197

198
199
                p_pes->b_data_alignment = p_header[6] & 0x04;

200
                i_max_len = MoveChunk( p_full_header, &p_data, &p_byte, 12 );
201
202
                if( i_max_len < 2 )
                {
203
                    intf_WarnMsg( 1,
204
                            "PES packet too short to have a MPEG-2 header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
205
206
                    p_input->pf_delete_pes( p_input->p_method_data,
                                            p_pes );
207
208
209
210
                    p_pes = NULL;
                    return;
                }

211
212
213
                b_has_pts = p_full_header[0] & 0x80;
                b_has_dts = p_full_header[0] & 0x40;
                i_pes_header_size = p_full_header[1] + 9;
214
215

                /* Now parse the optional header extensions */
216
                if( b_has_pts )
217
                {
218
219
                    if( i_max_len < 7 )
                    {
220
                        intf_WarnMsg( 1,
221
                            "PES packet too short to have a MPEG-2 header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
222
223
                        p_input->pf_delete_pes( p_input->p_method_data,
                                                p_pes );
224
225
226
                        p_pes = NULL;
                        return;
                    }
227
                    p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
228
                    ( ((mtime_t)(p_full_header[2] & 0x0E) << 29) |
229
230
                      ((mtime_t)(p_full_header[3]) << 22) |
                      ((mtime_t)(p_full_header[4] & 0xFE) << 14) |
231
232
                      ((mtime_t)p_full_header[5] << 7) |
                      ((mtime_t)p_full_header[6] >> 1) ) );
233
234
235
236
237

                    if( b_has_dts )
                    {
                        if( i_max_len < 12 )
                        {
238
                            intf_WarnMsg( 1,
239
                              "PES packet too short to have a MPEG-2 header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
240
241
                            p_input->pf_delete_pes( p_input->p_method_data,
                                                    p_pes );
242
243
244
                            p_pes = NULL;
                            return;
                        }
245
                        p_pes->i_dts = input_ClockGetTS( p_input, p_es->p_pgrm,
246
                        ( ((mtime_t)(p_full_header[7] & 0x0E) << 29) |
247
                          (((mtime_t)U16_AT(p_full_header + 8) << 14)
248
                                - (1 << 14)) |
249
                          ((mtime_t)U16_AT(p_full_header + 10) >> 1) ) );
250
                    }
251
252
253
254
255
                }
            }
            else
            {
                /* Probably MPEG-1 */
256
257
                boolean_t       b_has_pts, b_has_dts;

258
259
                i_pes_header_size = 6;
                p_data = p_pes->p_first;
260
261
262
263
                p_byte = p_data->p_payload_start;
                /* Cannot fail because the previous one succeeded. */
                MoveChunk( NULL, &p_data, &p_byte, 6 );

264
                while( *p_byte == 0xFF && i_pes_header_size < 23 )
265
266
                {
                    i_pes_header_size++;
267
                    if( MoveChunk( NULL, &p_data, &p_byte, 1 ) != 1 )
268
                    {
269
                        intf_WarnMsg( 1,
270
                            "PES packet too short to have a MPEG-1 header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
271
                        p_input->pf_delete_pes( p_input->p_method_data, p_pes );
272
273
                        p_pes = NULL;
                        return;
274
275
                    }
                }
276
                if( i_pes_header_size == 23 )
277
                {
Sam Hocevar's avatar
   
Sam Hocevar committed
278
                    intf_ErrMsg( "input error: too much MPEG-1 stuffing" );
Sam Hocevar's avatar
   
Sam Hocevar committed
279
                    p_input->pf_delete_pes( p_input->p_method_data, p_pes );
280
281
282
283
284
285
286
                    p_pes = NULL;
                    return;
                }

                if( (*p_byte & 0xC0) == 0x40 )
                {
                    /* Don't ask why... --Meuuh */
Sam Hocevar's avatar
   
Sam Hocevar committed
287
                    /* Erm... why ? --Sam */
288
289
                    /* Well... According to the recommendation, it is for
                     * STD_buffer_scale and STD_buffer_size. --Meuuh */
290
                    i_pes_header_size += 2;
291
                    if( MoveChunk( NULL, &p_data, &p_byte, 2 ) != 2 )
292
                    {
Sam Hocevar's avatar
   
Sam Hocevar committed
293
294
                        intf_WarnMsg( 1, "input: PES packet too short "
                                         "to have a MPEG-1 header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
295
                        p_input->pf_delete_pes( p_input->p_method_data, p_pes );
296
297
                        p_pes = NULL;
                        return;
298
299
300
301
302
                    }
                }

                i_pes_header_size++;

303
304
305
306
                b_has_pts = *p_byte & 0x20;
                b_has_dts = *p_byte & 0x10;

                if( b_has_pts )
307
                {
308
                    byte_t      p_ts[5];
309
310

                    i_pes_header_size += 4;
311
                    if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
312
                    {
Sam Hocevar's avatar
   
Sam Hocevar committed
313
314
                        intf_WarnMsg( 1, "input: PES packet too short "
                                         "to have a MPEG-1 header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
315
                        p_input->pf_delete_pes( p_input->p_method_data, p_pes );
316
317
                        p_pes = NULL;
                        return;
318
                    }
319

320
                    p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
321
322
323
324
                       ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
                         (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
                         ((mtime_t)p_ts[3] << 7) |
                         ((mtime_t)p_ts[4] >> 1) ) );
325
326
327
328
329
330

                    if( b_has_dts )
                    {
                        i_pes_header_size += 5;
                        if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
                        {
Sam Hocevar's avatar
   
Sam Hocevar committed
331
332
                            intf_WarnMsg( 1, "input: PES packet too short "
                                             "to have a MPEG-1 header" );
Sam Hocevar's avatar
   
Sam Hocevar committed
333
334
                            p_input->pf_delete_pes( p_input->p_method_data,
                                                    p_pes );
335
336
337
338
                            p_pes = NULL;
                            return;
                        }

339
340
                        p_pes->i_dts = input_ClockGetTS( p_input,
                                                         p_es->p_pgrm,
341
                            ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
342
343
344
                              (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
                              ((mtime_t)p_ts[3] << 7) |
                              ((mtime_t)p_ts[4] >> 1) ) );
345
                    }
346
347
348
                }
            }

349
350
351
            break;
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
352
        if( p_es->i_stream_id == 0xbd )
353
354
355
356
357
358
        {
            /* With private stream 1, the first byte of the payload
             * is a stream_private_id, so skip it. */
            i_pes_header_size++;
        }

359
360
361
362
        /* Now we've parsed the header, we just have to indicate in some
         * specific data packets where the PES payload begins (renumber
         * p_payload_start), so that the decoders can find the beginning
         * of their data right out of the box. */
363
364
365
        p_data = p_pes->p_first;
        i_payload_size = p_data->p_payload_end
                                 - p_data->p_payload_start;
366
367
368
369
        while( i_pes_header_size > i_payload_size )
        {
            /* These packets are entirely filled by the PES header. */
            i_pes_header_size -= i_payload_size;
370
            p_data->p_payload_start = p_data->p_payload_end;
371
            /* Go to the next data packet. */
372
            if( (p_data = p_data->p_next) == NULL )
373
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
374
                intf_ErrMsg( "input error: PES header bigger than payload" );
Sam Hocevar's avatar
   
Sam Hocevar committed
375
                p_input->pf_delete_pes( p_input->p_method_data, p_pes );
376
377
378
                p_pes = NULL;
                return;
            }
379
380
            i_payload_size = p_data->p_payload_end
                                 - p_data->p_payload_start;
381
382
383
384
        }
        /* This last packet is partly header, partly payload. */
        if( i_payload_size < i_pes_header_size )
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
385
            intf_ErrMsg( "input error: PES header bigger than payload" );
Sam Hocevar's avatar
   
Sam Hocevar committed
386
            p_input->pf_delete_pes( p_input->p_method_data, p_pes );
387
388
389
            p_pes = NULL;
            return;
        }
390
        p_data->p_payload_start += i_pes_header_size;
391
392
393

        /* Now we can eventually put the PES packet in the decoder's
         * PES fifo */
394
395
396
397
398
399
        if( p_es->p_decoder_fifo != NULL )
        {
            input_DecodePES( p_es->p_decoder_fifo, p_pes );
        }
        else
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
400
401
            intf_ErrMsg( "input error: no fifo to receive PES %p "
                         "(who wrote this damn code ?)", p_pes );
Sam Hocevar's avatar
   
Sam Hocevar committed
402
            p_input->pf_delete_pes( p_input->p_method_data, p_pes );
403
404
        }
        p_pes = NULL;
405
406
    }
#undef p_pes
407

408
409
410
411
412
413
414
}

/*****************************************************************************
 * input_GatherPES:
 *****************************************************************************
 * Gather a PES packet.
 *****************************************************************************/
415
void input_GatherPES( input_thread_t * p_input, data_packet_t * p_data,
416
417
418
419
420
                      es_descriptor_t * p_es,
                      boolean_t b_unit_start, boolean_t b_packet_lost )
{
#define p_pes (p_es->p_pes)

Sam Hocevar's avatar
   
Sam Hocevar committed
421
    //intf_DbgMsg("PES-demultiplexing %p (%p)", p_ts_packet, p_pes);
422

Sam Hocevar's avatar
   
Sam Hocevar committed
423
    /* If we lost data, insert a NULL data packet (philosophy : 0 is quite
424
425
     * often an escape sequence in decoders, so that should make them wait
     * for the next start code). */
426
    if( b_packet_lost )
427
    {
428
        input_NullPacket( p_input, p_es );
429
430
431
432
    }

    if( b_unit_start && p_pes != NULL )
    {
433
        /* If the data packet contains the begining of a new PES packet, and
434
435
436
437
438
439
440
441
         * if we were reassembling a PES packet, then the PES should be
         * complete now, so parse its header and give it to the decoders. */
        input_ParsePES( p_input, p_es );
    }

    if( !b_unit_start && p_pes == NULL )
    {
        /* Random access... */
Sam Hocevar's avatar
   
Sam Hocevar committed
442
        p_input->pf_delete_packet( p_input->p_method_data, p_data );
443
444
445
446
447
448
449
450
451
452
    }
    else
    {
        if( b_unit_start )
        {
            /* If we are at the beginning of a new PES packet, we must fetch
             * a new PES buffer to begin with the reassembly of this PES
             * packet. This is also here that we can synchronize with the
             * stream if we lost packets or if the decoder has just
             * started. */
Sam Hocevar's avatar
   
Sam Hocevar committed
453
            if( (p_pes = p_input->pf_new_pes( p_input->p_method_data ) ) == NULL )
454
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
455
                intf_ErrMsg( "input error: out of memory" );
456
457
458
                p_input->b_error = 1;
                return;
            }
459
            p_pes->i_rate = p_input->stream.control.i_rate;
460
            p_pes->p_first = p_data;
Henri Fallon's avatar
   
Henri Fallon committed
461
            
462
463
464
465
466
467
468
            /* If the PES header fits in the first data packet, we can
             * already set p_gather->i_pes_real_size. */
            if( p_data->p_payload_end - p_data->p_payload_start
                    >= PES_HEADER_SIZE )
            {
                p_es->i_pes_real_size =
                                U16_AT(p_data->p_payload_start + 4) + 6;
Henri Fallon's avatar
   
Henri Fallon committed
469
                
470
471
            }
            else
Henri Fallon's avatar
   
Henri Fallon committed
472
            { 
473
                p_es->i_pes_real_size = 0;
Henri Fallon's avatar
   
Henri Fallon committed
474
            } 
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
        }
        else
        {
            /* Update the relations between the data packets */
            p_es->p_last->p_next = p_data;
        }

        p_es->p_last = p_data;

        /* Size of the payload carried in the data packet */
        p_pes->i_pes_size += (p_data->p_payload_end
                                 - p_data->p_payload_start);
    
        /* We can check if the packet is finished */
        if( p_pes->i_pes_size == p_es->i_pes_real_size )
        {
            /* The packet is finished, parse it */
            input_ParsePES( p_input, p_es );
        }
    }
#undef p_pes
}


/*
 * PS Demultiplexing
 */

503
504
505
506
507
508
509
/*****************************************************************************
 * GetID: Get the ID of a stream
 *****************************************************************************/
static u16 GetID( data_packet_t * p_data )
{
    u16         i_id;

510
    i_id = p_data->p_payload_start[3];                                 /* stream_id */
511
512
    if( i_id == 0xBD )
    {
513
514
        /* FIXME : this is not valid if the header is split in multiple
         * packets */
515
        /* stream_private_id */
516
        i_id |= p_data->p_payload_start[ 9 + p_data->p_payload_start[8] ] << 8;
517
518
519
520
    }
    return( i_id );
}

521
522
/*****************************************************************************
 * DecodePSM: Decode the Program Stream Map information
523
524
 *****************************************************************************
 * FIXME : loads are not aligned in this function
525
526
527
528
529
 *****************************************************************************/
static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
{
    stream_ps_data_t *  p_demux =
                 (stream_ps_data_t *)p_input->stream.p_demux_data;
530
531
532
533
    byte_t *            p_byte;
    byte_t *            p_end;
    int                 i;
    int                 i_new_es_number = 0;
534

535
    if( p_data->p_payload_start + 10 > p_data->p_payload_end )
536
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
537
        intf_ErrMsg( "input error: PSM too short : packet corrupt" );
538
539
        return;
    }
540

541
    if( p_demux->b_has_PSM
542
        && p_demux->i_PSM_version == (p_data->p_payload_start[6] & 0x1F) )
543
544
545
546
    {
        /* Already got that one. */
        return;
    }
547

Sam Hocevar's avatar
   
Sam Hocevar committed
548
    intf_DbgMsg( "input: building PSM" );
549
    p_demux->b_has_PSM = 1;
550
    p_demux->i_PSM_version = p_data->p_payload_start[6] & 0x1F;
551
552
553
554
555
556
557

    /* Go to elementary_stream_map_length, jumping over
     * program_stream_info. */
    p_byte = p_data->p_payload_start + 10
              + U16_AT(&p_data->p_payload_start[8]);
    if( p_byte > p_data->p_payload_end )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
558
        intf_ErrMsg( "input error: PSM too short, packet corrupt" );
559
560
561
562
        return;
    }
    /* This is the full size of the elementary_stream_map.
     * 2 == elementary_stream_map_length
563
564
     * Please note that CRC_32 is not included in the length. */
    p_end = p_byte + 2 + U16_AT(p_byte);
565
566
567
    p_byte += 2;
    if( p_end > p_data->p_payload_end )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
568
        intf_ErrMsg( "input error: PSM too short, packet corrupt" );
569
570
        return;
    }
571

572
573
574
575
576
577
578
579
580
581
582
583
584
585
    vlc_mutex_lock( &p_input->stream.stream_lock );

    /* 4 == minimum useful size of a section */
    while( p_byte + 4 <= p_end )
    {
        es_descriptor_t *   p_es = NULL;
        u8                  i_stream_id = p_byte[1];
        /* FIXME: there will be a problem with private streams... (same
         * stream_id) */

        /* Look for the ES in the ES table */
        for( i = i_new_es_number;
             i < p_input->stream.pp_programs[0]->i_es_number;
             i++ )
586
        {
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
            if( p_input->stream.pp_programs[0]->pp_es[i]->i_stream_id
                    == i_stream_id )
            {
                p_es = p_input->stream.pp_programs[0]->pp_es[i];
                if( p_es->i_type != p_byte[0] )
                {
                    input_DelES( p_input, p_es );
                    p_es = NULL;
                }
                else
                {
                    /* Move the ES to the beginning. */
                    p_input->stream.pp_programs[0]->pp_es[i]
                        = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ];
                    p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ]
                        = p_es;
603
                    i_new_es_number++;
604
605
606
607
                }
                break;
            }
        }
608

609
610
611
612
613
        /* The goal is to have all the ES we have just read in the
         * beginning of the pp_es table, and all the others at the end,
         * so that we can close them more easily at the end. */
        if( p_es == NULL )
        {
614
            p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
615
                                i_stream_id, 0 );
616
            p_es->i_type = p_byte[0];
617
618
619
620
621
            p_es->b_audio = ( p_es->i_type == MPEG1_AUDIO_ES
                              || p_es->i_type == MPEG2_AUDIO_ES
                              || p_es->i_type == AC3_AUDIO_ES
                              || p_es->i_type == LPCM_AUDIO_ES
                            );
622

623
624
625
626
627
            /* input_AddES has inserted the new element at the end. */
            p_input->stream.pp_programs[0]->pp_es[
                p_input->stream.pp_programs[0]->i_es_number ]
                = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ];
            p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ] = p_es;
628
            i_new_es_number++;
629
630
        }
        p_byte += 4 + U16_AT(&p_byte[2]);
631
    }
632
633
634
635
636

    /* Un-select the streams that are no longer parts of the program. */
    for( i = i_new_es_number;
         i < p_input->stream.pp_programs[0]->i_es_number;
         i++ )
637
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
638
639
        /* We remove pp_es[i_new_es_member] and not pp_es[i] because the
         * list will be emptied starting from the end */
640
641
        input_DelES( p_input,
                     p_input->stream.pp_programs[0]->pp_es[i_new_es_number] );
642
    }
643

644
645
646
647
648
    if( p_main->b_stats )
    {
        intf_StatMsg( "input info: The stream map after the PSM is now :" );
        input_DumpStream( p_input );
    }
649

650
    vlc_mutex_unlock( &p_input->stream.stream_lock );
651
652
}

653
654
655
656
657
658
659
660
661
/*****************************************************************************
 * input_ParsePS: read the PS header
 *****************************************************************************/
es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                                 data_packet_t * p_data )
{
    u32                 i_code;
    es_descriptor_t *   p_es = NULL;

662
    i_code = p_data->p_payload_start[3];
Cyril Deguet's avatar
   
Cyril Deguet committed
663

664
    if( i_code > 0xBC ) /* ES start code */
665
666
667
668
669
670
671
672
673
674
675
    {
        u16                 i_id;
        int                 i_dummy;

        /* This is a PES packet. Find out if we want it or not. */
        i_id = GetID( p_data );

        vlc_mutex_lock( &p_input->stream.stream_lock );
        if( p_input->stream.pp_programs[0]->b_is_ok )
        {
            /* Look only at the selected ES. */
676
            for( i_dummy = 0; i_dummy < p_input->stream.i_selected_es_number;
677
                 i_dummy++ )
678
            {
679
680
                if( p_input->stream.pp_selected_es[i_dummy] != NULL
                    && p_input->stream.pp_selected_es[i_dummy]->i_id == i_id )
681
                {
682
                    p_es = p_input->stream.pp_selected_es[i_dummy];
683
684
685
686
687
688
                    break;
                }
            }
        }
        else
        {
689
690
691
            stream_ps_data_t * p_demux =
              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;

692
            /* Search all ES ; if not found -> AddES */
693
            p_es = input_FindES( p_input, i_id );
694

695
            if( p_es == NULL && !p_demux->b_has_PSM )
696
697
698
699
700
            {
                p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
                                    i_id, 0 );
                if( p_es != NULL )
                {
701
                    p_es->i_stream_id = p_data->p_payload_start[3];
702
703
704
705
706
707

                    /* Set stream type and auto-spawn. */
                    if( (i_id & 0xF0) == 0xE0 )
                    {
                        /* MPEG video */
                        p_es->i_type = MPEG2_VIDEO_ES;
Stéphane Borel's avatar
Stéphane Borel committed
708
                        p_es->i_cat = VIDEO_ES;
709
#ifdef AUTO_SPAWN
710
                        if( !p_input->stream.b_seekable )
711
                            input_SelectES( p_input, p_es );
712
713
714
715
716
717
#endif
                    }
                    else if( (i_id & 0xE0) == 0xC0 )
                    {
                        /* MPEG audio */
                        p_es->i_type = MPEG2_AUDIO_ES;
718
                        p_es->b_audio = 1;
Stéphane Borel's avatar
Stéphane Borel committed
719
                        p_es->i_cat = AUDIO_ES;
720
#ifdef AUTO_SPAWN
721
722
723
724
                        if( !p_input->stream.b_seekable )
                        if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
                                == (p_es->i_id & 0x1F) )
                        switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
725
                        {
726
727
728
729
730
                        case 0:
                            main_PutIntVariable( INPUT_CHANNEL_VAR,
                                                 REQUESTED_MPEG );
                        case REQUESTED_MPEG:
                            input_SelectES( p_input, p_es );
731
                        }
732
733
734
735
#endif
                    }
                    else if( (i_id & 0xF0FF) == 0x80BD )
                    {
736
                        /* AC3 audio (0x80->0x8F) */
737
                        p_es->i_type = AC3_AUDIO_ES;
738
                        p_es->b_audio = 1;
Stéphane Borel's avatar
Stéphane Borel committed
739
                        p_es->i_cat = AUDIO_ES;
740
#ifdef AUTO_SPAWN
741
742
743
744
                        if( !p_input->stream.b_seekable )
                        if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
                                == ((p_es->i_id & 0xF00) >> 8) )
                        switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
745
                        {
746
747
748
749
750
                        case 0:
                            main_PutIntVariable( INPUT_CHANNEL_VAR,
                                                 REQUESTED_AC3 );
                        case REQUESTED_AC3:
                            input_SelectES( p_input, p_es );
751
                        }
752
753
#endif
                    }
754
                    else if( (i_id & 0xE0FF) == 0x20BD )
755
                    {
756
                        /* Subtitles video (0x20->0x3F) */
757
                        p_es->i_type = DVD_SPU_ES;
Stéphane Borel's avatar
Stéphane Borel committed
758
                        p_es->i_cat = SPU_ES;
759
#ifdef AUTO_SPAWN
760
761
                        if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
                                == ((p_es->i_id & 0x1F00) >> 8) )
762
                        {
763
                            if( !p_input->stream.b_seekable )
764
                                input_SelectES( p_input, p_es );
765
                        }
766
767
#endif
                    }
768
769
770
771
                    else if( (i_id & 0xF0FF) == 0xA0BD )
                    {
                        /* LPCM audio (0xA0->0xAF) */
                        p_es->i_type = LPCM_AUDIO_ES;
772
                        p_es->b_audio = 1;
Stéphane Borel's avatar
Stéphane Borel committed
773
                        p_es->i_cat = AUDIO_ES;
774
775
                        /* FIXME : write the decoder */
                    }
776
777
778
779
780
                    else
                    {
                        p_es->i_type = UNKNOWN_ES;
                    }
                }
781

782
                /* Tell the interface the stream has changed */
783
                p_input->stream.b_changed = 1;
784
785
786
787
788
789
790
791
            }
        } /* stream.b_is_ok */
        vlc_mutex_unlock( &p_input->stream.stream_lock );
    } /* i_code > 0xBC */

    return( p_es );
}

792
793
794
795
796
797
798
799
800
/*****************************************************************************
 * input_DemuxPS: first step of demultiplexing: the PS header
 *****************************************************************************/
void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
{
    u32                 i_code;
    boolean_t           b_trash = 0;
    es_descriptor_t *   p_es = NULL;

801
    i_code = U32_AT( p_data->p_payload_start );
802
    if( i_code <= 0x1BC )
803
804
805
806
807
    {
        switch( i_code )
        {
        case 0x1BA: /* PACK_START_CODE */
            {
808
                /* Read the SCR. */
809
                mtime_t         scr_time;
Christophe Massiot's avatar
Christophe Massiot committed
810
                u32             i_mux_rate;
811

812
                if( (p_data->p_payload_start[4] & 0xC0) == 0x40 )
813
814
                {
                    /* MPEG-2 */
815
816
817
818
819
820
                    byte_t      p_header[14];
                    byte_t *    p_byte;
                    p_byte = p_data->p_payload_start;

                    if( MoveChunk( p_header, &p_data, &p_byte, 14 ) != 14 )
                    {
Sam Hocevar's avatar
   
Sam Hocevar committed
821
822
                        intf_WarnMsg( 1, "input: packet too short "
                                         "to have a header" );
823
824
825
                        b_trash = 1;
                        break;
                    }
826
                    scr_time =
827
828
                         ((mtime_t)(p_header[4] & 0x38) << 27) |
                         ((mtime_t)(U32_AT(p_header + 4) & 0x03FFF800)
829
                                        << 4) |
830
831
                         ((( ((mtime_t)U16_AT(p_header + 6) << 16)
                            | (mtime_t)U16_AT(p_header + 8) ) & 0x03FFF800)
832
                                        >> 11);
Christophe Massiot's avatar
Christophe Massiot committed
833
834

                    /* mux_rate */
835
836
                    i_mux_rate = ((u32)U16_AT(p_header + 10) << 6)
                                   | (p_header[12] >> 2);
837
838
839
840
841
842
                    /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
                     * This is the biggest kludge ever !
                     * I don't know what's wrong with mux_rate calculation
                     * but this heuristic work well : */
                    i_mux_rate <<= 1;
                    i_mux_rate /= 3;
843
844
845
                }
                else
                {
846
                    /* MPEG-1 SCR is like PTS. */
847
848
849
850
851
852
                    byte_t      p_header[12];
                    byte_t *    p_byte;
                    p_byte = p_data->p_payload_start;

                    if( MoveChunk( p_header, &p_data, &p_byte, 12 ) != 12 )
                    {
Sam Hocevar's avatar
   
Sam Hocevar committed
853
854
                        intf_WarnMsg( 1, "input: packet too short "
                                         "to have a header" );
855
856
857
                        b_trash = 1;
                        break;
                    }
858
                    scr_time =
859
860
861
862
                         ((mtime_t)(p_header[4] & 0x0E) << 29) |
                         (((mtime_t)U32_AT(p_header + 4) & 0xFFFE00) << 6) |
                         ((mtime_t)p_header[7] << 7) |
                         ((mtime_t)p_header[8] >> 1);
Christophe Massiot's avatar
Christophe Massiot committed
863
864

                    /* mux_rate */
865
                    i_mux_rate = (U32_AT(p_header + 8) & 0x7FFFFE) >> 1;
866
                }
867
                /* Call the pace control. */
868
869
                input_ClockManageRef( p_input, p_input->stream.pp_programs[0],
                                      scr_time );
Christophe Massiot's avatar
Christophe Massiot committed
870
871
872
873

                if( i_mux_rate != p_input->stream.i_mux_rate
                     && p_input->stream.i_mux_rate )
                {
Sam Hocevar's avatar
   
Sam Hocevar committed
874
875
                    intf_WarnMsg( 2, "input: mux_rate changed, "
                                     "expect cosmetic errors" );
Christophe Massiot's avatar
Christophe Massiot committed
876
877
878
                }
                p_input->stream.i_mux_rate = i_mux_rate;

879
                b_trash = 1;
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
            }
            break;

        case 0x1BB: /* SYSTEM_START_CODE */
            b_trash = 1;                              /* Nothing interesting */
            break;

        case 0x1BC: /* PROGRAM_STREAM_MAP_CODE */
            DecodePSM( p_input, p_data );
            b_trash = 1;
            break;
    
        case 0x1B9: /* PROGRAM_END_CODE */
            b_trash = 1;
            break;
   
        default:
            /* This should not happen */
            b_trash = 1;
Sam Hocevar's avatar
   
Sam Hocevar committed
899
900
            intf_WarnMsg( 3, "input: unwanted packet received "
                             "with start code 0x%.8x", i_code );
901
902
903
904
        }
    }
    else
    {
905
        p_es = input_ParsePS( p_input, p_data );
906

907
908
909
        vlc_mutex_lock( &p_input->stream.control.control_lock );
        if( p_es != NULL && p_es->p_decoder_fifo != NULL
             && (!p_es->b_audio || !p_input->stream.control.b_mute) )
910
        {
911
            vlc_mutex_unlock( &p_input->stream.control.control_lock );
912
913
914
            p_es->c_packets++;
            input_GatherPES( p_input, p_data, p_es, 1, 0 );
        }
915
916
        else
        {
917
            vlc_mutex_unlock( &p_input->stream.control.control_lock );
918
919
            b_trash = 1;
        }
920
921
922
923
924
    }

    /* Trash the packet if it has no payload or if it isn't selected */
    if( b_trash )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
925
        p_input->pf_delete_packet( p_input->p_method_data, p_data );
926
        p_input->stream.c_packets_trashed++;
927
928
929
    }
}

Henri Fallon's avatar
   
Henri Fallon committed
930
 
931
932
933
934
935
936
937
938
939
/*
 * TS Demultiplexing
 */

/*****************************************************************************
 * input_DemuxTS: first step of demultiplexing: the TS header
 *****************************************************************************/
void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
{
Henri Fallon's avatar
   
Henri Fallon committed
940
941
    u16                 i_pid;
    int                 i_dummy;
942
943
944
945
946
    boolean_t           b_adaptation;         /* Adaptation field is present */
    boolean_t           b_payload;                 /* Packet carries payload */
    boolean_t           b_unit_start;  /* A PSI or a PES start in the packet */
    boolean_t           b_trash = 0;             /* Is the packet unuseful ? */
    boolean_t           b_lost = 0;             /* Was there a packet loss ? */
Henri Fallon's avatar
   
Henri Fallon committed
947
    boolean_t           b_psi = 0;                        /* Is this a PSI ? */
948
949
950
951
    es_descriptor_t *   p_es = NULL;
    es_ts_data_t *      p_es_demux = NULL;
    pgrm_ts_data_t *    p_pgrm_demux = NULL;

952
#define p (p_data->p_buffer)
953
    /* Extract flags values from TS common header. */
954
    i_pid = ((p[1] & 0x1F) << 8) | p[2];
955
956
957
958
959
960
    b_unit_start = (p[1] & 0x40);
    b_adaptation = (p[3] & 0x20);
    b_payload = (p[3] & 0x10);

    /* Find out the elementary stream. */
    vlc_mutex_lock( &p_input->stream.stream_lock );
Henri Fallon's avatar
   
Henri Fallon committed
961
962
        
    p_es= input_FindES( p_input, i_pid );
Henri Fallon's avatar
   
Henri Fallon committed
963
    
Henri Fallon's avatar
   
Henri Fallon committed
964
965
966
967
968
    if( (p_es != NULL) && (p_es->p_demux_data != NULL) )
    {
        p_es_demux = (es_ts_data_t *)p_es->p_demux_data;
        
        if( p_es_demux->b_psi )
969
        {
Henri Fallon's avatar
   
Henri Fallon committed
970
            b_psi = 1;
971
        }
Henri Fallon's avatar
   
Henri Fallon committed
972
        else
973
        {
Henri Fallon's avatar
   
Henri Fallon committed
974
            p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data; 
975
        }
Henri Fallon's avatar
   
Henri Fallon committed
976
977
    }

978
    vlc_mutex_lock( &p_input->stream.control.control_lock );
Henri Fallon's avatar
   
Henri Fallon committed
979
    if( ( p_es == NULL ) || (p_es->b_audio && p_input->stream.control.b_mute) )
980
981
982
983
    {
        /* Not selected. Just read the adaptation field for a PCR. */
        b_trash = 1;
    }
984
985
986
987
    else if( p_es->p_decoder_fifo == NULL && !b_psi )
    {
        b_trash = 1; 
    }
Henri Fallon's avatar
   
Henri Fallon committed
988

989
990
    vlc_mutex_unlock( &p_input->stream.control.control_lock );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
991

Henri Fallon's avatar
   
Henri Fallon committed
992

Henri Fallon's avatar
   
Henri Fallon committed
993
    /* Don't change the order of the tests : if b_psi then p_pgrm_demux 
994
995
     * may still be null. Who said it was ugly ?
     * I have written worse. --Meuuh */
Henri Fallon's avatar
   
Henri Fallon committed
996
997
998
    if( ( p_es != NULL ) && 
        ((p_es->p_decoder_fifo != NULL) || b_psi 
                                   || (p_pgrm_demux->i_pcr_pid == i_pid) ) )
999
    {
1000
        p_es->c_packets++;
For faster browsing, not all history is shown. View entire blame