ts.c 87.9 KB
Newer Older
1
/*****************************************************************************
2
 * ts.c: MPEG-II TS Muxer
3
 *****************************************************************************
zorglub's avatar
zorglub committed
4
 * Copyright (C) 2001-2005 the VideoLAN team
5
 * $Id$
6
7
8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Eric Petit <titer@videolan.org>
9
 *          Jean-Paul Saman <jpsaman #_at_# m2x.nl>
10
 *          Wallace Wadge <wwadge #_at_# gmail.com>
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * 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
dionoea's avatar
dionoea committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25
26
27
28
29
30
31
32
33
34
35
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>

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

36
37
#include "iso_lang.h"

38
39
#include "bits.h"
#include "pes.h"
40
#include "csa.h"
41

42
43
#ifdef HAVE_DVBPSI_DR_H
#   include <dvbpsi/dvbpsi.h>
44
#   include <dvbpsi/demux.h>
45
46
47
#   include <dvbpsi/descriptor.h>
#   include <dvbpsi/pat.h>
#   include <dvbpsi/pmt.h>
48
#   include <dvbpsi/sdt.h>
49
50
51
52
#   include <dvbpsi/dr.h>
#   include <dvbpsi/psi.h>
#else
#   include "dvbpsi.h"
53
#   include "demux.h"
54
55
56
#   include "descriptor.h"
#   include "tables/pat.h"
#   include "tables/pmt.h"
57
#   include "tables/sdt.h"
58
59
#   include "descriptors/dr.h"
#   include "psi.h"
60
61
#endif

62
63
64
65
66
/*
 * TODO:
 *  - check PCR frequency requirement
 *  - check PAT/PMT  "        "
 *  - check PCR/PCR "soft"
67
68
 *  - check if "registration" descriptor : "AC-3" should be a program
 *    descriptor or an es one. (xine want an es one)
69
70
71
72
73
74
75
76
77
78
79
80
81
82
 *
 *  - 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 * );

zorglub's avatar
zorglub committed
83
#define VPID_TEXT N_("Video PID")
zorglub's avatar
zorglub committed
84
#define VPID_LONGTEXT N_("Assign a fixed PID to the video stream. The PCR " \
85
  "PID will automatically be the video.")
zorglub's avatar
zorglub committed
86
#define APID_TEXT N_("Audio PID")
zorglub's avatar
zorglub committed
87
#define APID_LONGTEXT N_("Assign a fixed PID to the audio stream.")
88
#define SPUPID_TEXT N_("SPU PID")
zorglub's avatar
zorglub committed
89
#define SPUPID_LONGTEXT N_("Assign a fixed PID to the SPU.")
90
#define PMTPID_TEXT N_("PMT PID")
zorglub's avatar
zorglub committed
91
#define PMTPID_LONGTEXT N_("Assign a fixed PID to the PMT")
92
#define TSID_TEXT N_("TS ID")
zorglub's avatar
zorglub committed
93
#define TSID_LONGTEXT N_("Assign a fixed Transport Stream ID.")
94
#define NETID_TEXT N_("NET ID")
zorglub's avatar
zorglub committed
95
96
97
98
99
100
#define NETID_LONGTEXT N_("Assign a fixed Network ID (for SDT table)")

#define PMTPROG_TEXT N_("PMT Program numbers")
#define PMTPROG_LONGTEXT N_("Assign a program number to each PMT. This " \
                            "requires \"Set PID to ID of ES\" to be enabled." )

101
#define MUXPMT_TEXT N_("Mux PMT (requires --sout-ts-es-id-pid)")
zorglub's avatar
zorglub committed
102
103
#define MUXPMT_LONGTEXT N_("Define the pids to add to each pmt. This " \
                           "requires \"Set PID to ID of ES\" to be enabled." )
104
105

#define SDTDESC_TEXT N_("SDT Descriptors (requires --sout-ts-es-id-pid)")
zorglub's avatar
zorglub committed
106
107
#define SDTDESC_LONGTEXT N_("Defines the descriptors of each SDT. This" \
                        "requires \"Set PID to ID of ES\" to be enabled." )
zorglub's avatar
zorglub committed
108

109
110
111
112
113
114
115
#define PID_TEXT N_("Set PID to ID of ES")
#define PID_LONGTEXT N_("Sets PID to the ID if the incoming ES. This is for " \
  "use with --ts-es-id-pid, and allows to have the same PIDs in the input " \
  "and output streams.")

#define ALIGNMENT_TEXT N_("Data alignment")
#define ALIGNMENT_LONGTEXT N_("Enforces alignment of all access units on " \
116
  "PES boundaries. Disabling this might save some bandwidth but introduce incompatibilities.")
117

zorglub's avatar
zorglub committed
118
#define SHAPING_TEXT N_("Shaping delay (ms)")
zorglub's avatar
zorglub committed
119
#define SHAPING_LONGTEXT N_("Cut the " \
120
  "stream in slices of the given duration, and ensure a constant bitrate " \
zorglub's avatar
zorglub committed
121
122
123
  "between the two boundaries. This avoids having huge bitrate peaks, " \
  "especially for reference frames." )

124
#define KEYF_TEXT N_("Use keyframes")
125
126
127
128
129
130
#define KEYF_LONGTEXT N_("If enabled, and shaping is specified, " \
  "the TS muxer will place the boundaries at the end of I pictures. In " \
  "that case, the shaping duration given by the user is a worse case " \
  "used when no reference frame is available. This enhances the efficiency " \
  "of the shaping algorithm, since I frames are usually the biggest " \
  "frames in the stream.")
zorglub's avatar
zorglub committed
131
132

#define PCR_TEXT N_("PCR delay (ms)")
zorglub's avatar
zorglub committed
133
134
135
#define PCR_LONGTEXT N_("Set at which interval " \
  "PCRs (Program Clock Reference) will be sent (in milliseconds). " \
  "This value should be below 100ms. (default is 70ms).")
zorglub's avatar
zorglub committed
136

137
138
139
140
141
142
#define BMIN_TEXT N_( "Minimum B (deprecated)")
#define BMIN_LONGTEXT N_( "This setting is deprecated and not used anymore" )

#define BMAX_TEXT N_( "Maximum B (deprecated)")
#define BMAX_LONGTEXT N_( "This setting is deprecated and not used anymore")

zorglub's avatar
zorglub committed
143
#define DTS_TEXT N_("DTS delay (ms)")
zorglub's avatar
zorglub committed
144
#define DTS_LONGTEXT N_("Delay the DTS (decoding time " \
145
146
147
  "stamps) and PTS (presentation timestamps) of the data in the " \
  "stream, compared to the PCRs. This allows for some buffering inside " \
  "the client decoder.")
zorglub's avatar
zorglub committed
148
149
150

#define ACRYPT_TEXT N_("Crypt audio")
#define ACRYPT_LONGTEXT N_("Crypt audio using CSA")
151
152
#define VCRYPT_TEXT N_("Crypt video")
#define VCRYPT_LONGTEXT N_("Crypt video using CSA")
zorglub's avatar
zorglub committed
153
154

#define CK_TEXT N_("CSA Key")
zorglub's avatar
zorglub committed
155
#define CK_LONGTEXT N_("CSA encryption key. This must be a " \
156
157
  "16 char string (8 hexadecimal bytes).")

158
#define CPKT_TEXT N_("Packet size in bytes to encrypt")
zorglub's avatar
Strings    
zorglub committed
159
/// \bug [String] Extra space
zorglub's avatar
zorglub committed
160
#define CPKT_LONGTEXT N_("Size of the TS packet to encrypt. " \
161
162
163
    "The encryption routines subtract the TS-header from the value before " \
    "encrypting. " )

164
#define SOUT_CFG_PREFIX "sout-ts-"
165
166
167
168
169
170
#ifdef HAVE_BSEARCH
#   define MAX_PMT 64       /* Maximum number of programs. FIXME: I just chose an arbitary number. Where is the maximum in the spec? */
#else
#   define MAX_PMT 1
#endif
#define MAX_PMT_PID 64       /* Maximum pids in each pmt.  FIXME: I just chose an arbitary number. Where is the maximum in the spec? */
171
172
173

vlc_module_begin();
    set_description( _("TS muxer (libdvbpsi)") );
zorglub's avatar
zorglub committed
174
    set_shortname( "MPEG-TS");
zorglub's avatar
zorglub committed
175
176
    set_category( CAT_SOUT );
    set_subcategory( SUBCAT_SOUT_MUX );
177
178
    set_capability( "sout mux", 120 );
    add_shortcut( "ts" );
zorglub's avatar
zorglub committed
179
180
181

    add_integer( SOUT_CFG_PREFIX "pid-video", 0, NULL,VPID_TEXT, VPID_LONGTEXT,
                                  VLC_TRUE );
182
183
    add_integer( SOUT_CFG_PREFIX "pid-audio", 0, NULL, APID_TEXT,
                 APID_LONGTEXT, VLC_TRUE );
184
185
    add_integer( SOUT_CFG_PREFIX "pid-spu", 0, NULL, SPUPID_TEXT,
                 SPUPID_LONGTEXT, VLC_TRUE );
186
187
    add_integer( SOUT_CFG_PREFIX "pid-pmt", 0, NULL, PMTPID_TEXT,
                 PMTPID_LONGTEXT, VLC_TRUE );
188
189
    add_integer( SOUT_CFG_PREFIX "tsid", 0, NULL, TSID_TEXT,
                 TSID_LONGTEXT, VLC_TRUE );
190
#ifdef HAVE_DVBPSI_SDT
191
192
    add_integer( SOUT_CFG_PREFIX "netid", 0, NULL, NETID_TEXT,
                 NETID_LONGTEXT, VLC_TRUE );
193
#endif
194
195
    add_string( SOUT_CFG_PREFIX "program-pmt", NULL, NULL, PMTPROG_TEXT,
                PMTPROG_LONGTEXT, VLC_TRUE );
196
197
    add_bool( SOUT_CFG_PREFIX "es-id-pid", 0, NULL, PID_TEXT, PID_LONGTEXT,
              VLC_TRUE );
198
    add_string( SOUT_CFG_PREFIX "muxpmt", NULL, NULL, MUXPMT_TEXT, MUXPMT_LONGTEXT, VLC_TRUE );
199
#ifdef HAVE_DVBPSI_SDT
200
    add_string( SOUT_CFG_PREFIX "sdtdesc", NULL, NULL, SDTDESC_TEXT, SDTDESC_LONGTEXT, VLC_TRUE );
201
#endif
202
    add_bool( SOUT_CFG_PREFIX "alignment", VLC_TRUE, NULL, ALIGNMENT_TEXT,
203
              ALIGNMENT_LONGTEXT, VLC_TRUE );
zorglub's avatar
zorglub committed
204
205

    add_integer( SOUT_CFG_PREFIX "shaping", 200, NULL,SHAPING_TEXT,
206
                 SHAPING_LONGTEXT, VLC_TRUE );
zorglub's avatar
zorglub committed
207
    add_bool( SOUT_CFG_PREFIX "use-key-frames", VLC_FALSE, NULL, KEYF_TEXT,
208
209
              KEYF_LONGTEXT, VLC_TRUE );

210
    add_integer( SOUT_CFG_PREFIX "pcr", 70, NULL, PCR_TEXT, PCR_LONGTEXT,
211
                 VLC_TRUE );
212
    add_integer( SOUT_CFG_PREFIX "bmin", 0, NULL, BMIN_TEXT, BMIN_LONGTEXT,
213
                 VLC_TRUE );
214
    add_integer( SOUT_CFG_PREFIX "bmax", 0, NULL, BMAX_TEXT, BMAX_LONGTEXT,
215
                 VLC_TRUE );
216
    add_integer( SOUT_CFG_PREFIX "dts-delay", 400, NULL, DTS_TEXT,
217
                 DTS_LONGTEXT, VLC_TRUE );
zorglub's avatar
zorglub committed
218
219

    add_bool( SOUT_CFG_PREFIX "crypt-audio", VLC_TRUE, NULL, ACRYPT_TEXT,
220
              ACRYPT_LONGTEXT, VLC_TRUE );
221
222
    add_bool( SOUT_CFG_PREFIX "crypt-video", VLC_TRUE, NULL, VCRYPT_TEXT,
              VCRYPT_LONGTEXT, VLC_TRUE );
zorglub's avatar
zorglub committed
223

224
225
    add_string( SOUT_CFG_PREFIX "csa-ck", NULL, NULL, CK_TEXT, CK_LONGTEXT,
                VLC_TRUE );
226
    add_integer( SOUT_CFG_PREFIX "csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, VLC_TRUE );
227

228
229
230
231
    set_callbacks( Open, Close );
vlc_module_end();

/*****************************************************************************
232
 * Local data structures
233
 *****************************************************************************/
234
static const char *ppsz_sout_options[] = {
235
    "pid-video", "pid-audio", "pid-spu", "pid-pmt", "tsid", "netid",
236
    "es-id-pid", "shaping", "pcr", "bmin", "bmax", "use-key-frames",
237
    "dts-delay", "csa-ck", "csa-pkt", "crypt-audio", "crypt-video",
238
    "muxpmt", "sdtdesc", "program-pmt", "alignment",
239
    NULL
240
241
};

242
243
244
245
246
247
248
249
typedef struct pmt_map_t   /* Holds the mapping between the pmt-pid/pmt table */
{
    int i_pid;
    unsigned long i_prog;
} pmt_map_t;

typedef struct sdt_desc_t
{
250
    char *psz_provider;
251
252
253
    char *psz_service_name;  /* name of program */
} sdt_desc_t;

254
255
typedef struct
{
256
    int     i_depth;
257
258
    block_t *p_first;
    block_t **pp_last;
259
260
261
262
263
264
265
266
} 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;
}
267

268
static inline void BufferChainAppend( sout_buffer_chain_t *c, block_t *b )
269
270
271
272
273
274
275
276
277
278
279
{
    *c->pp_last = b;
    c->i_depth++;

    while( b->p_next )
    {
        b = b->p_next;
        c->i_depth++;
    }
    c->pp_last = &b->p_next;
}
280

281
static inline block_t *BufferChainGet( sout_buffer_chain_t *c )
282
{
283
    block_t *b = c->p_first;
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

    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;
}
299

300
static inline block_t *BufferChainPeek( sout_buffer_chain_t *c )
301
{
302
    block_t *b = c->p_first;
303
304
305

    return b;
}
306

307
308
static inline void BufferChainClean( sout_instance_t *p_sout,
                                     sout_buffer_chain_t *c )
309
{
310
    block_t *b;
311
312
313

    while( ( b = BufferChainGet( c ) ) )
    {
314
        block_Release( b );
315
316
317
    }
    BufferChainInit( c );
}
318

319
typedef struct ts_stream_t
320
321
{
    int             i_pid;
322
323
    vlc_fourcc_t    i_codec;

324
325
326
    int             i_stream_type;
    int             i_stream_id;
    int             i_continuity_counter;
327
    vlc_bool_t      b_discontinuity;
328

329
330
331
332
    /* to be used for carriege of DIV3 */
    vlc_fourcc_t    i_bih_codec;
    int             i_bih_width, i_bih_height;

333
334
335
    /* Specific to mpeg4 in mpeg2ts */
    int             i_es_id;

336
    int             i_decoder_specific_info;
337
    uint8_t         *p_decoder_specific_info;
338

339
    /* language is iso639-2T */
340
341
    int             i_langs;
    uint8_t         *lang;
342

343
344
345
346
    sout_buffer_chain_t chain_pes;
    mtime_t             i_pes_dts;
    mtime_t             i_pes_length;
    int                 i_pes_used;
347
    vlc_bool_t          b_key_frame;
348

349
350
} ts_stream_t;

351
struct sout_mux_sys_t
352
353
{
    int             i_pcr_pid;
354
355
    sout_input_t    *p_pcr_input;

356
357
358
    int             i_audio_bound;
    int             i_video_bound;

359
    vlc_bool_t      b_es_id_pid;
360
    vlc_bool_t      b_sdt;
Christophe Massiot's avatar
Christophe Massiot committed
361
362
    int             i_pid_video;
    int             i_pid_audio;
363
    int             i_pid_spu;
364
    int             i_pid_free; /* first usable pid */
365

366
    int             i_tsid;
367
368
369
    int             i_netid;
    int             i_num_pmt;
    int             i_pmtslots;
370
371
372
373
    int             i_pat_version_number;
    ts_stream_t     pat;

    int             i_pmt_version_number;
374
    ts_stream_t     pmt[MAX_PMT];
375
376
377
    pmt_map_t       pmtmap[MAX_PMT_PID];
    int             i_pmt_program_number[MAX_PMT];
    sdt_desc_t      sdt_descriptors[MAX_PMT];
378
    vlc_bool_t      b_data_alignment;
379

380
381
    int             i_mpeg4_streams;

382
    int             i_null_continuity_counter;  /* Needed ? */
383
    ts_stream_t     sdt;
384
    dvbpsi_pmt_t    *dvbpmt;
385

386
387
388
    /* for TS building */
    int64_t             i_bitrate_min;
    int64_t             i_bitrate_max;
389

390
    int64_t             i_shaping_delay;
391
    int64_t             i_pcr_delay;
Laurent Aimar's avatar
Laurent Aimar committed
392

393
394
    int64_t             i_dts_delay;

395
396
    vlc_bool_t          b_use_key_frames;

397
    mtime_t             i_pcr;  /* last PCR emited */
398
399

    csa_t               *csa;
400
    int                 i_csa_pkt_size;
401
    vlc_bool_t          b_crypt_audio;
402
    vlc_bool_t          b_crypt_video;
403
};
404

405
/* Reserve a pid and return it */
Christophe Massiot's avatar
Christophe Massiot committed
406
static int  AllocatePID( sout_mux_sys_t *p_sys, int i_cat )
407
{
Christophe Massiot's avatar
Christophe Massiot committed
408
409
410
411
412
413
414
415
416
417
418
    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;
    }
419
420
421
422
423
    else if ( i_cat == SPU_ES && p_sys->i_pid_spu )
    {
        i_pid = p_sys->i_pid_spu;
        p_sys->i_pid_spu = 0;
    }
Christophe Massiot's avatar
Christophe Massiot committed
424
425
426
427
428
    else
    {
        i_pid = ++p_sys->i_pid_free;
    }
    return i_pid;
429
430
}

431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
static int pmtcompare( const void *pa, const void *pb )
{
    if ( ((pmt_map_t *)pa)->i_pid  < ((pmt_map_t *)pb)->i_pid )
        return -1;
    else if ( ((pmt_map_t *)pa)->i_pid  > ((pmt_map_t *)pb)->i_pid )
        return 1;
    else
        return 0;
}

static int intcompare( const void *pa, const void *pb )
{
    if ( *(int *)pa  < *(int *)pb )
        return -1;
    else if ( *(int *)pa > *(int *)pb )
        return 1;
    else
        return 0;
}

451
452
453
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
454
455
456
457
static int Control  ( sout_mux_t *, int, va_list );
static int AddStream( sout_mux_t *, sout_input_t * );
static int DelStream( sout_mux_t *, sout_input_t * );
static int Mux      ( sout_mux_t * );
458

459
static block_t *FixPES( sout_mux_t *p_mux, block_fifo_t *p_fifo );
460
461
462
463
static void TSSchedule  ( sout_mux_t *p_mux, sout_buffer_chain_t *p_chain_ts,
                          mtime_t i_pcr_length, mtime_t i_pcr_dts );
static void TSDate      ( sout_mux_t *p_mux, sout_buffer_chain_t *p_chain_ts,
                          mtime_t i_pcr_length, mtime_t i_pcr_dts );
464
465
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 );
466

467
468
static block_t *TSNew( sout_mux_t *p_mux, ts_stream_t *p_stream, vlc_bool_t b_pcr );
static void TSSetPCR( block_t *p_ts, mtime_t i_dts );
469

470
static void PEStoTS  ( sout_instance_t *, sout_buffer_chain_t *, block_t *, ts_stream_t * );
471

472
473
474
475
476
/*****************************************************************************
 * Open:
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
477
    sout_mux_t          *p_mux =(sout_mux_t*)p_this;
478
    sout_mux_sys_t      *p_sys = NULL;
479
    vlc_value_t         val;
480
    int i;
481

482
    config_ChainParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
483

484
    p_sys = malloc( sizeof( sout_mux_sys_t ) );
485
486
    if( !p_sys )
        return VLC_ENOMEM;
487
488
489
490
    p_sys->i_pmtslots = p_sys->b_sdt = 0;
    p_sys->i_num_pmt = 1;
    p_sys->dvbpmt = NULL;
    memset( &p_sys->pmtmap, 0, sizeof(p_sys->pmtmap) );
491

492
    p_mux->pf_control   = Control;
493
494
495
496
    p_mux->pf_addstream = AddStream;
    p_mux->pf_delstream = DelStream;
    p_mux->pf_mux       = Mux;
    p_mux->p_sys        = p_sys;
497

498
    srand( (uint32_t)mdate() );
499
500
501
502
    for ( i = 0; i < MAX_PMT; i++ )
        p_sys->sdt_descriptors[i].psz_service_name
            = p_sys->sdt_descriptors[i].psz_provider = NULL;
    memset( p_sys->sdt_descriptors, 0, sizeof(sdt_desc_t) );
503

504
505
    p_sys->i_audio_bound = 0;
    p_sys->i_video_bound = 0;
506

507
508
509
510
    var_Get( p_mux, SOUT_CFG_PREFIX "es-id-pid", &val );
    p_sys->b_es_id_pid = val.b_bool;

    var_Get( p_mux, SOUT_CFG_PREFIX "muxpmt", &val );
511
    /*
512
513
514
515
516
517
518
519
520
521
522
523
524
       fetch string of pmts. Here's a sample: --sout-ts-muxpmt="0x451,0x200,0x28a,0x240,,0x450,0x201,0x28b,0x241,,0x452,0x202,0x28c,0x242"
       This would mean 0x451, 0x200, 0x28a, 0x240 would fall under one pmt (program), 0x450,0x201,0x28b,0x241 would fall under another
    */
    if( val.psz_string != NULL && *val.psz_string )
    {
        char *psz_next;
        char *psz = val.psz_string;
        uint16_t i_pid;
        psz_next = psz;

        while( psz != NULL )
        {
            i_pid = strtoul( psz, &psz_next, 0 );
525

526
527
528
            if ( strlen(psz_next) > 0 )
                psz = &psz_next[1];
            if ( i_pid == 0 )
529
            {
530
531
532
533
534
535
536
537
                p_sys->i_num_pmt++;
                if ( p_sys->i_num_pmt > MAX_PMT )
                {
                    msg_Err( p_mux,
             "Number of PMTs greater than compiled maximum (%d)", MAX_PMT );
                    p_sys->i_num_pmt = MAX_PMT;
                }
            }
538
            else
539
540
541
542
543
544
545
546
547
548
549
550
            {
                p_sys->pmtmap[p_sys->i_pmtslots].i_pid = i_pid;
                p_sys->pmtmap[p_sys->i_pmtslots].i_prog = p_sys->i_num_pmt - 1;
                p_sys->i_pmtslots++;
                if ( p_sys->i_pmtslots > MAX_PMT_PID )
                {
                    msg_Err( p_mux,
             "Number of pids in PMT greater than compiled maximum (%d)",
                             MAX_PMT_PID );
                    p_sys->i_pmtslots = MAX_PMT_PID;
                }
            }
551

552
553
554
            /* Now sort according to pids for fast search later on */
            qsort( (void *)p_sys->pmtmap, p_sys->i_pmtslots,
                   sizeof(pmt_map_t), &pmtcompare );
555
            if ( !*psz_next )
556
557
558
559
560
                psz = NULL;
        }
    }
    if( val.psz_string != NULL) free( val.psz_string );

561
562
563
    p_sys->i_pat_version_number = rand() % 32;
    p_sys->pat.i_pid = 0;
    p_sys->pat.i_continuity_counter = 0;
564
    p_sys->pat.b_discontinuity = VLC_FALSE;
565

566
567
568
569
570
    var_Get( p_mux, SOUT_CFG_PREFIX "tsid", &val );
    if ( val.i_int )
        p_sys->i_tsid = val.i_int;
    else
        p_sys->i_tsid = rand() % 65536;
571
572
573

    p_sys->i_netid = rand() % 65536;
#ifdef HAVE_DVBPSI_SDT
574
575
576
    var_Get( p_mux, SOUT_CFG_PREFIX "netid", &val );
    if ( val.i_int )
        p_sys->i_netid = val.i_int;
577
#endif
578

579
    p_sys->i_pmt_version_number = rand() % 32;
580
    for( i = 0; i < p_sys->i_num_pmt; i++ )
581
    {
582
        p_sys->pmt[i].i_continuity_counter = 0;
583
584
585
586
587
588
        p_sys->pmt[i].b_discontinuity = VLC_FALSE;
    }

    p_sys->sdt.i_pid = 0x11;
    p_sys->sdt.i_continuity_counter = 0;
    p_sys->sdt.b_discontinuity = VLC_FALSE;
589

590
#ifdef HAVE_DVBPSI_SDT
591
592
    var_Get( p_mux, SOUT_CFG_PREFIX "sdtdesc", &val );
    p_sys->b_sdt = val.psz_string && *val.psz_string ? VLC_TRUE : VLC_FALSE;
593

594
    /* Syntax is provider_sdt1,service_name_sdt1,provider_sdt2,service_name_sdt2... */
595
    if( p_sys->b_sdt )
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
    {

        char *psz = val.psz_string;
        char *psz_sdttoken = psz;

        i = 0;
        while ( psz_sdttoken != NULL )
        {
            char *psz_end = strchr( psz_sdttoken, ',' );
            if( psz_end != NULL )
            {
                *psz_end++ = '\0';
            }
            if ( !(i % 2) )
            {
                p_sys->sdt_descriptors[i/2].psz_provider
                    = strdup(psz_sdttoken);
            }
            else
            {
                p_sys->sdt_descriptors[i/2].psz_service_name
617
                    = strdup(psz_sdttoken);
618
619
620
621
622
623
624
            }

            i++;
            psz_sdttoken = psz_end;
        }
    }
    if( val.psz_string != NULL ) free( val.psz_string );
625
626
627
#else
    p_sys->b_sdt = VLC_FALSE;
#endif
628

629
630
631
    var_Get( p_mux, SOUT_CFG_PREFIX "alignment", &val );
    p_sys->b_data_alignment = val.b_bool;

632
    var_Get( p_mux, SOUT_CFG_PREFIX "program-pmt", &val );
633
    if( val.psz_string && *val.psz_string )
634
    {
635
636
637
638
639
640
641
642
643
644
645
646
647
        char *psz_next;
        char *psz = val.psz_string;
        uint16_t i_pid;

        psz_next = psz;
        i = 0;
        while ( psz != NULL )
        {
            i_pid = strtoul( psz, &psz_next, 0 );
            if( strlen(psz_next) > 0 )
                psz = &psz_next[1];
            else
                psz = NULL;
648

649
            if( i_pid == 0 )
650
            {
651
652
653
654
655
656
657
658
659
660
                if( i > MAX_PMT )
                    msg_Err( p_mux, "Number of PMTs > maximum (%d)",
                             MAX_PMT );
            }
            else
            {
                p_sys->i_pmt_program_number[i] = i_pid;
                i++;
            }
        }
661
662
663
    }
    else
    {
664
665
666
        /* Option not specified, use 1, 2, 3... */
        for( i = 0; i < p_sys->i_num_pmt; i++ )
            p_sys->i_pmt_program_number[i] = i + 1;
667
    }
668
    if( val.psz_string != NULL ) free( val.psz_string );
669

670
    var_Get( p_mux, SOUT_CFG_PREFIX "pid-pmt", &val );
671
    if( val.i_int )
672
    {
673
674
        for( i = 0; i < p_sys->i_num_pmt; i++ )
            p_sys->pmt[i].i_pid = val.i_int + i; /* Does this make any sense? */
675
676
677
    }
    else
    {
678
        for( i = 0; i < p_sys->i_num_pmt; i++ )
679
            p_sys->pmt[i].i_pid = 0x42 + i;
680
681
    }

682
    p_sys->i_pid_free = p_sys->pmt[p_sys->i_num_pmt - 1].i_pid + 1;
683

684
685
686
    var_Get( p_mux, SOUT_CFG_PREFIX "pid-video", &val );
    p_sys->i_pid_video = val.i_int;
    if ( p_sys->i_pid_video > p_sys->i_pid_free )
Christophe Massiot's avatar
Christophe Massiot committed
687
    {
688
        p_sys->i_pid_free = p_sys->i_pid_video + 1;
Christophe Massiot's avatar
Christophe Massiot committed
689
    }
690
691
692
693

    var_Get( p_mux, SOUT_CFG_PREFIX "pid-audio", &val );
    p_sys->i_pid_audio = val.i_int;
    if ( p_sys->i_pid_audio > p_sys->i_pid_free )
Christophe Massiot's avatar
Christophe Massiot committed
694
    {
695
        p_sys->i_pid_free = p_sys->i_pid_audio + 1;
Christophe Massiot's avatar
Christophe Massiot committed
696
697
    }

698
699
700
701
702
703
704
    var_Get( p_mux, SOUT_CFG_PREFIX "pid-spu", &val );
    p_sys->i_pid_spu = val.i_int;
    if ( p_sys->i_pid_spu > p_sys->i_pid_free )
    {
        p_sys->i_pid_free = p_sys->i_pid_spu + 1;
    }

705
    p_sys->i_pcr_pid = 0x1fff;
706
    p_sys->p_pcr_input = NULL;
707

708
    p_sys->i_mpeg4_streams = 0;
709

710
711
712
    p_sys->i_null_continuity_counter = 0;

    /* Allow to create constrained stream */
713
    var_Get( p_mux, SOUT_CFG_PREFIX "bmin", &val );
714
    p_sys->i_bitrate_min = val.i_int;
715
716

    var_Get( p_mux, SOUT_CFG_PREFIX "bmax", &val );
717
    p_sys->i_bitrate_max = val.i_int;
718

719
720
721
    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
722
723
        msg_Err( p_mux, "incompatible minimum and maximum bitrate, "
                 "disabling bitrate control" );
724
725
726
        p_sys->i_bitrate_min = 0;
        p_sys->i_bitrate_max = 0;
    }
727
    if( p_sys->i_bitrate_min > 0 || p_sys->i_bitrate_max > 0 )
728
    {
729
730
        msg_Err( p_mux, "bmin and bmax no more supported "
                 "(if you need them report it)" );
731
732
    }

733
734
735
    var_Get( p_mux, SOUT_CFG_PREFIX "shaping", &val );
    p_sys->i_shaping_delay = (int64_t)val.i_int * 1000;
    if( p_sys->i_shaping_delay <= 0 )
736
    {
737
        msg_Err( p_mux,
738
                 "invalid shaping ("I64Fd"ms) resetting to 200ms",
739
740
                 p_sys->i_shaping_delay / 1000 );
        p_sys->i_shaping_delay = 200000;
741
    }
gbazin's avatar
   
gbazin committed
742

743
744
745
746
    var_Get( p_mux, SOUT_CFG_PREFIX "pcr", &val );
    p_sys->i_pcr_delay = (int64_t)val.i_int * 1000;
    if( p_sys->i_pcr_delay <= 0 ||
        p_sys->i_pcr_delay >= p_sys->i_shaping_delay )
747
    {
748
        msg_Err( p_mux,
749
                 "invalid pcr delay ("I64Fd"ms) resetting to 70ms",
750
                 p_sys->i_pcr_delay / 1000 );
751
        p_sys->i_pcr_delay = 70000;
752
753
    }

754
755
756
    var_Get( p_mux, SOUT_CFG_PREFIX "dts-delay", &val );
    p_sys->i_dts_delay = (int64_t)val.i_int * 1000;

757
758
759
    msg_Dbg( p_mux, "shaping="I64Fd" pcr="I64Fd" dts_delay="I64Fd,
             p_sys->i_shaping_delay, p_sys->i_pcr_delay, p_sys->i_dts_delay );

760
761
762
    var_Get( p_mux, SOUT_CFG_PREFIX "use-key-frames", &val );
    p_sys->b_use_key_frames = val.b_bool;

Christophe Massiot's avatar
Christophe Massiot committed
763
    /* for TS generation */
764
    p_sys->i_pcr    = 0;
765
766

    p_sys->csa      = NULL;
767
    var_Get( p_mux, SOUT_CFG_PREFIX "csa-ck", &val );
768
    if( val.psz_string && *val.psz_string )
769
    {
770
771
        char *psz = val.psz_string;

772
        /* skip 0x */
773
        if( psz[0] == '0' && ( psz[1] == 'x' || psz[1] == 'X' ) )
774
        {
775
            psz += 2;
776
        }
777
        if( strlen( psz ) != 16 )
778
779
780
781
782
        {
            msg_Dbg( p_mux, "invalid csa ck (it must be 16 chars long)" );
        }
        else
        {
783
            uint64_t i_ck = strtoull( psz, NULL, 16 );
gbazin's avatar
gbazin committed
784
785
786
            uint8_t  ck[8];
            int      i;

787
788
789
790
            for( i = 0; i < 8; i++ )
            {
                ck[i] = ( i_ck >> ( 56 - 8*i) )&0xff;
            }
791
#ifndef TS_NO_CSA_CK_MSG
792
793
            msg_Dbg( p_mux, "using CSA scrambling with ck=%x:%x:%x:%x:%x:%x:%x:%x",
                     ck[0], ck[1], ck[2], ck[3], ck[4], ck[5], ck[6], ck[7] );
794
#endif
795
            p_sys->csa = csa_New();
796
797
            if( p_sys->csa )
            {
798
                vlc_value_t pkt_val;
799
800
801

                csa_SetCW( p_sys->csa, ck, ck );

802
803
                var_Get( p_mux, SOUT_CFG_PREFIX "csa-pkt", &pkt_val );
                if( pkt_val.i_int < 12 || pkt_val.i_int > 188 )
804
                {
805
                    msg_Err( p_mux, "wrong packet size %d specified.", pkt_val.i_int );
806
807
808
                    msg_Warn( p_mux, "using default packet size of 188 bytes" );
                    p_sys->i_csa_pkt_size = 188;
                }
809
                else p_sys->i_csa_pkt_size = pkt_val.i_int;
810
                msg_Dbg( p_mux, "encrypting %d bytes of packet", p_sys->i_csa_pkt_size );
811
            }
812
813
        }
    }
814
815
816
817
    if( val.psz_string ) free( val.psz_string );

    var_Get( p_mux, SOUT_CFG_PREFIX "crypt-audio", &val );
    p_sys->b_crypt_audio = val.b_bool;
818

819
820
821
    var_Get( p_mux, SOUT_CFG_PREFIX "crypt-video", &val );
    p_sys->b_crypt_video = val.b_bool;

822
823
824
825
826
827
828
829
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
830
831
    sout_mux_t          *p_mux = (sout_mux_t*)p_this;
    sout_mux_sys_t      *p_sys = p_mux->p_sys;
832
    int i;
833

834
835
836
837
    if( p_sys->csa )
    {
        csa_Delete( p_sys->csa );
    }
838
839
840
841
842
843
844
845
846
847
    for( i = 0; i < MAX_PMT; i++ )
    {
        if( p_sys->sdt_descriptors[i].psz_service_name != NULL )
            free( p_sys->sdt_descriptors[i].psz_service_name );
        if( p_sys->sdt_descriptors[i].psz_provider != NULL )
            free( p_sys->sdt_descriptors[i].psz_provider );
    }

    if( p_sys->dvbpmt != NULL )  /* safety */
        free ( p_sys->dvbpmt );
848

849
    free( p_sys );
850
851
}

852
/*****************************************************************************
853
 * Control:
854
 *****************************************************************************/
855
static int Control( sout_mux_t *p_mux, int i_query, va_list args )
856
{
857
858
859
    vlc_bool_t *pb_bool;
    char **ppsz;

860
861
   switch( i_query )
   {
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
       case MUX_CAN_ADD_STREAM_WHILE_MUXING:
           pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
           *pb_bool = VLC_TRUE;
           return VLC_SUCCESS;

       case MUX_GET_ADD_STREAM_WAIT:
           pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
           *pb_bool = VLC_FALSE;
           return VLC_SUCCESS;

       case MUX_GET_MIME:
           ppsz = (char**)va_arg( args, char ** );
           *ppsz = strdup( "video/mpeg" );  /* FIXME not sure */
           return VLC_SUCCESS;

877
        default:
878
            return VLC_EGENERIC;
879
880
   }
}
881

882
883
884
/*****************************************************************************
 * AddStream: called for each stream addition
 *****************************************************************************/
885
static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
886
{
887
    sout_mux_sys_t      *p_sys = p_mux->p_sys;
888
    ts_stream_t         *p_stream;
889
    int                  i;
890

Laurent Aimar's avatar
Laurent Aimar committed
891
    p_input->p_sys = p_stream = malloc( sizeof( ts_stream_t ) );
892

893
    /* Init this new stream */
894
895
896
897
    if ( p_sys->b_es_id_pid )
        p_stream->i_pid = p_input->p_fmt->i_id & 0x1fff;
    else
        p_stream->i_pid = AllocatePID( p_sys, p_input->p_fmt->i_cat );
898
    p_stream->i_codec = p_input->p_fmt->i_codec;
899
    p_stream->i_continuity_counter    = 0;
900
    p_stream->b_discontinuity         = VLC_FALSE;
901
902
    p_stream->i_decoder_specific_info = 0;
    p_stream->p_decoder_specific_info = NULL;
903

904
905
    msg_Dbg( p_mux, "adding input codec=%4.4s pid=%d",
             (char*)&p_input->p_fmt->i_codec, p_stream->i_pid );
906

907
    /* All others fields depand on codec */
908
    switch( p_input->p_fmt->i_cat )
909
910
    {
        case VIDEO_ES:
911
            switch( p_input->p_fmt->i_codec )
912
913
            {
                case VLC_FOURCC( 'm', 'p','g', 'v' ):
914
                    /* TODO: do we need to check MPEG-I/II ? */
915
                    p_stream->i_stream_type = 0x02;
916
                    p_stream->i_stream_id = 0xe0;
917
918
919
                    break;
                case VLC_FOURCC( 'm', 'p','4', 'v' ):
                    p_stream->i_stream_type = 0x10;
920
                    p_stream->i_stream_id = 0xe0;
921
                    p_stream->i_es_id = p_stream->i_pid;
922
                    break;
923
924
925
926
                case VLC_FOURCC( 'h', '2','6', '4' ):
                    p_stream->i_stream_type = 0x1b;
                    p_stream->i_stream_id = 0xe0;
                    break;
927
928
                /* XXX dirty dirty but somebody want that:
                 *     using crapy MS-codec XXX */
929
930
931
                /* I didn't want to do that :P */
                case VLC_FOURCC( 'H', '2', '6', '3' ):
                case VLC_FOURCC( 'I', '2', '6', '3' ):
932
                case VLC_FOURCC( 'W', 'M', 'V', '3' ):
933
                case VLC_FOURCC( 'W', 'M', 'V', '2' ):
934
935
936
937
                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' ):
938
                case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
939
940
                    p_stream->i_stream_type = 0xa0; /* private */
                    p_stream->i_stream_id = 0xa0;   /* beurk */