ts.c 52.9 KB
Newer Older
1
/*****************************************************************************
2
 * ts.c: MPEG-II TS Muxer
3
4
 *****************************************************************************
 * Copyright (C) 2001, 2002 VideoLAN
5
 * $Id: ts.c,v 1.36 2003/11/20 18:26:44 fenrir Exp $
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Eric Petit <titer@videolan.org>
 *
 *
 * 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 <stdlib.h>

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/sout.h>

#include "codecs.h"
#include "bits.h"
#include "pes.h"

39
#if defined MODULE_NAME_IS_mux_ts_dvbpsi
ipkiss's avatar
ipkiss committed
40
#   ifdef HAVE_DVBPSI_DR_H
41
42
43
44
45
#       include <dvbpsi/dvbpsi.h>
#       include <dvbpsi/descriptor.h>
#       include <dvbpsi/pat.h>
#       include <dvbpsi/pmt.h>
#       include <dvbpsi/dr.h>
46
#       include <dvbpsi/psi.h>
ipkiss's avatar
ipkiss committed
47
48
49
50
51
52
#   else
#       include "dvbpsi.h"
#       include "descriptor.h"
#       include "tables/pat.h"
#       include "tables/pmt.h"
#       include "descriptors/dr.h"
53
#       include "psi.h"
ipkiss's avatar
ipkiss committed
54
#   endif
55
56
#endif

57
58
59
60
61
/*
 * TODO:
 *  - check PCR frequency requirement
 *  - check PAT/PMT  "        "
 *  - check PCR/PCR "soft"
62
63
 *  - check if "registration" descriptor : "AC-3" should be a program
 *    descriptor or an es one. (xine want an es one)
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
 *
 *  - remove creation of PAT/PMT without dvbpsi
 *  - ?
 * FIXME:
 *  - subtitle support is far from perfect. I expect some subtitles drop
 *    if they arrive a bit late
 *    (We cannot rely on the fact that the fifo should be full)
 */
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int     Open   ( vlc_object_t * );
static void    Close  ( vlc_object_t * );

vlc_module_begin();
#if defined MODULE_NAME_IS_mux_ts
    set_description( _("TS muxer") );
    set_capability( "sout mux", 100 );
    add_shortcut( "ts" );
    add_shortcut( "ts_nodvbpsi" );
#elif defined MODULE_NAME_IS_mux_ts_dvbpsi
    set_description( _("TS muxer (libdvbpsi)") );
    set_capability( "sout mux", 120 );
    add_shortcut( "ts" );
    add_shortcut( "ts_dvbpsi" );
#endif
    set_callbacks( Open, Close );
vlc_module_end();

/*****************************************************************************
 * Exported prototypes
 *****************************************************************************/
static int     Capability(sout_mux_t *, int, void *, void * );
static int     AddStream( sout_mux_t *, sout_input_t * );
static int     DelStream( sout_mux_t *, sout_input_t * );
static int     Mux      ( sout_mux_t * );

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
104
#define SOUT_BUFFER_FLAGS_PRIVATE_PCR  ( 1 << SOUT_BUFFER_FLAGS_PRIVATE_SHIFT )
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
typedef struct
{
    int           i_depth;
    sout_buffer_t *p_first;
    sout_buffer_t **pp_last;
} sout_buffer_chain_t;

static inline void BufferChainInit  ( sout_buffer_chain_t *c )
{
    c->i_depth = 0;
    c->p_first = NULL;
    c->pp_last = &c->p_first;
}
static inline void BufferChainAppend( sout_buffer_chain_t *c, sout_buffer_t *b )
{
    *c->pp_last = b;
    c->i_depth++;

    while( b->p_next )
    {
        b = b->p_next;
        c->i_depth++;
    }
    c->pp_last = &b->p_next;
}
static inline sout_buffer_t *BufferChainGet( sout_buffer_chain_t *c )
{
    sout_buffer_t *b = c->p_first;

    if( b )
    {
        c->i_depth--;
        c->p_first = b->p_next;

        if( c->p_first == NULL )
        {
            c->pp_last = &c->p_first;
        }

        b->p_next = NULL;
    }
    return b;
}
148
149
150
151
152
153
154
155
156
157
static inline void BufferChainClean( sout_instance_t *p_sout, sout_buffer_chain_t *c )
{
    sout_buffer_t *b;

    while( ( b = BufferChainGet( c ) ) )
    {
        sout_BufferDelete( p_sout, b );
    }
    BufferChainInit( c );
}
158

159
160
161
162
163
164
typedef struct ts_stream_s
{
    int             i_pid;
    int             i_stream_type;
    int             i_stream_id;
    int             i_continuity_counter;
165

166
167
168
169
    /* to be used for carriege of DIV3 */
    vlc_fourcc_t    i_bih_codec;
    int             i_bih_width, i_bih_height;

170
171
172
    /* Specific to mpeg4 in mpeg2ts */
    int             i_es_id;

173
    int             i_decoder_specific_info;
174
    uint8_t         *p_decoder_specific_info;
175

176
177
178
179
    sout_buffer_chain_t chain_pes;
    mtime_t             i_pes_dts;
    mtime_t             i_pes_length;
    int                 i_pes_used;
180

181
182
} ts_stream_t;

183
struct sout_mux_sys_t
184
185
{
    int             i_pcr_pid;
186
187
    sout_input_t    *p_pcr_input;

188
189
190
191
192
193
    int             i_stream_id_mpga;
    int             i_stream_id_mpgv;

    int             i_audio_bound;
    int             i_video_bound;

Christophe Massiot's avatar
Christophe Massiot committed
194
195
    int             i_pid_video;
    int             i_pid_audio;
196
197
198
199
200
201
202
203
    int             i_pid_free; // first usable pid

    int             i_pat_version_number;
    ts_stream_t     pat;

    int             i_pmt_version_number;
    ts_stream_t     pmt;        // Up to now only one program

204
205
    int             i_mpeg4_streams;

206
    int             i_null_continuity_counter;  /* Needed ? */
207

208
209
210
    /* for TS building */
    int64_t             i_bitrate_min;
    int64_t             i_bitrate_max;
211
212

    int64_t             i_caching_delay;
213
    int64_t             i_pcr_delay;
Laurent Aimar's avatar
Laurent Aimar committed
214

215
216
    int64_t             i_dts_delay;

217
    mtime_t             i_pcr;  /* last PCR emited */
218
};
219
220


221
/* Reserve a pid and return it */
Christophe Massiot's avatar
Christophe Massiot committed
222
static int  AllocatePID( sout_mux_sys_t *p_sys, int i_cat )
223
{
Christophe Massiot's avatar
Christophe Massiot committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    int i_pid;
    if ( i_cat == VIDEO_ES && p_sys->i_pid_video )
    {
        i_pid = p_sys->i_pid_video;
        p_sys->i_pid_video = 0;
    }
    else if ( i_cat == AUDIO_ES && p_sys->i_pid_audio )
    {
        i_pid = p_sys->i_pid_audio;
        p_sys->i_pid_audio = 0;
    }
    else
    {
        i_pid = ++p_sys->i_pid_free;
    }
    return i_pid;
240
241
}

242
243
static void GetPAT( sout_mux_t *p_mux, sout_buffer_chain_t *c );
static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c );
244

245
246
247
248
static sout_buffer_t *TSNew( sout_mux_t *p_mux, ts_stream_t *p_stream, vlc_bool_t b_pcr );
static void TSSetPCR( sout_buffer_t *p_ts, mtime_t i_dts );

static void PEStoTS  ( sout_instance_t *, sout_buffer_chain_t *, sout_buffer_t *, ts_stream_t * );
249

250
251
252
253
254
/*****************************************************************************
 * Open:
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
255
256
    sout_mux_t          *p_mux =(sout_mux_t*)p_this;
    sout_mux_sys_t      *p_sys;
257
    char                *val;
258

259
    msg_Dbg( p_mux, "Open" );
260

261
    p_sys = malloc( sizeof( sout_mux_sys_t ) );
262

263
264
265
266
267
268
    p_mux->pf_capacity  = Capability;
    p_mux->pf_addstream = AddStream;
    p_mux->pf_delstream = DelStream;
    p_mux->pf_mux       = Mux;
    p_mux->p_sys        = p_sys;
    p_mux->i_preheader  = 30; // really enough for a pes header
269

270
271
    srand( (uint32_t)mdate() );

272
273
    p_sys->i_stream_id_mpga = 0xc0;
    p_sys->i_stream_id_mpgv = 0xe0;
274

275
276
    p_sys->i_audio_bound = 0;
    p_sys->i_video_bound = 0;
277

278
279
280
    p_sys->i_pat_version_number = rand() % 32;
    p_sys->pat.i_pid = 0;
    p_sys->pat.i_continuity_counter = 0;
281

282
    p_sys->i_pmt_version_number = rand() % 32;
283
    p_sys->pmt.i_pid = 0x42;
284
    p_sys->pmt.i_continuity_counter = 0;
285

286
    p_sys->i_pid_free = 0x43;
287

Christophe Massiot's avatar
Christophe Massiot committed
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
    p_sys->i_pid_video = 0;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "pid-video" ) ) )
    {
        p_sys->i_pid_video = strtol( val, NULL, 0 );
        if ( p_sys->i_pid_video > p_sys->i_pid_free )
        {
            p_sys->i_pid_free = p_sys->i_pid_video + 1;
        }
    }
    p_sys->i_pid_audio = 0;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "pid-audio" ) ) )
    {
        p_sys->i_pid_audio = strtol( val, NULL, 0 );
        if ( p_sys->i_pid_audio > p_sys->i_pid_free )
        {
            p_sys->i_pid_free = p_sys->i_pid_audio + 1;
        }
    }

307
    p_sys->i_pcr_pid = 0x1fff;
308
    p_sys->p_pcr_input = NULL;
309

310
    p_sys->i_mpeg4_streams = 0;
311

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
    p_sys->i_null_continuity_counter = 0;

    /* Allow to create constrained stream */
    p_sys->i_bitrate_min = 0;
    p_sys->i_bitrate_max = 0;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "bmin" ) ) )
    {
        p_sys->i_bitrate_min = atoll( val );
    }
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "bmax" ) ) )
    {
        p_sys->i_bitrate_max = atoll( val );
    }
    if( p_sys->i_bitrate_min > 0 && p_sys->i_bitrate_max > 0 &&
        p_sys->i_bitrate_min > p_sys->i_bitrate_max )
    {
gbazin's avatar
   
gbazin committed
328
329
        msg_Err( p_mux, "incompatible minimum and maximum bitrate, "
                 "disabling bitrate control" );
330
331
332
        p_sys->i_bitrate_min = 0;
        p_sys->i_bitrate_max = 0;
    }
333
    if( p_sys->i_bitrate_min > 0 || p_sys->i_bitrate_max > 0 )
334
    {
335
336
337
338
339
340
341
342
        msg_Err( p_mux, "bmin and bmax no more supported (if you need them report it)" );
    }

    p_sys->i_caching_delay = 200000;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "caching" ) ) )
    {
        p_sys->i_caching_delay = (int64_t)atoi( val ) * 1000;
        if( p_sys->i_caching_delay <= 0 )
343
344
        {
            msg_Err( p_mux,
345
346
347
                     "invalid caching ("I64Fd"ms) reseting to 200ms",
                     p_sys->i_caching_delay / 1000 );
            p_sys->i_caching_delay = 200000;
348
349
        }
    }
350
351
    p_sys->i_pcr_delay = 30000;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "pcr" ) ) )
352
    {
353
354
355
        p_sys->i_pcr_delay = (int64_t)atoi( val ) * 1000;
        if( p_sys->i_pcr_delay <= 0 ||
            p_sys->i_pcr_delay >= p_sys->i_caching_delay )
356
357
        {
            msg_Err( p_mux,
358
359
360
                     "invalid pcr delay ("I64Fd"ms) reseting to 30ms",
                     p_sys->i_pcr_delay / 1000 );
            p_sys->i_pcr_delay = 30000;
361
362
363
        }
    }

364
365
    msg_Dbg( p_mux, "caching="I64Fd" pcr="I64Fd,
             p_sys->i_caching_delay, p_sys->i_pcr_delay );
gbazin's avatar
   
gbazin committed
366

367
368
369
370
371
372
    p_sys->i_dts_delay = 200000;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "dts-delay" ) ) )
    {
        p_sys->i_dts_delay = (int64_t)atoi( val ) * 1000;
    }

Christophe Massiot's avatar
Christophe Massiot committed
373
    /* for TS generation */
374
    p_sys->i_pcr    = 0;
375
376
377
378
379
380
381
382
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
383
384
    sout_mux_t          *p_mux = (sout_mux_t*)p_this;
    sout_mux_sys_t      *p_sys = p_mux->p_sys;
385

386
387
    msg_Dbg( p_mux, "Close" );

388
    free( p_sys );
389
390
}

391
392
393
/*****************************************************************************
 * Capability:
 *****************************************************************************/
394
static int Capability( sout_mux_t *p_mux, int i_query, void *p_args, void *p_answer )
395
396
397
398
399
400
401
402
403
404
{
   switch( i_query )
   {
        case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
            *(vlc_bool_t*)p_answer = VLC_TRUE;
            return( SOUT_MUX_CAP_ERR_OK );
        default:
            return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
   }
}
405

406
407
408
/*****************************************************************************
 * AddStream: called for each stream addition
 *****************************************************************************/
409
static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
410
{
411
    sout_mux_sys_t      *p_sys = p_mux->p_sys;
412
413
    ts_stream_t         *p_stream;

414
415
    msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_fourcc );

416
    p_input->p_sys = (void*)p_stream = malloc( sizeof( ts_stream_t ) );
417

418
    /* Init this new stream */
Christophe Massiot's avatar
Christophe Massiot committed
419
    p_stream->i_pid = AllocatePID( p_sys, p_input->p_fmt->i_cat );
420
421
422
    p_stream->i_continuity_counter    = 0;
    p_stream->i_decoder_specific_info = 0;
    p_stream->p_decoder_specific_info = NULL;
423

424
    /* All others fields depand on codec */
425
    switch( p_input->p_fmt->i_cat )
426
427
    {
        case VIDEO_ES:
428
            switch( p_input->p_fmt->i_fourcc )
429
430
            {
                case VLC_FOURCC( 'm', 'p','g', 'v' ):
431
                    /* TODO: do we need to check MPEG-I/II ? */
432
                    p_stream->i_stream_type = 0x02;
433
434
                    p_stream->i_stream_id = p_sys->i_stream_id_mpgv;
                    p_sys->i_stream_id_mpgv++;
435
436
437
438
                    break;
                case VLC_FOURCC( 'm', 'p','4', 'v' ):
                    p_stream->i_stream_type = 0x10;
                    p_stream->i_stream_id = 0xfa;
439
                    p_sys->i_mpeg4_streams++;
440
                    p_stream->i_es_id = p_stream->i_pid;
441
                    break;
442
443
444
445
                /* XXX dirty dirty but somebody want that : using crapy MS-codec XXX */
                /* I didn't want to do that :P */
                case VLC_FOURCC( 'H', '2', '6', '3' ):
                case VLC_FOURCC( 'I', '2', '6', '3' ):
446
                case VLC_FOURCC( 'W', 'M', 'V', '2' ):
447
448
449
450
                case VLC_FOURCC( 'W', 'M', 'V', '1' ):
                case VLC_FOURCC( 'D', 'I', 'V', '3' ):
                case VLC_FOURCC( 'D', 'I', 'V', '2' ):
                case VLC_FOURCC( 'D', 'I', 'V', '1' ):
451
                case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
452
453
                    p_stream->i_stream_type = 0xa0; // private
                    p_stream->i_stream_id = 0xa0;   // beurk
454
455
456
                    p_stream->i_bih_codec  = p_input->p_fmt->i_fourcc;
                    p_stream->i_bih_width  = p_input->p_fmt->i_width;
                    p_stream->i_bih_height = p_input->p_fmt->i_height;
457
                    break;
458
                default:
459
460
                    free( p_stream );
                    return VLC_EGENERIC;
461
            }
462
            p_sys->i_video_bound++;
463
            break;
464

465
        case AUDIO_ES:
466
            switch( p_input->p_fmt->i_fourcc )
467
            {
468
469
470
471
472
                case VLC_FOURCC( 'm', 'p','g', 'a' ):
                    p_stream->i_stream_type = p_input->p_fmt->i_sample_rate >= 32000 ? 0x03 : 0x04;
                    p_stream->i_stream_id = p_sys->i_stream_id_mpga;
                    p_sys->i_stream_id_mpga++;
                    break;
473
474
                case VLC_FOURCC( 'a', '5','2', ' ' ):
                    p_stream->i_stream_type = 0x81;
475
                    p_stream->i_stream_id = 0xbd;
476
477
478
479
                    break;
                case VLC_FOURCC( 'm', 'p','4', 'a' ):
                    p_stream->i_stream_type = 0x11;
                    p_stream->i_stream_id = 0xfa;
480
                    p_sys->i_mpeg4_streams++;
481
                    p_stream->i_es_id = p_stream->i_pid;
482
483
                    break;
                default:
484
485
                    free( p_stream );
                    return VLC_EGENERIC;
486
            }
487
            p_sys->i_audio_bound++;
488
            break;
489

490
491
        case SPU_ES:
            switch( p_input->p_fmt->i_fourcc )
492
            {
493
494
495
496
497
498
499
                case VLC_FOURCC( 's', 'p','u', ' ' ):
                    p_stream->i_stream_type = 0x82;
                    p_stream->i_stream_id = 0x82;
                    break;
                default:
                    free( p_stream );
                    return VLC_EGENERIC;
500
            }
501
            break;
502

503
        default:
504
505
            free( p_stream );
            return VLC_EGENERIC;
506
507
    }

508
509
510
511
512
513
514
515
516
517
    /* Copy extra data (VOL for MPEG-4 and extra BitMapInfoHeader for VFW */
    p_stream->i_decoder_specific_info = p_input->p_fmt->i_extra_data;
    if( p_stream->i_decoder_specific_info > 0 )
    {
        p_stream->p_decoder_specific_info =
            malloc( p_stream->i_decoder_specific_info );
        memcpy( p_stream->p_decoder_specific_info,
                p_input->p_fmt->p_extra_data,
                p_input->p_fmt->i_extra_data );
    }
518
519
520
521
522
523

    /* Init pes chain */
    BufferChainInit( &p_stream->chain_pes );
    p_stream->i_pes_dts    = 0;
    p_stream->i_pes_length = 0;
    p_stream->i_pes_used   = 0;
524
525
526
527
528
529
530
531
532
533
534

    /* We only change PMT version (PAT isn't changed) */
    p_sys->i_pmt_version_number = ( p_sys->i_pmt_version_number + 1 )%32;

    /* Update pcr_pid */
    if( p_input->p_fmt->i_cat != SPU_ES &&
        ( p_sys->i_pcr_pid == 0x1fff || p_input->p_fmt->i_cat == VIDEO_ES ) )
    {
        if( p_sys->p_pcr_input )
        {
            /* There was already a PCR stream, so clean context */
535
            /* FIXME */
536
537
538
539
540
541
        }
        p_sys->i_pcr_pid   = p_stream->i_pid;
        p_sys->p_pcr_input = p_input;
    }

    return VLC_SUCCESS;
542
543
}

544
545
546
/*****************************************************************************
 * DelStream: called before a stream deletion
 *****************************************************************************/
547
static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
548
{
549
550
    sout_mux_sys_t  *p_sys = p_mux->p_sys;
    ts_stream_t     *p_stream;
551
    char            *val;
552

553
554
    msg_Dbg( p_mux, "removing input" );
    p_stream = (ts_stream_t*)p_input->p_sys;
555

556
557
558
559
560
561
    if( p_sys->i_pcr_pid == p_stream->i_pid )
    {
        int i;

        /* Find a new pcr stream (Prefer Video Stream) */
        p_sys->i_pcr_pid = 0x1fff;
562
        p_sys->p_pcr_input = NULL;
563
564
565
566
567
568
569
570
571
        for( i = 0; i < p_mux->i_nb_inputs; i++ )
        {
            if( p_mux->pp_inputs[i] == p_input )
            {
                continue;
            }

            if( p_mux->pp_inputs[i]->p_fmt->i_cat == VIDEO_ES )
            {
572
573
                p_sys->i_pcr_pid  =
                    ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid;
574
575
576
                p_sys->p_pcr_input= p_mux->pp_inputs[i];
                break;
            }
577
578
            else if( p_mux->pp_inputs[i]->p_fmt->i_cat != SPU_ES &&
                     p_sys->i_pcr_pid == 0x1fff )
579
            {
580
581
                p_sys->i_pcr_pid  =
                    ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid;
582
583
584
585
586
587
                p_sys->p_pcr_input= p_mux->pp_inputs[i];
            }
        }
        if( p_sys->p_pcr_input )
        {
            /* Empty TS buffer */
588
            /* FIXME */
589
590
591
        }
    }

592
593
594
    /* Empty all data in chain_pes */
    BufferChainClean( p_mux->p_sout, &p_stream->chain_pes );

595
596
597
598
599
600
    if( p_stream->p_decoder_specific_info )
    {
        free( p_stream->p_decoder_specific_info );
    }
    if( p_stream->i_stream_id == 0xfa || p_stream->i_stream_id == 0xfb )
    {
601
        p_sys->i_mpeg4_streams--;
602
    }
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "pid-video" ) ) )
    {
        int i_pid_video = strtol( val, NULL, 0 );
        if ( i_pid_video == p_stream->i_pid )
        {
            p_sys->i_pid_video = i_pid_video;
        }
    }
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "pid-audio" ) ) )
    {
        int i_pid_audio = strtol( val, NULL, 0 );
        if ( i_pid_audio == p_stream->i_pid )
        {
            p_sys->i_pid_audio = i_pid_audio;
        }
    }
Laurent Aimar's avatar
Laurent Aimar committed
619
620
    free( p_stream );

621
    /* We only change PMT version (PAT isn't changed) */
622
    p_sys->i_pmt_version_number++; p_sys->i_pmt_version_number %= 32;
623

624
    return VLC_SUCCESS;
625
626
}

627
628
629
630
631
632
633
634
/*****************************************************************************
 * Mux: Call each time there is new data for at least one stream
 *****************************************************************************
 *
 *****************************************************************************/
static int Mux( sout_mux_t *p_mux )
{
    sout_mux_sys_t  *p_sys = p_mux->p_sys;
635
    ts_stream_t     *p_pcr_stream;
636

637
638
639
640
641
642
    if( p_sys->i_pcr_pid == 0x1fff )
    {
        msg_Dbg( p_mux, "waiting PCR streams" );
        msleep( 1000 );
        return VLC_SUCCESS;
    }
643
    p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys;
644

645
    for( ;; )
646
    {
647
648
649
650
651
652
        sout_buffer_chain_t chain_ts;
        int                 i_packet_count;
        int                 i_packet_pos;
        mtime_t             i_pcr_dts;
        mtime_t             i_pcr_length;
        int i;
653

654
655
        /* 1: get enough PES packet for all input */
        for( ;; )
656
        {
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
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
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
            vlc_bool_t b_ok = VLC_TRUE;
            sout_buffer_t *p_data;

            /* Accumulate enough data in the pcr stream (>i_caching_delay) */
            /* Accumulate enough data in all other stream ( >= length of pcr) */
            for( i = 0; i < p_mux->i_nb_inputs; i++ )
            {
                sout_input_t *p_input = p_mux->pp_inputs[i];
                ts_stream_t *p_stream = (ts_stream_t*)p_input->p_sys;

                if( p_stream->i_pes_length <= p_sys->i_caching_delay ||
                    p_stream->i_pes_dts + p_stream->i_pes_length < p_pcr_stream->i_pes_dts + p_pcr_stream->i_pes_length )
                {
                    /* Need more data */
                    if( p_input->p_fifo->i_depth <= 1 )
                    {
                        if( p_input->p_fmt->i_cat == AUDIO_ES ||
                            p_input->p_fmt->i_cat == VIDEO_ES )
                        {
                            /* We need more data */
                            return VLC_SUCCESS;
                        }
                        else if( p_input->p_fifo->i_depth <= 0 )
                        {
                            /* spu, only one packet is needed */
                            continue;
                        }
                    }
                    b_ok = VLC_FALSE;

                    p_data = sout_FifoGet( p_input->p_fifo );

                    if( ( p_pcr_stream->i_pes_dts > 0 && p_data->i_dts - 2000000 > p_pcr_stream->i_pes_dts + p_pcr_stream->i_pes_length ) ||
                        p_data->i_dts < p_stream->i_pes_dts ||
                        ( p_stream->i_pes_dts > 0 && p_data->i_dts - 2000000 > p_stream->i_pes_dts + p_stream->i_pes_length ) )
                    {
                        msg_Warn( p_mux, "packet with too strange dts (dts=%lld,old=%lld,pcr=%lld)",
                                  p_data->i_dts,
                                  p_stream->i_pes_dts,
                                  p_pcr_stream->i_pes_dts );
                        sout_BufferDelete( p_mux->p_sout, p_data );

                        BufferChainClean( p_mux->p_sout, &p_stream->chain_pes );
                        p_stream->i_pes_dts = 0;
                        p_stream->i_pes_used = 0;
                        p_stream->i_pes_length = 0;

                        BufferChainClean( p_mux->p_sout, &p_pcr_stream->chain_pes );
                        p_pcr_stream->i_pes_dts = 0;
                        p_pcr_stream->i_pes_used = 0;
                        p_pcr_stream->i_pes_length = 0;

                    }
                    else
                    {
                        p_stream->i_pes_length += p_data->i_length;
                        if( p_stream->i_pes_dts == 0 )
                        {
                            p_stream->i_pes_dts = p_data->i_dts;
                        }

                        /* Convert to pes */
                        E_( EStoPES )( p_mux->p_sout, &p_data, p_data, p_stream->i_stream_id, 1 );

                        BufferChainAppend( &p_stream->chain_pes, p_data );
                    }
                }
            }

            if( b_ok )
            {
                break;
            }
730
        }
731

732
733
734
735
736
737
738
739
        /* save */
        i_pcr_dts      = p_pcr_stream->i_pes_dts;
        i_pcr_length   = p_pcr_stream->i_pes_length;

        /* msg_Dbg( p_mux, "starting muxing %lldms", i_pcr_length / 1000 ); */
        /* 2: calculate non accurate total size of muxed ts */
        i_packet_count = 0;
        for( i = 0; i < p_mux->i_nb_inputs; i++ )
740
        {
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
            ts_stream_t *p_stream = (ts_stream_t*)p_mux->pp_inputs[i]->p_sys;
            sout_buffer_t *p_pes;

            /* False for pcr stream but it will be eough to do PCR algo */
            for( p_pes = p_stream->chain_pes.p_first; p_pes != NULL; p_pes = p_pes->p_next )
            {
                int i_size = p_pes->i_size;
                if( p_pes->i_dts + p_pes->i_length > p_pcr_stream->i_pes_dts + p_pcr_stream->i_pes_length )
                {
                    mtime_t i_frag = p_pcr_stream->i_pes_dts + p_pcr_stream->i_pes_length - p_pes->i_dts;
                    if( i_frag < 0 )
                    {
                        /* Next stream */
                        break;
                    }
                    i_size = p_pes->i_size * i_frag / p_pes->i_length;
                }
                i_packet_count += ( i_size + 183 ) / 184;
            }
760
        }
761
762
763
764
765
766
767
768
769
770
771
772
        /* add overhead for PCR (not really exact) */
        i_packet_count += ( 8 * i_pcr_length / p_sys->i_pcr_delay + 175 ) / 176;


        /* 3: mux PES into TS */
        BufferChainInit( &chain_ts );
        /* append PAT/PMT  -> FIXME with big pcr delay it won't have enough pat/pmt */
        GetPAT( p_mux, &chain_ts);
        GetPMT( p_mux, &chain_ts );
        i_packet_pos = 0;
        i_packet_count += chain_ts.i_depth;
        /* msg_Dbg( p_mux, "estimated pck=%d", i_packet_count ); */
773

774
        for( ;; )
775
        {
776
777
778
779
780
            int         i_stream;
            mtime_t     i_dts;
            ts_stream_t *p_stream;
            sout_buffer_t *p_ts;
            vlc_bool_t   b_pcr;
781

782
783
            /* Select stream (lowest dts)*/
            for( i = 0, i_stream = -1, i_dts = 0; i < p_mux->i_nb_inputs; i++ )
784
            {
785
786
787
                p_stream = (ts_stream_t*)p_mux->pp_inputs[i]->p_sys;

                if( p_stream->i_pes_dts == 0 )
788
                {
789
                    continue;
790
                }
791
792
793

                if( i_stream == -1 ||
                    p_stream->i_pes_dts < i_dts )
794
                {
795
796
                    i_stream = i;
                    i_dts = p_stream->i_pes_dts;
797
798
                }
            }
799
800
801
802
803
            if( i_stream == -1 )
            {
                break;
            }
            p_stream = (ts_stream_t*)p_mux->pp_inputs[i_stream]->p_sys;
804

805
806
807
808
            /* do we need to issue pcr */
            b_pcr = VLC_FALSE;
            if( p_stream == p_pcr_stream &&
                i_pcr_dts + i_packet_pos * i_pcr_length / i_packet_count >= p_sys->i_pcr + p_sys->i_pcr_delay )
809
            {
810
811
                b_pcr = VLC_TRUE;
                p_sys->i_pcr = i_pcr_dts + i_packet_pos * i_pcr_length / i_packet_count;
812
            }
813

814
815
816
            /* Build the TS packet */
            p_ts = TSNew( p_mux, p_stream, b_pcr );
            i_packet_pos++;
817

818
819
820
            /* */
            BufferChainAppend( &chain_ts, p_ts );
        }
821

822
823
824
825
        /* 4: date and send */
        i_packet_count = chain_ts.i_depth;
        /* msg_Dbg( p_mux, "real pck=%d", i_packet_count ); */
        for( i = 0; i < i_packet_count; i++ )
826
        {
827
            sout_buffer_t *p_ts = BufferChainGet( &chain_ts );
828

829
830
            p_ts->i_dts    = i_pcr_dts + i_pcr_length * i / i_packet_count;
            p_ts->i_length = i_pcr_length / i_packet_count;
831

832
            if( p_ts->i_flags&SOUT_BUFFER_FLAGS_PRIVATE_PCR )
833
            {
834
                /* msg_Dbg( p_mux, "pcr=%lld ms", p_ts->i_dts / 1000 ); */
835
                TSSetPCR( p_ts, p_ts->i_dts - p_sys->i_dts_delay );
836
            }
837

838
839
            /* latency */
            p_ts->i_dts += 3*p_sys->i_caching_delay/2;
840

841
            sout_AccessOutWrite( p_mux->p_access, p_ts );
842
        }
843
    }
844
}
845

846
847
848
849
static sout_buffer_t *TSNew( sout_mux_t *p_mux, ts_stream_t *p_stream, vlc_bool_t b_pcr )
{
    sout_buffer_t *p_pes = p_stream->chain_pes.p_first;
    sout_buffer_t *p_ts;
850

851
852
    vlc_bool_t b_new_pes = VLC_FALSE;
    vlc_bool_t b_adaptation_field = VLC_FALSE;
853

854
855
856
857
858
859
860
861
    int        i_payload_max = 184 - ( b_pcr ? 8 : 0 );
    int        i_payload;

    if( p_stream->i_pes_used <= 0 )
    {
        b_new_pes = VLC_TRUE;
    }
    i_payload = __MIN( (int)p_pes->i_size - p_stream->i_pes_used, i_payload_max );
862

863
864
865
866
    if( b_pcr || i_payload < i_payload_max )
    {
        b_adaptation_field = VLC_TRUE;
    }
867

868
    p_ts = sout_BufferNew( p_mux->p_sout, 188 );
869

870
871
872
873
874
875
876
877
    p_ts->p_buffer[0] = 0x47;
    p_ts->p_buffer[1] = ( b_new_pes ? 0x40 : 0x00 )|( ( p_stream->i_pid >> 8 )&0x1f );
    p_ts->p_buffer[2] = p_stream->i_pid & 0xff;
    p_ts->p_buffer[3] = ( b_adaptation_field ? 0x30 : 0x10 )|p_stream->i_continuity_counter;

    p_stream->i_continuity_counter = (p_stream->i_continuity_counter+1)%16;

    if( b_adaptation_field )
878
    {
879
        int i;
880

881
        if( b_pcr )
882
        {
883
            int     i_stuffing = i_payload_max - i_payload;
884

885
            p_ts->i_flags |= SOUT_BUFFER_FLAGS_PRIVATE_PCR;
886

887
888
889
890
891
892
893
894
895
896
            p_ts->p_buffer[4] = 7 + i_stuffing;
            p_ts->p_buffer[5] = 0x10;   /* flags */
            p_ts->p_buffer[6] = ( 0 )&0xff;
            p_ts->p_buffer[7] = ( 0 )&0xff;
            p_ts->p_buffer[8] = ( 0 )&0xff;
            p_ts->p_buffer[9] = ( 0 )&0xff;
            p_ts->p_buffer[10]= ( 0 )&0x80;
            p_ts->p_buffer[11]= 0;

            for( i = 12; i < 12 + i_stuffing; i++ )
897
            {
898
                p_ts->p_buffer[i] = 0xff;
899
            }
900
901
902
903
904
905
906
        }
        else
        {
            int i_stuffing = i_payload_max - i_payload;

            p_ts->p_buffer[4] = i_stuffing - 1;
            if( i_stuffing > 1 )
907
            {
908
909
910
911
912
                p_ts->p_buffer[5] = 0x00;
                for( i = 6; i < 6 + i_stuffing - 2; i++ )
                {
                    p_ts->p_buffer[i] = 0xff;
                }
913
            }
914
        }
915
    }
916

917
918
    /* copy payload */
    memcpy( &p_ts->p_buffer[188 - i_payload], &p_pes->p_buffer[p_stream->i_pes_used], i_payload );
919

920
921
922
    p_stream->i_pes_used += i_payload;
    p_stream->i_pes_dts      = p_pes->i_dts + p_pes->i_length * p_stream->i_pes_used / p_pes->i_size;
    p_stream->i_pes_length  -= p_pes->i_length * i_payload / p_pes->i_size;
923

924
925
926
927
928
929
930
931
932
933
934
    if( p_stream->i_pes_used >= (int)p_pes->i_size )
    {
        p_pes = BufferChainGet( &p_stream->chain_pes );
        sout_BufferDelete( p_mux->p_sout, p_pes );

        p_pes = p_stream->chain_pes.p_first;
        if( p_pes )
        {
            p_stream->i_pes_dts    = p_pes->i_dts;
            p_stream->i_pes_length = 0;
            while( p_pes )
935
            {
936
937
938
                p_stream->i_pes_length += p_pes->i_length;

                p_pes = p_pes->p_next;
939
            }
940
        }
941
        else
942
        {
943
944
            p_stream->i_pes_dts = 0;
            p_stream->i_pes_length = 0;
945
        }
946
        p_stream->i_pes_used = 0;
947
948
    }

949
950
    return p_ts;
}
951
952


953
954
static void TSSetPCR( sout_buffer_t *p_ts, mtime_t i_dts )
{
955
    mtime_t i_pcr = 9 * i_dts / 100;
956

957
958
959
960
961
    p_ts->p_buffer[6]  = ( i_pcr >> 25 )&0xff;
    p_ts->p_buffer[7]  = ( i_pcr >> 17 )&0xff;
    p_ts->p_buffer[8]  = ( i_pcr >> 9  )&0xff;
    p_ts->p_buffer[9]  = ( i_pcr >> 1  )&0xff;
    p_ts->p_buffer[10]|= ( i_pcr << 7  )&0x80;
962
963
}

964
#if 0
965
static void TSSetConstraints( sout_mux_t *p_mux, sout_buffer_chain_t *c, mtime_t i_length, int i_bitrate_min, int i_bitrate_max )
966
{
967
968
969
970
971
972
    sout_mux_sys_t  *p_sys = p_mux->p_sys;
    sout_buffer_chain_t s = *c;

    int i_packets = 0;
    int i_packets_min = 0;
    int i_packets_max = 0;
973

974
    if( i_length <= 0 )
975
    {
976
        return;
977
978
    }

979
980
981
982
983
    i_packets     = c->i_depth;
    i_packets_min = ( (int64_t)i_bitrate_min * i_length / 8 / 1000000  + 187 ) / 188;
    i_packets_max = ( (int64_t)i_bitrate_max * i_length / 8 / 1000000  + 187 ) / 188;

    if( i_packets < i_packets_min && i_packets_min > 0 )
984
    {
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
        sout_buffer_t *p_pk;
        int i_div = ( i_packets_min - i_packets ) / i_packets;
        int i_mod = ( i_packets_min - i_packets ) % i_packets;
        int i_rest = 0;

        /* We need to pad with null packets (pid=0x1fff)
         * We try to melt null packets with true packets */
        msg_Dbg( p_mux,
                 "packets=%d but min=%d -> adding %d packets of padding",
                 i_packets, i_packets_min, i_packets_min - i_packets );

        BufferChainInit( c );
        while( ( p_pk = BufferChainGet( &s ) ) )
        {
            int i, i_null;

            BufferChainAppend( c, p_pk );

            i_null = i_div + ( i_rest + i_mod ) / i_packets;

            for( i = 0; i < i_null; i++ )
            {
                sout_buffer_t *p_null;

                p_null = sout_BufferNew( p_mux->p_sout, 188 );
                p_null->p_buffer[0] = 0x47;
                p_null->p_buffer[1] = 0x1f;
                p_null->p_buffer[2] = 0xff;
                p_null->p_buffer[3] = 0x10 | p_sys->i_null_continuity_counter;
                memset( &p_null->p_buffer[4], 0, 184 );
                p_sys->i_null_continuity_counter =
                    ( p_sys->i_null_continuity_counter + 1 ) % 16;

                BufferChainAppend( c, p_null );
            }
1020

1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
            i_rest = ( i_rest + i_mod ) % i_packets;
        }
    }
    else if( i_packets > i_packets_max && i_packets_max > 0 )
    {
        sout_buffer_t *p_pk;
        int           i;

        /* Arg, we need to drop packets, I don't do something clever (like
         * dropping complete pid, b frames, ... ), I just get the right amount
         * of packets and discard the others */
        msg_Warn( p_mux,
                  "packets=%d but max=%d -> removing %d packets -> stream broken",
                  i_packets, i_packets_max, i_packets - i_packets_max );

        BufferChainInit( c );
        for( i = 0; i < i_packets_max; i++ )
        {
            BufferChainAppend( c, BufferChainGet( &s ) );
        }

        while( ( p_pk = BufferChainGet( &s ) ) )
        {
            sout_BufferDelete( p_mux->p_sout, p_pk );
        }
1046
1047
    }
}
1048
#endif
1049

1050
1051
static void PEStoTS( sout_instance_t *p_sout,
                     sout_buffer_chain_t *c, sout_buffer_t *p_pes,
1052
                     ts_stream_t *p_stream )
1053
1054
1055
1056
{
    uint8_t *p_data;
    int     i_size;
    int     b_new_pes;
1057

1058
1059
1060
    /* get PES total size */
    i_size = p_pes->i_size;
    p_data = p_pes->p_buffer;
1061

1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
    b_new_pes = VLC_TRUE;

    for( ;; )
    {
        int           b_adaptation_field;
        int           i_copy;
        sout_buffer_t *p_ts;

        p_ts = sout_BufferNew( p_sout, 188 );
        /* write header
         * 8b   0x47    sync byte
         * 1b           transport_error_indicator
         * 1b           payload_unit_start
         * 1b           transport_priority
         * 13b          pid
         * 2b           transport_scrambling_control
         * 2b           if adaptation_field 0x03 else 0x01
         * 4b           continuity_counter
         */

1082
1083
        i_copy    = __MIN( i_size, 184 );
        b_adaptation_field = i_size < 184 ? VLC_TRUE : VLC_FALSE;
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095

        p_ts->p_buffer[0] = 0x47;
        p_ts->p_buffer[1] = ( b_new_pes ? 0x40 : 0x00 )|
                            ( ( p_stream->i_pid >> 8 )&0x1f );
        p_ts->p_buffer[2] = p_stream->i_pid & 0xff;
        p_ts->p_buffer[3] = ( b_adaptation_field ? 0x30 : 0x10 )|
                            p_stream->i_continuity_counter;

        b_new_pes = VLC_FALSE;
        p_stream->i_continuity_counter = (p_stream->i_continuity_counter+1)%16;

        if( b_adaptation_field )
1096
        {
1097
            int i_stuffing = 184 - i_copy;
1098
1099
            int i;

1100
1101
            p_ts->p_buffer[4] = i_stuffing - 1;
            if( i_stuffing > 1 )
1102
            {
1103
1104
                p_ts->p_buffer[5] = 0x00;
                for( i = 6; i < 6 + i_stuffing - 2; i++ )
1105
1106
1107
1108
                {
                    p_ts->p_buffer[i] = 0xff;
                }
            }
1109
        }
1110
1111
1112
1113
        /* copy payload */
        memcpy( &p_ts->p_buffer[188 - i_copy], p_data, i_copy );
        p_data += i_copy;
        i_size -= i_copy;
1114

1115
        BufferChainAppend( c, p_ts );
1116

1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
        if( i_size <= 0 )
        {
            sout_buffer_t *p_next = p_pes->p_next;

            p_pes->p_next = NULL;
            sout_BufferDelete( p_sout, p_pes );
            if( p_next == NULL )
            {
                break;
            }
            b_new_pes = VLC_TRUE;
            p_pes = p_next;
            i_size = p_pes->i_size;
            p_data = p_pes->p_buffer;
        }
1132
1133
    }

1134
    return;
1135
1136
}

gbazin's avatar
   
gbazin committed
1137
#if defined MODULE_NAME_IS_mux_ts
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
static uint32_t CalculateCRC( uint8_t *p_begin, int i_count )
{
    static uint32_t CRC32[256] =
    {
        0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
        0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
        0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
        0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
        0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
        0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
        0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
        0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
        0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
        0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
        0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
        0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
        0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
        0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
        0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
        0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
        0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
        0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
        0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
        0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
        0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
        0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
        0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
        0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
        0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
        0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
        0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
        0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
        0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
        0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
        0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
        0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
        0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
        0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
        0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
        0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
        0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
        0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
        0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
        0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
        0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
        0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
        0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
        0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
        0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
        0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
        0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
        0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
        0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
        0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
        0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
        0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
        0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
        0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
        0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
        0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
        0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
        0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
        0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
        0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
        0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
        0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
        0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
        0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
    };

    uint32_t i_crc = 0xffffffff;

    /* Calculate the CRC */
    while( i_count > 0 )
    {
        i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((uint32_t)*p_begin) ];
        p_begin++;
        i_count--;
    }

    return( i_crc );
}

1221
1222
static void GetPAT( sout_mux_t *p_mux,
                    sout_buffer_chain_t *c )
1223
{
1224
    sout_mux_sys_t      *p_sys = p_mux->p_sys;
1225
1226
1227
    sout_buffer_t       *p_pat;
    bits_buffer_t bits;

1228
    p_pat = sout_BufferNew( p_mux->p_sout, 1024 );
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239

    p_pat->i_pts = 0;
    p_pat->i_dts = 0;
    p_pat->i_length = 0;

    bits_initwrite( &bits, 1024, p_pat->p_buffer );

    bits_write( &bits, 8, 0 );      // pointer
    bits_write( &bits, 8, 0x00 );   // table id
    bits_write( &bits, 1,  1 );     // section_syntax_indicator
    bits_write( &bits, 1,  0 );     // 0
1240
    bits_write( &bits, 2,  0x03 );     // reserved FIXME