ts.c 128 KB
Newer Older
1 2 3
/*****************************************************************************
 * ts.c: Transport Stream input module for VLC.
 *****************************************************************************
Clément Stenac's avatar
Clément Stenac committed
4
 * Copyright (C) 2004-2005 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Jean-Paul Saman <jpsaman #_at_# m2x.nl>
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24 25 26 27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
28

29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc_common.h>
34
#include <vlc_plugin.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
35

36
#include <assert.h>
37

38
#include <vlc_access.h>    /* DVB-specific things */
Clément Stenac's avatar
Clément Stenac committed
39 40
#include <vlc_demux.h>
#include <vlc_meta.h>
41
#include <vlc_epg.h>
42
#include <vlc_charset.h>   /* FromCharset, for EIT */
43

44
#include <vlc_network.h>   /* net_ for ts-out mode */
45

46 47
#include "../mux/mpeg/csa.h"

48
/* Include dvbpsi headers */
49 50 51 52 53 54 55 56
# include <dvbpsi/dvbpsi.h>
# include <dvbpsi/demux.h>
# include <dvbpsi/descriptor.h>
# include <dvbpsi/pat.h>
# include <dvbpsi/pmt.h>
# include <dvbpsi/sdt.h>
# include <dvbpsi/dr.h>
# include <dvbpsi/psi.h>
57

58
/* EIT support */
59
# include <dvbpsi/eit.h>
60 61

/* TDT support */
62
# include <dvbpsi/tot.h>
63

64
#undef TS_DEBUG
65 66 67 68 69 70 71 72 73 74 75
static void ts_debug(const char *format, ...)
{
#ifdef TS_DEBUG
    va_list ap;
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
#else
    (void)format;
#endif
}
76

77 78 79
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
80 81
static int  Open  ( vlc_object_t * );
static void Close ( vlc_object_t * );
82

83 84 85
/* TODO
 * - Rename "extra pmt" to "user pmt"
 * - Update extra pmt description
86
 *      pmt_pid[:pmt_number][=pid_description[,pid_description]]
87 88 89
 *      where pid_description could take 3 forms:
 *          1. pid:pcr (to force the pcr pid)
 *          2. pid:stream_type
90
 *          3. pid:type=fourcc where type=(video|audio|spu)
91
 */
92 93
#define PMT_TEXT N_("Extra PMT")
#define PMT_LONGTEXT N_( \
94
  "Allows a user to specify an extra pmt (pmt_pid=pid:stream_type[,...])." )
95 96

#define PID_TEXT N_("Set id of ES to PID")
97 98 99 100
#define PID_LONGTEXT N_("Set the internal ID of each elementary stream" \
                       " handled by VLC to the same value as the PID in" \
                       " the TS stream, instead of 1, 2, 3, etc. Useful to" \
                       " do \'#duplicate{..., select=\"es=<pid>\"}\'.")
101 102 103

#define TSOUT_TEXT N_("Fast udp streaming")
#define TSOUT_LONGTEXT N_( \
104
  "Sends TS to specific ip:port by udp (you must know what you are doing).")
105 106

#define MTUOUT_TEXT N_("MTU for out mode")
107
#define MTUOUT_LONGTEXT N_("MTU for out mode.")
108

109 110 111
#define CSA_TEXT N_("CSA Key")
#define CSA_LONGTEXT N_("CSA encryption key. This must be a " \
  "16 char string (8 hexadecimal bytes).")
112

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
113 114 115 116
#define CSA2_TEXT N_("Second CSA Key")
#define CSA2_LONGTEXT N_("The even CSA encryption key. This must be a " \
  "16 char string (8 hexadecimal bytes).")

117
#define SILENT_TEXT N_("Silent mode")
118
#define SILENT_LONGTEXT N_("Do not complain on encrypted PES.")
119

120
#define CAPMT_SYSID_TEXT N_("CAPMT System ID")
121
#define CAPMT_SYSID_LONGTEXT N_("Only forward descriptors from this SysID to the CAM.")
122

123 124 125 126 127
#define CPKT_TEXT N_("Packet size in bytes to decrypt")
#define CPKT_LONGTEXT N_("Specify the size of the TS packet to decrypt. " \
    "The decryption routines subtract the TS-header from the value before " \
    "decrypting. " )

128 129
#define SPLIT_ES_TEXT N_("Separate sub-streams")
#define SPLIT_ES_LONGTEXT N_( \
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
130
    "Separate teletex/dvbs pages into independent ES. " \
Rémi Denis-Courmont's avatar
Typos  
Rémi Denis-Courmont committed
131
    "It can be useful to turn off this option when using stream output." )
132

133 134 135
#define SEEK_PERCENT_TEXT N_("Seek based on percent not time")
#define SEEK_PERCENT_LONGTEXT N_( \
    "Seek and position based on a percent byte position, not a PCR generated " \
136
    "time position. If seeking doesn't work property, turn on this option." )
137 138


139 140 141 142 143 144
vlc_module_begin ()
    set_description( N_("MPEG Transport Stream demuxer") )
    set_shortname ( "MPEG-TS" )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )

145
    add_string( "ts-extra-pmt", NULL, PMT_TEXT, PMT_LONGTEXT, true )
146
    add_bool( "ts-es-id-pid", true, PID_TEXT, PID_LONGTEXT, true )
147
        change_safe()
148
    add_string( "ts-out", NULL, TSOUT_TEXT, TSOUT_LONGTEXT, true )
149
    add_integer( "ts-out-mtu", 1400, MTUOUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
150
                 MTUOUT_LONGTEXT, true )
151

152
    add_string( "ts-csa-ck", NULL, CSA_TEXT, CSA_LONGTEXT, true )
153
        change_safe()
154
    add_string( "ts-csa2-ck", NULL, CSA2_TEXT, CSA2_LONGTEXT, true )
155
        change_safe()
156
    add_integer( "ts-csa-pkt", 188, CPKT_TEXT, CPKT_LONGTEXT, true )
157 158
        change_safe()

159
    add_bool( "ts-silent", false, SILENT_TEXT, SILENT_LONGTEXT, true )
160

161
    add_bool( "ts-split-es", true, SPLIT_ES_TEXT, SPLIT_ES_LONGTEXT, false )
162
    add_bool( "ts-seek-percent", false, SEEK_PERCENT_TEXT, SEEK_PERCENT_LONGTEXT, true )
163

164 165 166 167
    set_capability( "demux", 10 )
    set_callbacks( Open, Close )
    add_shortcut( "ts" )
vlc_module_end ()
168 169 170 171

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
172 173 174 175
static const char *const ppsz_teletext_type[] = {
 "",
 N_("Teletext"),
 N_("Teletext subtitles"),
176 177 178
 N_("Teletext: additional information"),
 N_("Teletext: program schedule"),
 N_("Teletext subtitles: hearing impaired")
179
};
180 181 182 183 184 185

typedef struct
{
    uint8_t                 i_objectTypeIndication;
    uint8_t                 i_streamType;

186 187
    int                     i_extra;
    uint8_t                 *p_extra;
188 189 190 191 192

} decoder_config_descriptor_t;

typedef struct
{
193
    bool                    b_ok;
194 195 196 197 198
    uint16_t                i_es_id;

    char                    *psz_url;

    decoder_config_descriptor_t    dec_descr;
199

200 201 202 203 204 205 206 207 208 209 210 211 212
} es_mpeg4_descriptor_t;

typedef struct
{
    /* IOD */
    char                    *psz_url;

    es_mpeg4_descriptor_t   es_descr[255];

} iod_descriptor_t;

typedef struct
{
213 214
    dvbpsi_handle   handle;

215 216 217
    int             i_version;
    int             i_number;
    int             i_pid_pcr;
218
    int             i_pid_pmt;
219
    mtime_t         i_pcr_value;
220 221
    /* IOD stuff (mpeg4) */
    iod_descriptor_t *iod;
222

223 224
} ts_prg_psi_t;

225 226 227 228
typedef struct
{
    /* for special PAT/SDT case */
    dvbpsi_handle   handle; /* PAT/SDT/EIT */
229
    int             i_pat_version;
230
    int             i_sdt_version;
231 232 233 234

    /* For PMT */
    int             i_prg;
    ts_prg_psi_t    **prg;
235

236 237 238 239 240 241
} ts_psi_t;

typedef struct
{
    es_format_t  fmt;
    es_out_id_t *id;
242 243
    int         i_pes_size;
    int         i_pes_gathered;
244
    block_t     *p_pes;
245
    block_t     **pp_last;
246 247

    es_mpeg4_descriptor_t *p_mpeg4desc;
248
    int         b_gather;
249

250 251 252 253 254 255
} ts_es_t;

typedef struct
{
    int         i_pid;

256 257
    bool        b_seen;
    bool        b_valid;
258
    int         i_cc;   /* countinuity counter */
259
    bool        b_scrambled;
260 261 262

    /* PSI owner (ie PMT -> PAT, ES -> PMT */
    ts_psi_t   *p_owner;
263
    int         i_owner_number;
264 265 266 267 268

    /* */
    ts_psi_t    *psi;
    ts_es_t     *es;

269 270 271 272
    /* Some private streams encapsulate several ES (eg. DVB subtitles)*/
    ts_es_t     **extra_es;
    int         i_extra_es;

273 274 275 276
} ts_pid_t;

struct demux_sys_t
{
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
277 278
    vlc_mutex_t     csa_lock;

279 280 281
    /* TS packet size (188, 192, 204) */
    int         i_packet_size;

282 283 284
    /* how many TS packet we read at once */
    int         i_ts_read;

285 286 287 288 289 290 291 292 293 294
    /* to determine length and time */
    int         i_pid_ref_pcr;
    mtime_t     i_first_pcr;
    mtime_t     i_current_pcr;
    mtime_t     i_last_pcr;
    bool        b_force_seek_per_percent;
    int         i_pcrs_num;
    mtime_t     *p_pcrs;
    int64_t     *p_pos;

295 296 297 298
    /* All pid */
    ts_pid_t    pid[8192];

    /* All PMT */
299
    bool        b_user_pmt;
300 301
    int         i_pmt;
    ts_pid_t    **pmt;
302
    int         i_pmt_es;
303 304

    /* */
305
    bool        b_es_id_pid;
306
    csa_t       *csa;
307
    int         i_csa_pkt_size;
308
    bool        b_silent;
309
    bool        b_split_es;
310

311
    bool        b_udp_out;
312 313
    int         fd; /* udp socket */
    uint8_t     *buffer;
314

Laurent Aimar's avatar
Laurent Aimar committed
315 316 317 318 319
    /* */
    bool        b_access_control;

    /* */
    bool        b_dvb_meta;
320
    int64_t     i_tdt_delta;
321 322
    int64_t     i_dvb_start;
    int64_t     i_dvb_length;
323
    bool        b_broken_charset; /* True if broken encoding is used in EPG/SDT */
Laurent Aimar's avatar
Laurent Aimar committed
324 325 326

    /* */
    int         i_current_program;
327
    vlc_list_t  programs_list;
328

329 330
    /* */
    bool        b_start_record;
331 332
};

333
static int Demux    ( demux_t *p_demux );
334 335
static int Control( demux_t *p_demux, int i_query, va_list args );

336
static void PIDInit ( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner );
337
static void PIDClean( demux_t *, ts_pid_t *pid );
338 339
static int  PIDFillFormat( ts_pid_t *pid, int i_stream_type );

340 341
static void PATCallBack( demux_t *, dvbpsi_pat_t * );
static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt );
342 343
static void PSINewTableCallBack( demux_t *, dvbpsi_handle,
                                 uint8_t  i_table_id, uint16_t i_extension );
Laurent Aimar's avatar
Laurent Aimar committed
344
static int ChangeKeyCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
345

346 347 348 349 350
static inline int PIDGet( block_t *p )
{
    return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
}

351
static bool GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
352

353 354 355 356 357 358 359
static block_t* ReadTSPacket( demux_t *p_demux );
static mtime_t GetPCR( block_t *p_pkt );
static int SeekToPCR( demux_t *p_demux, int64_t i_pos );
static int Seek( demux_t *p_demux, double f_percent );
static void GetFirstPCR( demux_t *p_demux );
static void GetLastPCR( demux_t *p_demux );
static void CheckPCR( demux_t *p_demux );
360 361
static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );

362
static void              IODFree( iod_descriptor_t * );
363

364
#define TS_USER_PMT_NUMBER (0)
365 366
static int UserPmt( demux_t *p_demux, const char * );

367 368
static int  SetPIDFilter( demux_t *, int i_pid, bool b_selected );
static void SetPrgFilter( demux_t *, int i_prg, bool b_selected );
Laurent Aimar's avatar
Laurent Aimar committed
369

370 371 372 373
#define TS_PACKET_SIZE_188 188
#define TS_PACKET_SIZE_192 192
#define TS_PACKET_SIZE_204 204
#define TS_PACKET_SIZE_MAX 204
374
#define TS_TOPFIELD_HEADER 1320
375

Laurent Aimar's avatar
Laurent Aimar committed
376
static int DetectPacketSize( demux_t *p_demux )
377
{
378
    const uint8_t *p_peek;
Laurent Aimar's avatar
Laurent Aimar committed
379 380 381
    if( stream_Peek( p_demux->s,
                     &p_peek, TS_PACKET_SIZE_MAX ) < TS_PACKET_SIZE_MAX )
        return -1;
382

383
    if( memcmp( p_peek, "TFrc", 4 ) == 0 )
384 385
    {
#if 0
386
        /* I used the TF5000PVR 2004 Firmware .doc header documentation,
387 388 389
         * http://www.i-topfield.com/data/product/firmware/Structure%20of%20Recorded%20File%20in%20TF5000PVR%20(Feb%2021%202004).doc
         * but after the filename the offsets seem to be incorrect.  - DJ */
        int i_duration, i_name;
390
        char *psz_name = xmalloc(25);
391
        char *psz_event_name;
392 393
        char *psz_event_text = xmalloc(130);
        char *psz_ext_text = xmalloc(1025);
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

        // 2 bytes version Uimsbf (4,5)
        // 2 bytes reserved (6,7)
        // 2 bytes duration in minutes Uimsbf (8,9(
        i_duration = (int) (p_peek[8] << 8) | p_peek[9];
        msg_Dbg( p_demux, "Topfield recording length: +/- %d minutes", i_duration);
        // 2 bytes service number in channel list (10, 11)
        // 2 bytes service type Bslbf 0=TV 1=Radio Bslb (12, 13)
        // 4 bytes of reserved + tuner info (14,15,16,17)
        // 2 bytes of Service ID  Bslbf (18,19)
        // 2 bytes of PMT PID  Uimsbf (20,21)
        // 2 bytes of PCR PID  Uimsbf (22,23)
        // 2 bytes of Video PID  Uimsbf (24,25)
        // 2 bytes of Audio PID  Uimsbf (26,27)
        // 24 bytes filename Bslbf
        memcpy( psz_name, &p_peek[28], 24 );
        psz_name[24] = '\0';
        msg_Dbg( p_demux, "recordingname=%s", psz_name );
        // 1 byte of sat index Uimsbf  (52)
        // 3 bytes (1 bit of polarity Bslbf +23 bits reserved)
        // 4 bytes of freq. Uimsbf (56,57,58,59)
        // 2 bytes of symbol rate Uimsbf (60,61)
        // 2 bytes of TS stream ID Uimsbf (62,63)
417
        // 4 bytes reserved
418 419 420 421 422 423 424 425 426 427
        // 2 bytes reserved
        // 2 bytes duration Uimsbf (70,71)
        //i_duration = (int) (p_peek[70] << 8) | p_peek[71];
        //msg_Dbg( p_demux, "Topfield 2nd duration field: +/- %d minutes", i_duration);
        // 4 bytes EventID Uimsbf (72-75)
        // 8 bytes of Start and End time info (76-83)
        // 1 byte reserved (84)
        // 1 byte event name length Uimsbf (89)
        i_name = (int)(p_peek[89]&~0x81);
        msg_Dbg( p_demux, "event name length = %d", i_name);
428
        psz_event_name = xmalloc( i_name+1 );
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
        // 1 byte parental rating (90)
        // 129 bytes of event text
        memcpy( psz_event_name, &p_peek[91], i_name );
        psz_event_name[i_name] = '\0';
        memcpy( psz_event_text, &p_peek[91+i_name], 129-i_name );
        psz_event_text[129-i_name] = '\0';
        msg_Dbg( p_demux, "event name=%s", psz_event_name );
        msg_Dbg( p_demux, "event text=%s", psz_event_text );
        // 12 bytes reserved (220)
        // 6 bytes reserved
        // 2 bytes Event Text Length Uimsbf
        // 4 bytes EventID Uimsbf
        // FIXME We just have 613 bytes. not enough for this entire text
        // 1024 bytes Extended Event Text Bslbf
        memcpy( psz_ext_text, p_peek+372, 1024 );
        psz_ext_text[1024] = '\0';
        msg_Dbg( p_demux, "extended event text=%s", psz_ext_text );
        // 52 bytes reserved Bslbf
#endif
Laurent Aimar's avatar
Laurent Aimar committed
448 449
        msg_Dbg( p_demux, "this is a topfield file" );
        return TS_PACKET_SIZE_188;
450
    }
Laurent Aimar's avatar
Laurent Aimar committed
451 452

    for( int i_sync = 0; i_sync < TS_PACKET_SIZE_MAX; i_sync++ )
453
    {
Laurent Aimar's avatar
Laurent Aimar committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
        if( p_peek[i_sync] != 0x47 )
            continue;

        /* Check next 3 sync bytes */
        int i_peek = TS_PACKET_SIZE_MAX * 3 + i_sync + 1;
        if( ( stream_Peek( p_demux->s, &p_peek, i_peek ) ) < i_peek )
        {
            msg_Err( p_demux, "cannot peek" );
            return -1;
        }
        if( p_peek[i_sync + 1 * TS_PACKET_SIZE_188] == 0x47 &&
            p_peek[i_sync + 2 * TS_PACKET_SIZE_188] == 0x47 &&
            p_peek[i_sync + 3 * TS_PACKET_SIZE_188] == 0x47 )
        {
            return TS_PACKET_SIZE_188;
        }
        else if( p_peek[i_sync + 1 * TS_PACKET_SIZE_192] == 0x47 &&
                 p_peek[i_sync + 2 * TS_PACKET_SIZE_192] == 0x47 &&
                 p_peek[i_sync + 3 * TS_PACKET_SIZE_192] == 0x47 )
        {
            return TS_PACKET_SIZE_192;
        }
        else if( p_peek[i_sync + 1 * TS_PACKET_SIZE_204] == 0x47 &&
                 p_peek[i_sync + 2 * TS_PACKET_SIZE_204] == 0x47 &&
                 p_peek[i_sync + 3 * TS_PACKET_SIZE_204] == 0x47 )
        {
            return TS_PACKET_SIZE_204;
        }
482
    }
483

Laurent Aimar's avatar
Laurent Aimar committed
484 485 486 487 488
    if( p_demux->b_force )
    {
        msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
        return TS_PACKET_SIZE_188;
    }
489
    msg_Dbg( p_demux, "TS module discarded (lost sync)" );
Laurent Aimar's avatar
Laurent Aimar committed
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
    return -1;
}

/*****************************************************************************
 * Open
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;

    int          i_packet_size;

    ts_pid_t    *pat;

    /* Search first sync byte */
    i_packet_size = DetectPacketSize( p_demux );
    if( i_packet_size < 0 )
        return VLC_EGENERIC;

510
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
511 512
    if( !p_sys )
        return VLC_ENOMEM;
513
    memset( p_sys, 0, sizeof( demux_sys_t ) );
514
    p_sys->i_packet_size = i_packet_size;
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
515
    vlc_mutex_init( &p_sys->csa_lock );
516

517
    p_sys->buffer = NULL;
518
    p_demux->pf_demux = Demux;
519 520 521
    p_demux->pf_control = Control;

    /* Init p_sys field */
Laurent Aimar's avatar
Laurent Aimar committed
522 523 524
    p_sys->b_dvb_meta = true;
    p_sys->b_access_control = true;
    p_sys->i_current_program = 0;
525 526
    p_sys->programs_list.i_count = 0;
    p_sys->programs_list.p_values = NULL;
527
    p_sys->i_tdt_delta = 0;
528
    p_sys->i_dvb_start = 0;
529 530
    p_sys->i_dvb_length = 0;

531 532
    p_sys->b_broken_charset = false;

Laurent Aimar's avatar
Laurent Aimar committed
533
    for( int i = 0; i < 8192; i++ )
534 535 536 537
    {
        ts_pid_t *pid = &p_sys->pid[i];

        pid->i_pid      = i;
538 539
        pid->b_seen     = false;
        pid->b_valid    = false;
540
    }
541
    /* PID 8191 is padding */
542
    p_sys->pid[8191].b_seen = true;
543
    p_sys->i_packet_size = i_packet_size;
544
    p_sys->b_udp_out = false;
545
    p_sys->fd = -1;
546
    p_sys->i_ts_read = 50;
547
    p_sys->csa = NULL;
548
    p_sys->b_start_record = false;
549 550 551

    /* Init PAT handler */
    pat = &p_sys->pid[0];
552
    PIDInit( pat, true, NULL );
553 554
    pat->psi->handle = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack,
                                         p_demux );
Laurent Aimar's avatar
Laurent Aimar committed
555
    if( p_sys->b_dvb_meta )
556 557 558 559
    {
        ts_pid_t *sdt = &p_sys->pid[0x11];
        ts_pid_t *eit = &p_sys->pid[0x12];

560
        PIDInit( sdt, true, NULL );
561 562 563
        sdt->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
564
        PIDInit( eit, true, NULL );
565 566 567
        eit->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
568

569
        ts_pid_t *tdt = &p_sys->pid[0x14];
570 571 572 573
        PIDInit( tdt, true, NULL );
        tdt->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
Laurent Aimar's avatar
Laurent Aimar committed
574
        if( p_sys->b_access_control )
575
        {
Laurent Aimar's avatar
Laurent Aimar committed
576 577 578
            if( SetPIDFilter( p_demux, 0x11, true ) ||
                SetPIDFilter( p_demux, 0x14, true ) ||
                SetPIDFilter( p_demux, 0x12, true ) )
Laurent Aimar's avatar
Laurent Aimar committed
579
                p_sys->b_access_control = false;
580 581
        }
    }
582 583

    /* Init PMT array */
584
    TAB_INIT( p_sys->i_pmt, p_sys->pmt );
585
    p_sys->i_pmt_es = 0;
586

587
    /* Read config */
588
    p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" );
589

590
    char* psz_string = var_CreateGetString( p_demux, "ts-out" );
591
    if( psz_string && *psz_string )
592
    {
593
        char *psz = strchr( psz_string, ':' );
594 595
        int   i_port = 0;

596
        p_sys->b_udp_out = true;
597 598 599 600 601 602 603

        if( psz )
        {
            *psz++ = '\0';
            i_port = atoi( psz );
        }
        if( i_port <= 0 ) i_port  = 1234;
604
        msg_Dbg( p_demux, "resend ts to '%s:%d'", psz_string, i_port );
605

606
        p_sys->fd = net_ConnectUDP( VLC_OBJECT(p_demux), psz_string, i_port, -1 );
607 608 609
        if( p_sys->fd < 0 )
        {
            msg_Err( p_demux, "failed to open udp socket, send disabled" );
610
            p_sys->b_udp_out = false;
611 612 613
        }
        else
        {
614 615
            int i_mtu = var_CreateGetInteger( p_demux, "ts-out-mtu" );
            p_sys->i_ts_read = i_mtu / p_sys->i_packet_size;
616 617
            if( p_sys->i_ts_read <= 0 )
            {
618
                p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
619
            }
620
            p_sys->buffer = xmalloc( p_sys->i_packet_size * p_sys->i_ts_read );
621 622
        }
    }
623
    free( psz_string );
624

625
    /* We handle description of an extra PMT */
626
    psz_string = var_CreateGetString( p_demux, "ts-extra-pmt" );
627
    p_sys->b_user_pmt = false;
628 629 630
    if( psz_string && *psz_string )
        UserPmt( p_demux, psz_string );
    free( psz_string );
631

632 633
    psz_string = var_CreateGetStringCommand( p_demux, "ts-csa-ck" );
    if( psz_string && *psz_string )
634
    {
635
        int i_res;
636
        char* psz_csa2;
637 638 639

        p_sys->csa = csa_New();

640 641 642
        psz_csa2 = var_CreateGetStringCommand( p_demux, "ts-csa2-ck" );
        i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, true );
        if( i_res == VLC_SUCCESS && psz_csa2 && *psz_csa2 )
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
643
        {
644
            if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_csa2, false ) != VLC_SUCCESS )
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
645
            {
646
                csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
647 648 649 650
            }
        }
        else if ( i_res == VLC_SUCCESS )
        {
651
            csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
652 653
        }
        else
654
        {
655
            csa_Delete( p_sys->csa );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
656
            p_sys->csa = NULL;
657
        }
658 659

        if( p_sys->csa )
660
        {
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
661 662 663
            var_AddCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, (void *)1 );
            var_AddCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );

664 665
            int i_pkt = var_CreateGetInteger( p_demux, "ts-csa-pkt" );
            if( i_pkt < 4 || i_pkt > 188 )
666
            {
667
                msg_Err( p_demux, "wrong packet size %d specified.", i_pkt );
668 669
                msg_Warn( p_demux, "using default packet size of 188 bytes" );
                p_sys->i_csa_pkt_size = 188;
670
            }
671 672
            else
                p_sys->i_csa_pkt_size = i_pkt;
673
            msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size );
674
        }
675
        free( psz_csa2 );
676
    }
677
    free( psz_string );
678

679
    p_sys->b_silent = var_CreateGetBool( p_demux, "ts-silent" );
680
    p_sys->b_split_es = var_InheritBool( p_demux, "ts-split-es" );
681

682 683 684 685 686 687 688 689 690 691
    p_sys->i_pid_ref_pcr = -1;
    p_sys->i_first_pcr = -1;
    p_sys->i_current_pcr = -1;
    p_sys->i_last_pcr = -1;
    p_sys->b_force_seek_per_percent = var_InheritBool( p_demux, "ts-seek-percent" );
    p_sys->i_pcrs_num = 10;
    p_sys->p_pcrs = (mtime_t *)calloc( p_sys->i_pcrs_num, sizeof( mtime_t ) );
    p_sys->p_pos = (int64_t *)calloc( p_sys->i_pcrs_num, sizeof( int64_t ) );

    bool can_seek = false;
692
    stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &can_seek );
693 694 695 696 697 698 699 700 701 702 703
    if( can_seek  )
    {
        GetFirstPCR( p_demux );
        CheckPCR( p_demux );
        GetLastPCR( p_demux );
    }
    if( p_sys->i_first_pcr < 0 || p_sys->i_last_pcr < 0 )
    {
        p_sys->b_force_seek_per_percent = true;
    }

704
    while( p_sys->i_pmt_es <= 0 && vlc_object_alive( p_demux ) )
705 706 707 708 709
    {
        if( p_demux->pf_demux( p_demux ) != 1 )
            break;
    }

710 711 712 713 714 715 716 717 718 719 720 721
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;

    msg_Dbg( p_demux, "pid list:" );
722
    for( int i = 0; i < 8192; i++ )
723 724 725 726 727 728 729
    {
        ts_pid_t *pid = &p_sys->pid[i];

        if( pid->b_valid && pid->psi )
        {
            switch( pid->i_pid )
            {
Laurent Aimar's avatar
Laurent Aimar committed
730 731 732 733 734 735 736 737
            case 0: /* PAT */
                dvbpsi_DetachPAT( pid->psi->handle );
                free( pid->psi );
                break;
            case 1: /* CAT */
                free( pid->psi );
                break;
            default:
738
                if( p_sys->b_dvb_meta && ( pid->i_pid == 0x11 || pid->i_pid == 0x12 || pid->i_pid == 0x14 ) )
Laurent Aimar's avatar
Laurent Aimar committed
739
                {
740
                    /* SDT or EIT or TDT */
Laurent Aimar's avatar
Laurent Aimar committed
741
                    dvbpsi_DetachDemux( pid->psi->handle );
742
                    free( pid->psi );
Laurent Aimar's avatar
Laurent Aimar committed
743 744 745
                }
                else
                {
746
                    PIDClean( p_demux, pid );
Laurent Aimar's avatar
Laurent Aimar committed
747 748
                }
                break;
749 750 751 752
            }
        }
        else if( pid->b_valid && pid->es )
        {
753
            PIDClean( p_demux, pid );
754
        }
755

756 757
        if( pid->b_seen )
        {
758
            msg_Dbg( p_demux, "  - pid[%d] seen", pid->i_pid );
759
        }
760

Laurent Aimar's avatar
Laurent Aimar committed
761 762 763
        /* too much */
        if( pid->i_pid > 0 )
            SetPIDFilter( p_demux, pid->i_pid, false );
764 765
    }

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
766
    vlc_mutex_lock( &p_sys->csa_lock );
767 768
    if( p_sys->csa )
    {
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
769 770
        var_DelCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, NULL );
        var_DelCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
771 772
        csa_Delete( p_sys->csa );
    }
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
773
    vlc_mutex_unlock( &p_sys->csa_lock );
774

775
    TAB_CLEAN( p_sys->i_pmt, p_sys->pmt );
776

777
    free( p_sys->programs_list.p_values );
778

779 780 781 782 783
    /* When streaming, close the port */
    if( p_sys->fd > -1 )
    {
        net_Close( p_sys->fd );
    }
784

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
785
    free( p_sys->buffer );
786

787 788 789
    free( p_sys->p_pcrs );
    free( p_sys->p_pos );

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
790
    vlc_mutex_destroy( &p_sys->csa_lock );
791 792 793
    free( p_sys );
}

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
/*****************************************************************************
 * ChangeKeyCallback: called when changing the odd encryption key on the fly.
 *****************************************************************************/
static int ChangeKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
                           vlc_value_t oldval, vlc_value_t newval,
                           void *p_data )
{
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;
    int         i_tmp = (intptr_t)p_data;

    vlc_mutex_lock( &p_sys->csa_lock );
    if ( i_tmp )
        i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, true );
    else
        i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, false );

    vlc_mutex_unlock( &p_sys->csa_lock );
    return i_tmp;
}

816 817 818 819 820 821
/*****************************************************************************
 * Demux:
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
822
    bool b_wait_es = p_sys->i_pmt_es <= 0;
823 824

    /* We read at most 100 TS packet or until a frame is completed */
Laurent Aimar's avatar
Laurent Aimar committed
825
    for( int i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
826
    {
827
        bool         b_frame = false;
828
        block_t     *p_pkt;
829
        if( !(p_pkt = ReadTSPacket( p_demux )) )
830 831 832
        {
            return 0;
        }
833

834 835 836 837 838 839 840
        if( p_sys->b_start_record )
        {
            /* Enable recording once synchronized */
            stream_Control( p_demux->s, STREAM_SET_RECORD_STATE, true, "ts" );
            p_sys->b_start_record = false;
        }

841 842
        if( p_sys->b_udp_out )
        {
843 844
            memcpy( &p_sys->buffer[i_pkt * p_sys->i_packet_size],
                    p_pkt->p_buffer, p_sys->i_packet_size );
845 846
        }

847
        /* Parse the TS packet */
Laurent Aimar's avatar
Laurent Aimar committed
848
        ts_pid_t *p_pid = &p_sys->pid[PIDGet( p_pkt )];
849 850 851 852 853

        if( p_pid->b_valid )
        {
            if( p_pid->psi )
            {
854
                if( p_pid->i_pid == 0 || ( p_sys->b_dvb_meta && ( p_pid->i_pid == 0x11 || p_pid->i_pid == 0x12 || p_pid->i_pid == 0x14 ) ) )
855 856 857 858 859
                {
                    dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
                }
                else
                {
Laurent Aimar's avatar
Laurent Aimar committed
860
                    for( int i_prg = 0; i_prg < p_pid->psi->i_prg; i_prg++ )
861
                    {
862 863
                        dvbpsi_PushPacket( p_pid->psi->prg[i_prg]->handle,
                                           p_pkt->p_buffer );
864 865
                    }
                }
866 867
                block_Release( p_pkt );
            }
868
            else if( !p_sys->b_udp_out )
869 870 871
            {
                b_frame = GatherPES( p_demux, p_pid, p_pkt );
            }
872 873
            else
            {
Laurent Aimar's avatar
Laurent Aimar committed
874
                PCRHandle( p_demux, p_pid, p_pkt );
875 876
                block_Release( p_pkt );
            }
877 878 879 880 881
        }
        else
        {
            if( !p_pid->b_seen )
            {
882
                msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid );
883
            }
884 885
            /* We have to handle PCR if present */
            PCRHandle( p_demux, p_pid, p_pkt );
886 887
            block_Release( p_pkt );
        }
888
        p_pid->b_seen = true;
889

890
        if( b_frame || ( b_wait_es && p_sys->i_pmt_es > 0 ) )
891 892 893
            break;
    }

894 895 896
    if( p_sys->b_udp_out )
    {
        /* Send the complete block */
897
        net_Write( p_demux, p_sys->fd, NULL, p_sys->buffer,
898
                   p_sys->i_ts_read * p_sys->i_packet_size );
899 900
    }

901 902 903 904 905 906
    return 1;
}

/*****************************************************************************
 * Control:
 *****************************************************************************/
907 908 909 910 911 912 913 914
static int DVBEventInformation( demux_t *p_demux, int64_t *pi_time, int64_t *pi_length )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    if( pi_length )
        *pi_length = 0;
    if( pi_time )
        *pi_time = 0;

915
    if( p_sys->i_dvb_length > 0 )
916
    {
917 918
        const int64_t t = mdate() + p_sys->i_tdt_delta;

919 920 921
        if( p_sys->i_dvb_start <= t && t < p_sys->i_dvb_start + p_sys->i_dvb_length )
        {
            if( pi_length )
922
                *pi_length = p_sys->i_dvb_length;
923
            if( pi_time )
924
                *pi_time   = t - p_sys->i_dvb_start;
925 926 927 928 929 930
            return VLC_SUCCESS;
        }
    }
    return VLC_EGENERIC;
}

931 932
static int Control( demux_t *p_demux, int i_query, va_list args )
{
933
    demux_sys_t *p_sys = p_demux->p_sys;
934
    double f, *pf;
935
    bool b_bool, *pb_bool;
936
    int64_t i64;
937
    int64_t *pi64;
938
    int i_int;
939 940 941

    switch( i_query )
    {
Laurent Aimar's avatar
Laurent Aimar committed
942 943
    case DEMUX_GET_POSITION:
        pf = (double*) va_arg( args