ts.c 136 KB
Newer Older
1 2 3
/*****************************************************************************
 * ts.c: Transport Stream input module for VLC.
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2004-2005 VLC authors and VideoLAN
5
 * $Id$
6 7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Jean-Paul Saman <jpsaman #_at_# m2x.nl>
9
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
10 11 12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13 14 15 16
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software 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 */
zorglub's avatar
zorglub 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 65
#include "../mux/mpeg/dvbpsi_compat.h"

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

79 80 81
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
82 83
static int  Open  ( vlc_object_t * );
static void Close ( vlc_object_t * );
84

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

#define PID_TEXT N_("Set id of ES to PID")
99 100 101 102
#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>\"}\'.")
103 104 105

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

#define MTUOUT_TEXT N_("MTU for out mode")
109
#define MTUOUT_LONGTEXT N_("MTU for out mode.")
110

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

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
115 116 117 118
#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).")

119

120 121 122 123 124
#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. " )

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

130 131 132
#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 " \
133
    "time position. If seeking doesn't work property, turn on this option." )
134 135


136 137 138 139 140 141
vlc_module_begin ()
    set_description( N_("MPEG Transport Stream demuxer") )
    set_shortname ( "MPEG-TS" )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )

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

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

156
    add_bool( "ts-split-es", true, SPLIT_ES_TEXT, SPLIT_ES_LONGTEXT, false )
157
    add_bool( "ts-seek-percent", false, SEEK_PERCENT_TEXT, SEEK_PERCENT_LONGTEXT, true )
158

159 160
    add_obsolete_bool( "ts-silent" );

161 162 163 164
    set_capability( "demux", 10 )
    set_callbacks( Open, Close )
    add_shortcut( "ts" )
vlc_module_end ()
165 166 167 168

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

typedef struct
{
    uint8_t                 i_objectTypeIndication;
    uint8_t                 i_streamType;

183 184
    int                     i_extra;
    uint8_t                 *p_extra;
185 186 187 188 189

} decoder_config_descriptor_t;

typedef struct
{
190
    bool                    b_ok;
191 192 193 194 195
    uint16_t                i_es_id;

    char                    *psz_url;

    decoder_config_descriptor_t    dec_descr;
196

197 198 199 200 201 202 203 204 205 206 207 208 209
} es_mpeg4_descriptor_t;

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

    es_mpeg4_descriptor_t   es_descr[255];

} iod_descriptor_t;

typedef struct
{
210
    dvbpsi_handle   handle;
211 212 213
    int             i_version;
    int             i_number;
    int             i_pid_pcr;
214
    int             i_pid_pmt;
215
    mtime_t         i_pcr_value;
216 217
    /* IOD stuff (mpeg4) */
    iod_descriptor_t *iod;
218

219 220
} ts_prg_psi_t;

221 222 223 224
typedef struct
{
    /* for special PAT/SDT case */
    dvbpsi_handle   handle; /* PAT/SDT/EIT */
225
    int             i_pat_version;
226
    int             i_sdt_version;
227 228 229 230

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

232 233
} ts_psi_t;

234 235 236 237 238 239
typedef enum
{
    TS_ES_DATA_PES,
    TS_ES_DATA_TABLE_SECTION
} ts_es_data_type_t;

240 241 242 243
typedef struct
{
    es_format_t  fmt;
    es_out_id_t *id;
244
    ts_es_data_type_t data_type;
245 246 247
    int         i_data_size;
    int         i_data_gathered;
    block_t     *p_data;
248
    block_t     **pp_last;
249 250

    es_mpeg4_descriptor_t *p_mpeg4desc;
251

252 253 254 255 256 257
} ts_es_t;

typedef struct
{
    int         i_pid;

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

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

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

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

275 276 277 278
} ts_pid_t;

struct demux_sys_t
{
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
279 280
    vlc_mutex_t     csa_lock;

281 282 283
    /* TS packet size (188, 192, 204) */
    int         i_packet_size;

284 285 286
    /* how many TS packet we read at once */
    int         i_ts_read;

287 288 289 290 291 292 293 294 295 296
    /* 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;

297 298 299 300
    /* All pid */
    ts_pid_t    pid[8192];

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

    /* */
307
    bool        b_es_id_pid;
308
    csa_t       *csa;
309
    int         i_csa_pkt_size;
310
    bool        b_split_es;
311

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

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

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

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

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

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

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

341 342
static void PATCallBack( void*, dvbpsi_pat_t * );
static void PMTCallBack( void *data, dvbpsi_pmt_t *p_pmt );
343 344 345 346
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
static void PSINewTableCallBack( dvbpsi_t *handle, uint8_t  i_table_id,
                                 uint16_t i_extension, demux_t * );
#else
347 348
static void PSINewTableCallBack( demux_t *, dvbpsi_handle,
                                 uint8_t  i_table_id, uint16_t i_extension );
349 350
#endif

Laurent Aimar's avatar
Laurent Aimar committed
351
static int ChangeKeyCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
352

353 354 355 356 357
static inline int PIDGet( block_t *p )
{
    return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
}

358
static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
359

360 361 362 363 364 365 366
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 );
367 368
static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );

369
static void              IODFree( iod_descriptor_t * );
370

371
#define TS_USER_PMT_NUMBER (0)
372 373
static int UserPmt( demux_t *p_demux, const char * );

374 375
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
376

377 378 379 380
#define TS_PACKET_SIZE_188 188
#define TS_PACKET_SIZE_192 192
#define TS_PACKET_SIZE_204 204
#define TS_PACKET_SIZE_MAX 204
381
#define TS_TOPFIELD_HEADER 1320
382

Laurent Aimar's avatar
Laurent Aimar committed
383
static int DetectPacketSize( demux_t *p_demux )
384
{
385
    const uint8_t *p_peek;
Laurent Aimar's avatar
Laurent Aimar committed
386 387 388
    if( stream_Peek( p_demux->s,
                     &p_peek, TS_PACKET_SIZE_MAX ) < TS_PACKET_SIZE_MAX )
        return -1;
389

390
    if( memcmp( p_peek, "TFrc", 4 ) == 0 )
391 392
    {
#if 0
393
        /* I used the TF5000PVR 2004 Firmware .doc header documentation,
394 395 396
         * 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;
397
        char *psz_name = xmalloc(25);
398
        char *psz_event_name;
399 400
        char *psz_event_text = xmalloc(130);
        char *psz_ext_text = xmalloc(1025);
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423

        // 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)
424
        // 4 bytes reserved
425 426 427 428 429 430 431 432 433 434
        // 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);
435
        psz_event_name = xmalloc( i_name+1 );
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
        // 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
455 456
        msg_Dbg( p_demux, "this is a topfield file" );
        return TS_PACKET_SIZE_188;
457
    }
Laurent Aimar's avatar
Laurent Aimar committed
458 459

    for( int i_sync = 0; i_sync < TS_PACKET_SIZE_MAX; i_sync++ )
460
    {
Laurent Aimar's avatar
Laurent Aimar committed
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
        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;
        }
489
    }
490

Laurent Aimar's avatar
Laurent Aimar committed
491 492 493 494 495
    if( p_demux->b_force )
    {
        msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
        return TS_PACKET_SIZE_188;
    }
496
    msg_Dbg( p_demux, "TS module discarded (lost sync)" );
Laurent Aimar's avatar
Laurent Aimar committed
497 498 499
    return -1;
}

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
static void vlc_dvbpsi_reset( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;

    ts_pid_t *pat = &p_sys->pid[0];
    ts_pid_t *sdt = &p_sys->pid[0x11];
    ts_pid_t *eit = &p_sys->pid[0x12];
    ts_pid_t *tdt = &p_sys->pid[0x14];

    if( pat->psi->handle )
    {
        if( dvbpsi_decoder_present( pat->psi->handle ) )
            dvbpsi_pat_detach( pat->psi->handle );
        dvbpsi_delete( pat->psi->handle );
        pat->psi->handle = NULL;
    }

    if( sdt->psi->handle )
    {
        if( dvbpsi_decoder_present( sdt->psi->handle ) )
            dvbpsi_DetachDemux( sdt->psi->handle );
        dvbpsi_delete( sdt->psi->handle );
        sdt->psi->handle = NULL;
    }

    if( eit->psi->handle )
    {
        if( dvbpsi_decoder_present( eit->psi->handle ) )
            dvbpsi_DetachDemux( eit->psi->handle );
        dvbpsi_delete( eit->psi->handle );
        eit->psi->handle = NULL;
    }

    if( tdt->psi->handle )
    {
        if( dvbpsi_decoder_present( tdt->psi->handle ) )
            dvbpsi_DetachDemux( tdt->psi->handle );
        dvbpsi_delete( tdt->psi->handle );
        tdt->psi->handle = NULL;
    }
}
#endif

Laurent Aimar's avatar
Laurent Aimar committed
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
/*****************************************************************************
 * 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;

561
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
562 563
    if( !p_sys )
        return VLC_ENOMEM;
564
    memset( p_sys, 0, sizeof( demux_sys_t ) );
565
    p_sys->i_packet_size = i_packet_size;
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
566
    vlc_mutex_init( &p_sys->csa_lock );
567

hartman's avatar
hartman committed
568
    p_sys->buffer = NULL;
569
    p_demux->pf_demux = Demux;
570 571 572
    p_demux->pf_control = Control;

    /* Init p_sys field */
Laurent Aimar's avatar
Laurent Aimar committed
573 574 575
    p_sys->b_dvb_meta = true;
    p_sys->b_access_control = true;
    p_sys->i_current_program = 0;
576 577
    p_sys->programs_list.i_count = 0;
    p_sys->programs_list.p_values = NULL;
578
    p_sys->i_tdt_delta = 0;
579
    p_sys->i_dvb_start = 0;
580 581
    p_sys->i_dvb_length = 0;

582 583
    p_sys->b_broken_charset = false;

Laurent Aimar's avatar
Laurent Aimar committed
584
    for( int i = 0; i < 8192; i++ )
585 586 587
    {
        ts_pid_t *pid = &p_sys->pid[i];
        pid->i_pid      = i;
588 589
        pid->b_seen     = false;
        pid->b_valid    = false;
590
    }
591
    /* PID 8191 is padding */
592
    p_sys->pid[8191].b_seen = true;
593
    p_sys->i_packet_size = i_packet_size;
594
    p_sys->b_udp_out = false;
hartman's avatar
hartman committed
595
    p_sys->fd = -1;
596
    p_sys->i_ts_read = 50;
597
    p_sys->csa = NULL;
598
    p_sys->b_start_record = false;
599

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
# define VLC_DVBPSI_DEMUX_TABLE_INIT(table,obj) \
    do { \
        (table)->psi->handle = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG ); \
        if( ! (table)->psi->handle ) \
        { \
            vlc_mutex_destroy( &p_sys->csa_lock ); \
            free( p_sys ); \
            return VLC_ENOMEM; \
        } \
        (table)->psi->handle->p_sys = (void *) VLC_OBJECT(obj); \
        if( !dvbpsi_AttachDemux( (table)->psi->handle, (dvbpsi_demux_new_cb_t)PSINewTableCallBack, (obj) ) ) \
        { \
            vlc_dvbpsi_reset( obj ); \
            vlc_mutex_destroy( &p_sys->csa_lock ); \
            free( p_sys ); \
            return VLC_EGENERIC; \
        } \
    } while (0);
#endif

621 622
    /* Init PAT handler */
    pat = &p_sys->pid[0];
623
    PIDInit( pat, true, NULL );
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
    pat->psi->handle = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG );
    if( !pat->psi->handle )
    {
        vlc_mutex_destroy( &p_sys->csa_lock );
        free( p_sys );
        return VLC_ENOMEM;
    }
    pat->psi->handle->p_sys = (void *) p_demux;
    if( !dvbpsi_pat_attach( pat->psi->handle, PATCallBack, p_demux ) )
    {
        vlc_dvbpsi_reset( p_demux );
        vlc_mutex_destroy( &p_sys->csa_lock );
        free( p_sys );
        return VLC_EGENERIC;
    }
#else
641
    pat->psi->handle = dvbpsi_AttachPAT( PATCallBack, p_demux );
642
#endif
Laurent Aimar's avatar
Laurent Aimar committed
643
    if( p_sys->b_dvb_meta )
644 645 646 647
    {
        ts_pid_t *sdt = &p_sys->pid[0x11];
        ts_pid_t *eit = &p_sys->pid[0x12];

648
        PIDInit( sdt, true, NULL );
649 650 651
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
        VLC_DVBPSI_DEMUX_TABLE_INIT( sdt, p_demux )
#else
652 653 654
        sdt->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
655
#endif
656
        PIDInit( eit, true, NULL );
657 658 659
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
        VLC_DVBPSI_DEMUX_TABLE_INIT( eit, p_demux )
#else
660 661 662
        eit->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
663
#endif
664
        ts_pid_t *tdt = &p_sys->pid[0x14];
665
        PIDInit( tdt, true, NULL );
666 667 668
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
        VLC_DVBPSI_DEMUX_TABLE_INIT( tdt, p_demux )
#else
669 670 671
        tdt->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
672 673
#endif

Laurent Aimar's avatar
Laurent Aimar committed
674
        if( p_sys->b_access_control )
675
        {
Laurent Aimar's avatar
Laurent Aimar committed
676 677 678
            if( SetPIDFilter( p_demux, 0x11, true ) ||
                SetPIDFilter( p_demux, 0x14, true ) ||
                SetPIDFilter( p_demux, 0x12, true ) )
Laurent Aimar's avatar
Laurent Aimar committed
679
                p_sys->b_access_control = false;
680 681
        }
    }
682

683 684 685 686
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
# undef VLC_DVBPSI_DEMUX_TABLE_INIT
#endif

687
    /* Init PMT array */
hartman's avatar
hartman committed
688
    TAB_INIT( p_sys->i_pmt, p_sys->pmt );
689
    p_sys->i_pmt_es = 0;
690

691
    /* Read config */
692
    p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" );
693

694
    char* psz_string = var_CreateGetString( p_demux, "ts-out" );
695
    if( psz_string && *psz_string )
696
    {
697
        char *psz = strchr( psz_string, ':' );
698 699
        int   i_port = 0;

700
        p_sys->b_udp_out = true;
701 702 703 704 705 706 707

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

710
        p_sys->fd = net_ConnectUDP( VLC_OBJECT(p_demux), psz_string, i_port, -1 );
711 712 713
        if( p_sys->fd < 0 )
        {
            msg_Err( p_demux, "failed to open udp socket, send disabled" );
714
            p_sys->b_udp_out = false;
715 716 717
        }
        else
        {
718 719
            int i_mtu = var_CreateGetInteger( p_demux, "ts-out-mtu" );
            p_sys->i_ts_read = i_mtu / p_sys->i_packet_size;
720 721
            if( p_sys->i_ts_read <= 0 )
            {
722
                p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
723
            }
724
            p_sys->buffer = xmalloc( p_sys->i_packet_size * p_sys->i_ts_read );
725 726
        }
    }
727
    free( psz_string );
728

729
    /* We handle description of an extra PMT */
730
    psz_string = var_CreateGetString( p_demux, "ts-extra-pmt" );
731
    p_sys->b_user_pmt = false;
732 733 734
    if( psz_string && *psz_string )
        UserPmt( p_demux, psz_string );
    free( psz_string );
735

736 737
    psz_string = var_CreateGetStringCommand( p_demux, "ts-csa-ck" );
    if( psz_string && *psz_string )
738
    {
739
        int i_res;
740
        char* psz_csa2;
741 742 743

        p_sys->csa = csa_New();

744 745 746
        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
747
        {
748
            if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_csa2, false ) != VLC_SUCCESS )
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
749
            {
750
                csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
751 752 753 754
            }
        }
        else if ( i_res == VLC_SUCCESS )
        {
755
            csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
756 757
        }
        else
758
        {
759
            csa_Delete( p_sys->csa );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
760
            p_sys->csa = NULL;
761
        }
762 763

        if( p_sys->csa )
764
        {
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
765 766 767
            var_AddCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, (void *)1 );
            var_AddCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );

768 769
            int i_pkt = var_CreateGetInteger( p_demux, "ts-csa-pkt" );
            if( i_pkt < 4 || i_pkt > 188 )
770
            {
771
                msg_Err( p_demux, "wrong packet size %d specified.", i_pkt );
772 773
                msg_Warn( p_demux, "using default packet size of 188 bytes" );
                p_sys->i_csa_pkt_size = 188;
774
            }
775 776
            else
                p_sys->i_csa_pkt_size = i_pkt;
777
            msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size );
778
        }
779
        free( psz_csa2 );
780
    }
781
    free( psz_string );
782

783
    p_sys->b_split_es = var_InheritBool( p_demux, "ts-split-es" );
784

785 786 787 788 789 790 791 792 793 794
    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;
795
    stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &can_seek );
796 797 798 799 800 801 802 803 804 805 806
    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;
    }

807
    while( p_sys->i_pmt_es <= 0 && vlc_object_alive( p_demux ) )
808 809 810 811 812
    {
        if( p_demux->pf_demux( p_demux ) != 1 )
            break;
    }

813 814 815 816 817 818 819 820 821 822 823 824
    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:" );
825
    for( int i = 0; i < 8192; i++ )
826 827 828 829 830 831 832
    {
        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
833
            case 0: /* PAT */
834 835 836 837 838 839
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
                if( dvbpsi_decoder_present( pid->psi->handle ) )
                    dvbpsi_pat_detach( pid->psi->handle );
                dvbpsi_delete( pid->psi->handle );
                pid->psi->handle = NULL;
#else
Laurent Aimar's avatar
Laurent Aimar committed
840
                dvbpsi_DetachPAT( pid->psi->handle );
841
#endif
Laurent Aimar's avatar
Laurent Aimar committed
842 843 844 845 846 847
                free( pid->psi );
                break;
            case 1: /* CAT */
                free( pid->psi );
                break;
            default:
848
                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
849
                {
850
                    /* SDT or EIT or TDT */
Laurent Aimar's avatar
Laurent Aimar committed
851
                    dvbpsi_DetachDemux( pid->psi->handle );
852 853 854 855
#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
                    dvbpsi_delete( pid->psi->handle );
                    pid->psi->handle = NULL;
#endif
856
                    free( pid->psi );
Laurent Aimar's avatar
Laurent Aimar committed
857 858 859
                }
                else
                {
860
                    PIDClean( p_demux, pid );
Laurent Aimar's avatar
Laurent Aimar committed
861 862
                }
                break;
863 864 865 866
            }
        }
        else if( pid->b_valid && pid->es )
        {
867
            PIDClean( p_demux, pid );
868
        }
869

870 871
        if( pid->b_seen )
        {
872
            msg_Dbg( p_demux, "  - pid[%d] seen", pid->i_pid );
873
        }
874

Laurent Aimar's avatar
Laurent Aimar committed
875 876 877
        /* too much */
        if( pid->i_pid > 0 )
            SetPIDFilter( p_demux, pid->i_pid, false );
878 879
    }

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
880
    vlc_mutex_lock( &p_sys->csa_lock );
881 882
    if( p_sys->csa )
    {
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
883 884
        var_DelCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, NULL );
        var_DelCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
885 886
        csa_Delete( p_sys->csa );
    }
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
887
    vlc_mutex_unlock( &p_sys->csa_lock );
888

hartman's avatar
hartman committed
889
    TAB_CLEAN( p_sys->i_pmt, p_sys->pmt );
890

891
    free( p_sys->programs_list.p_values );
892

hartman's avatar
hartman committed
893 894 895 896 897
    /* When streaming, close the port */
    if( p_sys->fd > -1 )
    {
        net_Close( p_sys->fd );
    }
898

hartman's avatar
hartman committed
899
    free( p_sys->buffer );
900

901 902 903
    free( p_sys->p_pcrs );
    free( p_sys->p_pos );