ts.c 138 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

Laurent Aimar's avatar
Laurent Aimar committed
36
#include <ctype.h>
37

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

43
#include <vlc_iso_lang.h>
Clément Stenac's avatar
Clément Stenac committed
44 45
#include <vlc_network.h>
#include <vlc_charset.h>
46

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

49 50 51
/* Include dvbpsi headers */
#ifdef HAVE_DVBPSI_DR_H
#   include <dvbpsi/dvbpsi.h>
52
#   include <dvbpsi/demux.h>
53 54 55
#   include <dvbpsi/descriptor.h>
#   include <dvbpsi/pat.h>
#   include <dvbpsi/pmt.h>
56
#   include <dvbpsi/sdt.h>
57 58 59 60
#   include <dvbpsi/dr.h>
#   include <dvbpsi/psi.h>
#else
#   include "dvbpsi.h"
61
#   include "demux.h"
62 63 64
#   include "descriptor.h"
#   include "tables/pat.h"
#   include "tables/pmt.h"
65
#   include "tables/sdt.h"
66 67 68 69
#   include "descriptors/dr.h"
#   include "psi.h"
#endif

70 71 72 73 74 75 76 77 78
/* EIT support */
#ifdef _DVBPSI_DR_4D_H_
#   define TS_USE_DVB_SI 1
#   ifdef HAVE_DVBPSI_DR_H
#       include <dvbpsi/eit.h>
#   else
#       include "tables/eit.h"
#   endif
#endif
79
#ifdef HAVE_TIME_H
80
#   include <time.h>
81
#endif
82 83
#undef TS_DEBUG

84
/* TODO:
85
 *  - XXX: do not mark options message to be translated, they are too osbcure for now ...
86 87 88 89
 *  - test it
 *  - ...
 */

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
90 91 92 93 94
/*****************************************************************************
 * Callback prototypes
 *****************************************************************************/
static int ChangeKeyCallback    ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );

95 96 97
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
98 99
static int  Open  ( vlc_object_t * );
static void Close ( vlc_object_t * );
100

101 102 103
/* TODO
 * - Rename "extra pmt" to "user pmt"
 * - Update extra pmt description
104
 *      pmt_pid[:pmt_number][=pid_description[,pid_description]]
105 106 107
 *      where pid_description could take 3 forms:
 *          1. pid:pcr (to force the pcr pid)
 *          2. pid:stream_type
108
 *          3. pid:type=fourcc where type=(video|audio|spu)
109
 */
110 111
#define PMT_TEXT N_("Extra PMT")
#define PMT_LONGTEXT N_( \
112
  "Allows a user to specify an extra pmt (pmt_pid=pid:stream_type[,...])." )
113 114

#define PID_TEXT N_("Set id of ES to PID")
115 116 117 118
#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>\"}\'.")
119 120 121

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

#define MTUOUT_TEXT N_("MTU for out mode")
125
#define MTUOUT_LONGTEXT N_("MTU for out mode.")
126 127

#define CSA_TEXT N_("CSA ck")
Christophe Mutricy's avatar
Typo  
Christophe Mutricy committed
128
#define CSA_LONGTEXT N_("Control word for the CSA encryption algorithm")
129

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
130 131 132 133
#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).")

134
#define SILENT_TEXT N_("Silent mode")
135
#define SILENT_LONGTEXT N_("Do not complain on encrypted PES.")
136

137
#define CAPMT_SYSID_TEXT N_("CAPMT System ID")
138
#define CAPMT_SYSID_LONGTEXT N_("Only forward descriptors from this SysID to the CAM.")
139

140 141 142 143 144 145
#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. " )

#define TSDUMP_TEXT N_("Filename of dump")
146
#define TSDUMP_LONGTEXT N_("Specify a filename where to dump the TS in.")
147 148 149 150 151 152 153 154 155 156 157

#define APPEND_TEXT N_("Append")
#define APPEND_LONGTEXT N_( \
    "If the file exists and this option is selected, the existing file " \
    "will not be overwritten." )

#define DUMPSIZE_TEXT N_("Dump buffer size")
#define DUMPSIZE_LONGTEXT N_( \
    "Tweak the buffer size for reading and writing an integer number of packets." \
    "Specify the size of the buffer here and not the number of packets." )

158
vlc_module_begin();
159
    set_description( N_("MPEG Transport Stream demuxer") );
160
    set_shortname ( "MPEG-TS" );
Clément Stenac's avatar
Clément Stenac committed
161 162
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_DEMUX );
163

164 165 166
    add_string( "ts-extra-pmt", NULL, NULL, PMT_TEXT, PMT_LONGTEXT, true );
    add_bool( "ts-es-id-pid", 1, NULL, PID_TEXT, PID_LONGTEXT, true );
    add_string( "ts-out", NULL, NULL, TSOUT_TEXT, TSOUT_LONGTEXT, true );
167
    add_integer( "ts-out-mtu", 1400, NULL, MTUOUT_TEXT,
168 169
                 MTUOUT_LONGTEXT, true );
    add_string( "ts-csa-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
170
    add_string( "ts-csa2-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true );
171 172
    add_integer( "ts-csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true );
    add_bool( "ts-silent", 0, NULL, SILENT_TEXT, SILENT_LONGTEXT, true );
173

174
    add_file( "ts-dump-file", NULL, NULL, TSDUMP_TEXT, TSDUMP_LONGTEXT, false );
175
        change_unsafe();
176
    add_bool( "ts-dump-append", 0, NULL, APPEND_TEXT, APPEND_LONGTEXT, false );
177
    add_integer( "ts-dump-size", 16384, NULL, DUMPSIZE_TEXT,
178
                 DUMPSIZE_LONGTEXT, true );
179

180
    set_capability( "demux", 10 );
181
    set_callbacks( Open, Close );
Laurent Aimar's avatar
Laurent Aimar committed
182
    add_shortcut( "ts" );
183 184 185 186 187 188 189 190 191 192
vlc_module_end();

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

typedef struct
{
    uint8_t                 i_objectTypeIndication;
    uint8_t                 i_streamType;
193
    bool                    b_upStream;
194 195 196 197 198 199 200 201 202 203 204
    uint32_t                i_bufferSizeDB;
    uint32_t                i_maxBitrate;
    uint32_t                i_avgBitrate;

    int                     i_decoder_specific_info_len;
    uint8_t                 *p_decoder_specific_info;

} decoder_config_descriptor_t;

typedef struct
{
205 206 207 208 209 210 211 212
    bool                    b_useAccessUnitStartFlag;
    bool                    b_useAccessUnitEndFlag;
    bool                    b_useRandomAccessPointFlag;
    bool                    b_useRandomAccessUnitsOnlyFlag;
    bool                    b_usePaddingFlag;
    bool                    b_useTimeStampsFlags;
    bool                    b_useIdleFlag;
    bool                    b_durationFlag;
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    uint32_t                i_timeStampResolution;
    uint32_t                i_OCRResolution;
    uint8_t                 i_timeStampLength;
    uint8_t                 i_OCRLength;
    uint8_t                 i_AU_Length;
    uint8_t                 i_instantBitrateLength;
    uint8_t                 i_degradationPriorityLength;
    uint8_t                 i_AU_seqNumLength;
    uint8_t                 i_packetSeqNumLength;

    uint32_t                i_timeScale;
    uint16_t                i_accessUnitDuration;
    uint16_t                i_compositionUnitDuration;

    uint64_t                i_startDecodingTimeStamp;
    uint64_t                i_startCompositionTimeStamp;

} sl_config_descriptor_t;

typedef struct
{
234
    bool                    b_ok;
235 236
    uint16_t                i_es_id;

237 238
    bool                    b_streamDependenceFlag;
    bool                    b_OCRStreamFlag;
239 240 241 242 243 244 245 246 247
    uint8_t                 i_streamPriority;

    char                    *psz_url;

    uint16_t                i_dependOn_es_id;
    uint16_t                i_OCR_es_id;

    decoder_config_descriptor_t    dec_descr;
    sl_config_descriptor_t         sl_descr;
248

249 250 251 252
} es_mpeg4_descriptor_t;

typedef struct
{
253
    uint8_t                 i_iod_label, i_iod_label_scope;
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

    /* IOD */
    uint16_t                i_od_id;
    char                    *psz_url;

    uint8_t                 i_ODProfileLevelIndication;
    uint8_t                 i_sceneProfileLevelIndication;
    uint8_t                 i_audioProfileLevelIndication;
    uint8_t                 i_visualProfileLevelIndication;
    uint8_t                 i_graphicsProfileLevelIndication;

    es_mpeg4_descriptor_t   es_descr[255];

} iod_descriptor_t;

typedef struct
{
271 272
    dvbpsi_handle   handle;

273 274 275
    int             i_version;
    int             i_number;
    int             i_pid_pcr;
276
    int             i_pid_pmt;
277 278
    /* IOD stuff (mpeg4) */
    iod_descriptor_t *iod;
279

280 281
} ts_prg_psi_t;

282 283 284 285
typedef struct
{
    /* for special PAT/SDT case */
    dvbpsi_handle   handle; /* PAT/SDT/EIT */
286
    int             i_pat_version;
287
    int             i_sdt_version;
288 289 290 291

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

293 294 295 296 297 298
} ts_psi_t;

typedef struct
{
    es_format_t  fmt;
    es_out_id_t *id;
299 300
    int         i_pes_size;
    int         i_pes_gathered;
301
    block_t     *p_pes;
302
    block_t     **pp_last;
303 304

    es_mpeg4_descriptor_t *p_mpeg4desc;
305
    int         b_gather;
306

307 308 309 310 311 312
} ts_es_t;

typedef struct
{
    int         i_pid;

313 314
    bool        b_seen;
    bool        b_valid;
315 316 317 318
    int         i_cc;   /* countinuity counter */

    /* PSI owner (ie PMT -> PAT, ES -> PMT */
    ts_psi_t   *p_owner;
319
    int         i_owner_number;
320 321 322 323 324

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

325 326 327 328
    /* Some private streams encapsulate several ES (eg. DVB subtitles)*/
    ts_es_t     **extra_es;
    int         i_extra_es;

329 330 331 332
} ts_pid_t;

struct demux_sys_t
{
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
333 334
    vlc_mutex_t     csa_lock;

335 336 337
    /* TS packet size (188, 192, 204) */
    int         i_packet_size;

338 339 340
    /* how many TS packet we read at once */
    int         i_ts_read;

341 342 343 344
    /* All pid */
    ts_pid_t    pid[8192];

    /* All PMT */
345
    bool        b_user_pmt;
346 347
    int         i_pmt;
    ts_pid_t    **pmt;
348 349

    /* */
350
    bool        b_es_id_pid;
351
    csa_t       *csa;
352
    int         i_csa_pkt_size;
353
    bool        b_silent;
354

355
    bool        b_udp_out;
356 357
    int         fd; /* udp socket */
    uint8_t     *buffer;
358

359
    bool        b_dvb_control;
360
    int         i_dvb_program;
361 362
    int64_t     i_dvb_start;
    int64_t     i_dvb_length;
363
    vlc_list_t  *p_programs_list;
364

365 366 367 368
    /* TS dump */
    char        *psz_file;  /* file to dump data in */
    FILE        *p_file;    /* filehandle */
    uint64_t    i_write;    /* bytes written */
369
    bool        b_file_out; /* dump mode enabled */
370

371
    /* */
372
    bool        b_meta;
373 374
};

375 376
static int Demux    ( demux_t *p_demux );
static int DemuxFile( demux_t *p_demux );
377 378
static int Control( demux_t *p_demux, int i_query, va_list args );

379
static void PIDInit ( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner );
380 381 382
static void PIDClean( es_out_t *out, ts_pid_t *pid );
static int  PIDFillFormat( ts_pid_t *pid, int i_stream_type );

383 384
static void PATCallBack( demux_t *, dvbpsi_pat_t * );
static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt );
385
#ifdef TS_USE_DVB_SI
386 387
static void PSINewTableCallBack( demux_t *, dvbpsi_handle,
                                 uint8_t  i_table_id, uint16_t i_extension );
388
#endif
389

390 391 392 393 394
static inline int PIDGet( block_t *p )
{
    return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
}

395
static bool GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
396

397 398
static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );

399
static iod_descriptor_t *IODNew( int , uint8_t * );
400
static void              IODFree( iod_descriptor_t * );
401

402
#define TS_USER_PMT_NUMBER (0)
403 404
static int UserPmt( demux_t *p_demux, const char * );

405 406 407 408
#define TS_PACKET_SIZE_188 188
#define TS_PACKET_SIZE_192 192
#define TS_PACKET_SIZE_204 204
#define TS_PACKET_SIZE_MAX 204
409
#define TS_TOPFIELD_HEADER 1320
410 411 412 413 414 415 416 417 418

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

419
    const uint8_t *p_peek;
420 421
    int          i_sync, i_peek, i;
    int          i_packet_size;
422

423
    ts_pid_t    *pat;
Clément Stenac's avatar
Clément Stenac committed
424
    const char  *psz_mode;
425 426
    bool         b_append;
    bool         b_topfield = false;
427 428 429

    vlc_value_t  val;

430
    if( stream_Peek( p_demux->s, &p_peek, TS_PACKET_SIZE_MAX ) <
431
        TS_PACKET_SIZE_MAX ) return VLC_EGENERIC;
432

433
    if( memcmp( p_peek, "TFrc", 4 ) == 0 )
434
    {
435
        b_topfield = true;
436 437 438
        msg_Dbg( p_demux, "this is a topfield file" );
    }

439 440
    /* Search first sync byte */
    for( i_sync = 0; i_sync < TS_PACKET_SIZE_MAX; i_sync++ )
441 442 443
    {
        if( p_peek[i_sync] == 0x47 ) break;
    }
444
    if( i_sync >= TS_PACKET_SIZE_MAX && !b_topfield )
445
    {
446 447
        if( !p_demux->b_force )
            return VLC_EGENERIC;
448 449
        msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
    }
450

451 452 453 454 455 456 457 458 459 460
    if( b_topfield )
    {
        /* Read the entire Topfield header */
        i_peek = TS_TOPFIELD_HEADER;
    }
    else
    {
        /* Check next 3 sync bytes */
        i_peek = TS_PACKET_SIZE_MAX * 3 + i_sync + 1;
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
461

462
    if( ( stream_Peek( p_demux->s, &p_peek, i_peek ) ) < i_peek )
463
    {
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
        msg_Err( p_demux, "cannot peek" );
        return VLC_EGENERIC;
    }
    if( p_peek[i_sync + 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 )
    {
        i_packet_size = TS_PACKET_SIZE_188;
    }
    else if( p_peek[i_sync + 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 )
    {
        i_packet_size = TS_PACKET_SIZE_192;
    }
    else if( p_peek[i_sync + 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 )
    {
        i_packet_size = TS_PACKET_SIZE_204;
    }
485
    else if( p_demux->b_force )
486 487 488
    {
        i_packet_size = TS_PACKET_SIZE_188;
    }
489 490 491 492
    else if( b_topfield )
    {
        i_packet_size = TS_PACKET_SIZE_188;
#if 0
493
        /* I used the TF5000PVR 2004 Firmware .doc header documentation,
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
         * 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;
        char *psz_name = malloc(25);
        char *psz_event_name;
        char *psz_event_text = malloc(130);
        char *psz_ext_text = malloc(1025);

        // 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)
524
        // 4 bytes reserved
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
        // 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);
        psz_event_name = malloc( i_name+1 );
        // 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
    }
556 557 558 559
    else
    {
        msg_Warn( p_demux, "TS module discarded (lost sync)" );
        return VLC_EGENERIC;
560
    }
561

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

    /* Fill dump mode fields */
    p_sys->i_write = 0;
    p_sys->p_file = NULL;
572
    p_sys->b_file_out = false;
573 574 575
    p_sys->psz_file = var_CreateGetString( p_demux, "ts-dump-file" );
    if( *p_sys->psz_file != '\0' )
    {
576
        p_sys->b_file_out = true;
577 578 579 580 581 582 583 584 585 586 587 588 589 590

        var_Create( p_demux, "ts-dump-append", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
        var_Get( p_demux, "ts-dump-append", &val );
        b_append = val.b_bool;
        if ( b_append )
            psz_mode = "ab";
        else
            psz_mode = "wb";

        if( !strcmp( p_sys->psz_file, "-" ) )
        {
            msg_Info( p_demux, "dumping raw stream to standard output" );
            p_sys->p_file = stdout;
        }
591
        else if( ( p_sys->p_file = utf8_fopen( p_sys->psz_file, psz_mode ) ) == NULL )
592 593
        {
            msg_Err( p_demux, "cannot create `%s' for writing", p_sys->psz_file );
594
            p_sys->b_file_out = false;
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
        }

        if( p_sys->b_file_out )
        {
            vlc_value_t bufsize;

            /* Determine how many packets to read. */
            var_Create( p_demux, "ts-dump-size",
                        VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
            var_Get( p_demux, "ts-dump-size", &bufsize );
            p_sys->i_ts_read = (int) (bufsize.i_int / p_sys->i_packet_size);
            if( p_sys->i_ts_read <= 0 )
            {
                p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
            }
            p_sys->buffer = malloc( p_sys->i_packet_size * p_sys->i_ts_read );
            msg_Info( p_demux, "%s raw stream to file `%s' reading packets %d",
                      b_append ? "appending" : "dumping", p_sys->psz_file,
                      p_sys->i_ts_read );
        }
    }

617
    /* Fill p_demux field */
618 619 620 621
    if( p_sys->b_file_out )
        p_demux->pf_demux = DemuxFile;
    else
        p_demux->pf_demux = Demux;
622 623 624
    p_demux->pf_control = Control;

    /* Init p_sys field */
625 626
    p_sys->b_meta = true;
    p_sys->b_dvb_control = true;
627
    p_sys->i_dvb_program = 0;
628
    p_sys->i_dvb_start = 0;
629 630
    p_sys->i_dvb_length = 0;

631 632 633 634 635
    for( i = 0; i < 8192; i++ )
    {
        ts_pid_t *pid = &p_sys->pid[i];

        pid->i_pid      = i;
636 637
        pid->b_seen     = false;
        pid->b_valid    = false;
638
    }
639
    /* PID 8191 is padding */
640
    p_sys->pid[8191].b_seen = true;
641
    p_sys->i_packet_size = i_packet_size;
642
    p_sys->b_udp_out = false;
643
    p_sys->i_ts_read = 50;
644
    p_sys->csa = NULL;
645 646 647

    /* Init PAT handler */
    pat = &p_sys->pid[0];
648
    PIDInit( pat, true, NULL );
649 650
    pat->psi->handle = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack,
                                         p_demux );
651
#ifdef TS_USE_DVB_SI
652 653 654 655 656
    if( p_sys->b_meta )
    {
        ts_pid_t *sdt = &p_sys->pid[0x11];
        ts_pid_t *eit = &p_sys->pid[0x12];

657
        PIDInit( sdt, true, NULL );
658 659 660
        sdt->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
661
        PIDInit( eit, true, NULL );
662 663 664
        eit->psi->handle =
            dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
                                p_demux );
665 666
        if( p_sys->b_dvb_control )
        {
667
            if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
668
                                ACCESS_SET_PRIVATE_ID_STATE, 0x11, true ) ||
669
                stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
670 671
                                ACCESS_SET_PRIVATE_ID_STATE, 0x12, true ) )
                p_sys->b_dvb_control = false;
672 673 674
        }
    }
#endif
675 676 677 678 679

    /* Init PMT array */
    p_sys->i_pmt = 0;
    p_sys->pmt   = NULL;

680
    /* Read config */
681 682
    var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "ts-es-id-pid", &val );
683
    p_sys->b_es_id_pid = val.b_bool;
684

685 686
    var_Create( p_demux, "ts-out", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "ts-out", &val );
687
    if( val.psz_string && *val.psz_string && !p_sys->b_file_out )
688 689 690 691 692
    {
        vlc_value_t mtu;
        char *psz = strchr( val.psz_string, ':' );
        int   i_port = 0;

693
        p_sys->b_udp_out = true;
694 695 696 697 698 699 700 701 702

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

703
        p_sys->fd = net_ConnectUDP( VLC_OBJECT(p_demux), val.psz_string, i_port, 0 );
704 705 706
        if( p_sys->fd < 0 )
        {
            msg_Err( p_demux, "failed to open udp socket, send disabled" );
707
            p_sys->b_udp_out = false;
708 709 710
        }
        else
        {
711 712
            var_Create( p_demux, "ts-out-mtu",
                        VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
713
            var_Get( p_demux, "ts-out-mtu", &mtu );
714
            p_sys->i_ts_read = mtu.i_int / p_sys->i_packet_size;
715 716
            if( p_sys->i_ts_read <= 0 )
            {
717
                p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
718
            }
719
            p_sys->buffer = malloc( p_sys->i_packet_size * p_sys->i_ts_read );
720 721
        }
    }
722
    free( val.psz_string );
723

724 725 726
    /* We handle description of an extra PMT */
    var_Create( p_demux, "ts-extra-pmt", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "ts-extra-pmt", &val );
727 728
    p_sys->b_user_pmt = false;
    if( val.psz_string && *val.psz_string )
729
        UserPmt( p_demux, val.psz_string );
730
    free( val.psz_string );
731

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
732
    var_Create( p_demux, "ts-csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
733 734 735
    var_Get( p_demux, "ts-csa-ck", &val );
    if( val.psz_string && *val.psz_string )
    {
736
        int i_res;
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
737
        vlc_value_t csa2;
738 739 740

        p_sys->csa = csa_New();

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
        var_Create( p_demux, "ts-csa2-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND);
        var_Get( p_demux, "ts-csa2-ck", &csa2 );
        i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, true );
        if( i_res == VLC_SUCCESS && csa2.psz_string && *csa2.psz_string )
        {
            if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, csa2.psz_string, false ) != VLC_SUCCESS )
            {
                csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false );
            }
        }
        else if ( i_res == VLC_SUCCESS )
        {
            csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false );
        }
        else
756
        {
757
            csa_Delete( p_sys->csa );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
758
            p_sys->csa = NULL;
759
        }
760 761

        if( p_sys->csa )
762
        {
763
            vlc_value_t pkt_val;
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 770
            var_Create( p_demux, "ts-csa-pkt", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
            var_Get( p_demux, "ts-csa-pkt", &pkt_val );
            if( pkt_val.i_int < 4 || pkt_val.i_int > 188 )
771
            {
772 773 774
                msg_Err( p_demux, "wrong packet size %d specified.", pkt_val.i_int );
                msg_Warn( p_demux, "using default packet size of 188 bytes" );
                p_sys->i_csa_pkt_size = 188;
775
            }
776 777
            else p_sys->i_csa_pkt_size = pkt_val.i_int;
            msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size );
778
        }
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
779
        free( csa2.psz_string );
780
    }
781
    free( val.psz_string );
782

783 784 785
    var_Create( p_demux, "ts-silent", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "ts-silent", &val );
    p_sys->b_silent = val.b_bool;
786

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
    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;

    int          i;

    msg_Dbg( p_demux, "pid list:" );
    for( i = 0; i < 8192; i++ )
    {
        ts_pid_t *pid = &p_sys->pid[i];

        if( pid->b_valid && pid->psi )
        {
            switch( pid->i_pid )
            {
                case 0: /* PAT */
                    dvbpsi_DetachPAT( pid->psi->handle );
811
                    free( pid->psi );
812 813
                    break;
                case 1: /* CAT */
814
                    free( pid->psi );
815
                    break;
816 817 818 819 820
                case 0x11: /* SDT */
                case 0x12: /* EIT */
                    dvbpsi_DetachDemux( pid->psi->handle );
                    free( pid->psi );
                    break;
821
                default:
822
                    PIDClean( p_demux->out, pid );
823 824 825 826 827
                    break;
            }
        }
        else if( pid->b_valid && pid->es )
        {
828
            PIDClean( p_demux->out, pid );
829
        }
830

831 832
        if( pid->b_seen )
        {
833
            msg_Dbg( p_demux, "  - pid[%d] seen", pid->i_pid );
834
        }
835 836 837 838

        if( p_sys->b_dvb_control && pid->i_pid > 0 )
        {
            /* too much */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
839 840
            stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
                            ACCESS_SET_PRIVATE_ID_STATE, pid->i_pid,
841
                            false );
842 843
        }

844 845
    }

846 847 848 849 850
    if( p_sys->b_udp_out )
    {
        net_Close( p_sys->fd );
        free( p_sys->buffer );
    }
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
851
    vlc_mutex_lock( &p_sys->csa_lock );
852 853
    if( p_sys->csa )
    {
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
854 855
        var_DelCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, NULL );
        var_DelCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
856
        csa_Delete( p_sys->csa );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
857
        p_sys->csa = NULL;
858
    }
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
859
    vlc_mutex_unlock( &p_sys->csa_lock );
860

Gildas Bazin's avatar
 
Gildas Bazin committed
861
    if( p_sys->i_pmt ) free( p_sys->pmt );
862 863 864 865 866 867 868 869

    if ( p_sys->p_programs_list )
    {
        vlc_value_t val;
        val.p_list = p_sys->p_programs_list;
        var_Change( p_demux, "programs", VLC_VAR_FREELIST, &val, NULL );
    }

870 871 872
    /* If in dump mode, then close the file */
    if( p_sys->b_file_out )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
873
        msg_Info( p_demux ,"closing %s (%"PRId64" Kbytes dumped)",
Jean-Paul Saman's avatar
Jean-Paul Saman committed
874
                  p_sys->psz_file, p_sys->i_write / 1024 );
875 876 877 878 879 880 881 882 883 884

        if( p_sys->p_file != stdout )
        {
            fclose( p_sys->p_file );
            p_sys->p_file = NULL;
        }

        free( p_sys->buffer );
    }

885 886 887
    free( p_sys->psz_file );
    p_sys->psz_file = NULL;

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
888
    vlc_mutex_destroy( &p_sys->csa_lock );
889 890 891
    free( p_sys );
}

Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
/*****************************************************************************
 * 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;
}

914 915 916 917
/*****************************************************************************
 * DemuxFile:
 *****************************************************************************/
static int DemuxFile( demux_t *p_demux )
918
{
919 920 921 922 923 924
    demux_sys_t *p_sys = p_demux->p_sys;
    uint8_t     *p_buffer = p_sys->buffer; /* Put first on sync byte */
    int i_diff= 0;
    int i_data= 0;
    int i_pos = 0;
    int i_bufsize = p_sys->i_packet_size * p_sys->i_ts_read;
925

926 927 928
    i_data = stream_Read( p_demux->s, p_sys->buffer, i_bufsize );
    if( (i_data <= 0) && (i_data < p_sys->i_packet_size) )
    {
929
        msg_Dbg( p_demux, "error reading malformed packets" );
930 931 932 933 934 935
        return i_data;
    }

    /* Test continuity counter */
    while( i_pos < i_data )
    {
936 937 938 939
        ts_pid_t *p_pid;   /* point to a PID structure */
        bool      b_payload; /* indicates a packet with payload */
        bool      b_adaptation; /* adaptation field */
        int       i_cc  = 0;    /* continuity counter */
940

941 942 943
        if( p_sys->buffer[i_pos] != 0x47 )
        {
            msg_Warn( p_demux, "lost sync" );
944
            while( vlc_object_alive (p_demux) && (i_pos < i_data) )
945 946 947 948 949
            {
                i_pos++;
                if( p_sys->buffer[i_pos] == 0x47 )
                    break;
            }
950
            if( vlc_object_alive (p_demux) )
951 952
                msg_Warn( p_demux, "sync found" );
        }
953

954 955 956 957 958 959 960 961 962
        /* continuous when (one of this):
         * diff == 1
         * diff == 0 and payload == 0
         * diff == 0 and duplicate packet (playload != 0) <- should we
         *   test the content ?
         */
        i_cc  = p_buffer[i_pos+3]&0x0f;
        b_payload = p_buffer[i_pos+3]&0x10;
        b_adaptation = p_buffer[i_pos+3]&0x20;
963

964 965
        /* Get the PID */
        p_pid = &p_sys->pid[ ((p_buffer[i_pos+1]&0x1f)<<8)|p_buffer[i_pos+2] ];
966

967
        /* Detect discontinuity indicator in adaptation field */
968
        if( b_adaptation && p_buffer[i_pos + 4] > 0 )
969 970 971 972 973 974
        {
            if( p_buffer[i_pos+5]&0x80 )
                msg_Warn( p_demux, "discontinuity indicator (pid=%d) ", p_pid->i_pid );
            if( p_buffer[i_pos+5]&0x40 )
                msg_Warn( p_demux, "random access indicator (pid=%d) ", p_pid->i_pid );
        }
975

976 977 978
        i_diff = ( i_cc - p_pid->i_cc )&0x0f;
        if( b_payload && i_diff == 1 )
        {
979
            p_pid->i_cc = ( p_pid->i_cc + 1 ) & 0xf;
980 981 982 983 984 985 986 987 988 989 990 991 992 993
        }
        else
        {
            if( p_pid->i_cc == 0xff )
            {
                msg_Warn( p_demux, "first packet for pid=%d cc=0x%x",
                        p_pid->i_pid, i_cc );
                p_pid->i_cc = i_cc;
            }
            else if( i_diff != 0 )
            {
                /* FIXME what to do when discontinuity_indicator is set ? */
                msg_Warn( p_demux, "transport error detected 0x%x instead of 0x%x",
                          i_cc, ( p_pid->i_cc + 1 )&0x0f );
994

995 996 997 998 999
                p_pid->i_cc = i_cc;
                /* Mark transport error in the TS packet. */
                p_buffer[i_pos+1] |= 0x80;
            }
        }
1000

1001 1002
        /* Test if user wants to decrypt it first */
        if( p_sys->csa )
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
1003 1004
        {
            vlc_mutex_lock( &p_sys->csa_lock );
1005
            csa_Decrypt( p_demux->p_sys->csa, &p_buffer[i_pos], p_demux->p_sys->i_csa_pkt_size );
Kaloyan Kovachev's avatar
Kaloyan Kovachev committed
1006 1007
            vlc_mutex_unlock( &p_sys->csa_lock );
        }
1008

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
        i_pos += p_sys->i_packet_size;
    }

    /* Then write */
    i_data = fwrite( p_sys->buffer, 1, i_data, p_sys->p_file );
    if( i_data < 0 )
    {
        msg_Err( p_demux, "failed to write data" );
        return -1;
    }
#if 0
    msg_Dbg( p_demux, "dumped %d bytes", i_data );
#endif

    p_sys->i_write += i_data;
    return 1;
}

1027 1028 1029 1030 1031 1032 1033 1034 1035
/*****************************************************************************
 * Demux:
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    int          i_pkt;

    /* We read at most 100 TS packet or until a frame is completed */
1036
    for( i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
1037
    {
1038
        bool         b_frame = false;
1039 1040 1041 1042
        block_t     *p_pkt;
        ts_pid_t    *p_pid;

        /* Get a new TS packet */
1043
        if( !( p_pkt = stream_Block( p_demux->s, p_sys->i_packet_size ) ) )
1044 1045 1046 1047
        {
            msg_Dbg( p_demux, "eof ?" );
            return 0;