Coverage Report

Created: 2026-01-17 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/ty.c
Line
Count
Source
1
/*****************************************************************************
2
 * ty.c - TiVo ty stream video demuxer for VLC
3
 *****************************************************************************
4
 * Copyright (C) 2005 VLC authors and VideoLAN
5
 * Copyright (C) 2005 by Neal Symms (tivo@freakinzoo.com) - February 2005
6
 * based on code by Christopher Wingert for tivo-mplayer
7
 * tivo(at)wingert.org, February 2003
8
 *
9
 *
10
 * This program is free software; you can redistribute it and/or modify it
11
 * under the terms of the GNU Lesser General Public License as published by
12
 * the Free Software Foundation; either version 2.1 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with this program; if not, write to the Free Software Foundation,
22
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 *
24
 * CODE CHANGES:
25
 * v1.0.0 - 24-Feb-2005 - Initial release - Series 1 support ONLY!
26
 * v1.0.1 - 25-Feb-2005 - Added fix for bad GOP headers - Neal
27
 * v1.0.2 - 26-Feb-2005 - No longer require "seekable" input stream - Neal
28
 * v2.0.0 - 21-Mar-2005 - Series 2 support!  No AC-3 on S2 DTivo yet.
29
 * v2.1.0 - 22-Mar-2005 - Support for AC-3 on S2 DTivo (long ac3 packets)
30
 * v3.0.0 - 14-Jul-2005 - Support for skipping fwd/back via VLC hotkeys
31
 *****************************************************************************/
32
33
/*****************************************************************************
34
 * Preamble
35
 *****************************************************************************/
36
37
#ifdef HAVE_CONFIG_H
38
# include "config.h"
39
#endif
40
41
#include <limits.h>
42
43
#include <vlc_common.h>
44
#include <vlc_plugin.h>
45
#include <vlc_demux.h>
46
#include <vlc_codec.h>
47
#include <vlc_meta.h>
48
#include <vlc_input_item.h>
49
#include "../codec/cc.h"
50
51
#include "mpeg/pes.h"
52
53
#include <assert.h>
54
55
/*****************************************************************************
56
 * Module descriptor
57
 *****************************************************************************/
58
static int  Open ( vlc_object_t * );
59
static void Close( vlc_object_t * );
60
61
108
vlc_module_begin ()
62
54
    set_shortname( N_("TY") )
63
54
    set_description(N_("TY Stream audio/video demux"))
64
54
    set_subcategory( SUBCAT_INPUT_DEMUX )
65
54
    set_capability("demux", 8)
66
    /* FIXME: there seems to be a segfault when using PVR access
67
     * and TY demux has a bigger priority than PS
68
     * Something must be wrong.
69
     */
70
108
    set_callbacks( Open, Close )
71
54
    add_shortcut("ty", "tivo")
72
54
    add_file_extension("ty")
73
54
    add_file_extension("ty+")
74
54
vlc_module_end ()
75
76
/*****************************************************************************
77
 * Local prototypes
78
 *****************************************************************************/
79
static int Demux  ( demux_t * );
80
static int Control( demux_t *, int, va_list );
81
82
22
#define SERIES1_PES_LENGTH  (11)    /* length of audio PES hdr on S1 */
83
655
#define SERIES2_PES_LENGTH  (16)    /* length of audio PES hdr on S2 */
84
46
#define AC3_PES_LENGTH      (14)    /* length of audio PES hdr for AC3 */
85
18.3k
#define VIDEO_PES_LENGTH    (16)    /* length of video PES header */
86
27
#define DTIVO_PTS_OFFSET    (6)     /* offs into PES for MPEG PTS on DTivo */
87
570
#define SA_PTS_OFFSET       (9)     /* offset into PES for MPEG PTS on SA */
88
46
#define AC3_PTS_OFFSET      (9)     /* offset into PES for AC3 PTS on DTivo */
89
6.11k
#define VIDEO_PTS_OFFSET    (9)     /* offset into PES for video PTS on all */
90
15
#define AC3_PKT_LENGTH      (1536)  /* size of TiVo AC3 pkts (w/o PES hdr) */
91
static const uint8_t ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 };
92
static const uint8_t ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 };
93
static const uint8_t ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd };
94
95
3.59k
#define CHUNK_PEEK_COUNT    (3)         /* number of chunks to probe */
96
97
/* packet types for reference:
98
 2/c0: audio data continued
99
 3/c0: audio packet header (PES header)
100
 4/c0: audio data (S/A only?)
101
 9/c0: audio packet header, AC-3 audio
102
 2/e0: video data continued
103
 6/e0: video packet header (PES header)
104
 7/e0: video sequence header start
105
 8/e0: video I-frame header start
106
 a/e0: video P-frame header start
107
 b/e0: video B-frame header start
108
 c/e0: video GOP header start
109
 e/01: closed-caption data
110
 e/02: Extended data services data
111
 e/03: ipreview data ("thumbs up to record" signal)
112
 e/05: UK Teletext
113
*/
114
115
7.49k
#define TIVO_PES_FILEID   ( 0xf5467abd )
116
0
#define TIVO_PART_LENGTH  ( 0x20000000 )    /* 536,870,912 bytes */
117
115k
#define CHUNK_SIZE        ( 128 * 1024 )
118
222k
#define REC_SIZE 16
119
110k
#define CHUNK_HEADER_SIZE 4
120
2.46k
#define MAX_NUM_RECS ((CHUNK_SIZE - CHUNK_HEADER_SIZE) / REC_SIZE)
121
122
typedef struct
123
{
124
  long l_rec_size;
125
  uint8_t ex[2];
126
  uint8_t rec_type;
127
  uint8_t subrec_type;
128
  bool b_ext;
129
  uint64_t l_ty_pts;            /* TY PTS in the record header */
130
} ty_rec_hdr_t;
131
132
typedef struct
133
{
134
    uint64_t l_timestamp;
135
    uint8_t chunk_bitmask[8];
136
} ty_seq_table_t;
137
138
typedef enum
139
{
140
    TIVO_TYPE_UNKNOWN,
141
    TIVO_TYPE_SA,
142
    TIVO_TYPE_DTIVO
143
} tivo_type_t;
144
145
typedef enum
146
{
147
    TIVO_SERIES_UNKNOWN,
148
    TIVO_SERIES1,
149
    TIVO_SERIES2
150
} tivo_series_t;
151
152
typedef enum
153
{
154
    TIVO_AUDIO_UNKNOWN,
155
    TIVO_AUDIO_AC3,
156
    TIVO_AUDIO_MPEG
157
} tivo_audio_t;
158
159
8.13k
#define XDS_MAX_DATA_SIZE (32)
160
typedef enum
161
{
162
    XDS_CLASS_CURRENT        = 0,
163
    XDS_CLASS_FUTURE         = 1,
164
    XDS_CLASS_CHANNEL        = 2,
165
    XDS_CLASS_MISCELLANEOUS  = 3,
166
    XDS_CLASS_PUBLIC_SERVICE = 4,
167
    XDS_CLASS_RESERVED       = 5,
168
    XDS_CLASS_UNDEFINED      = 6,
169
    XDS_CLASS_OTHER          = 7,
170
171
    XDS_MAX_CLASS_COUNT
172
} xds_class_t;
173
typedef struct
174
{
175
    bool b_started;
176
    size_t     i_data;
177
    uint8_t    p_data[XDS_MAX_DATA_SIZE];
178
    int        i_sum;
179
} xds_packet_t;
180
typedef enum
181
{
182
    XDS_META_PROGRAM_RATING_NONE,
183
    XDS_META_PROGRAM_RATING_MPAA,
184
    XDS_META_PROGRAM_RATING_TPG,
185
    /* TODO add CA/CE rating */
186
} xds_meta_program_rating_t;
187
typedef struct
188
{
189
    char *psz_name;
190
    xds_meta_program_rating_t rating;
191
    char *psz_rating;
192
    /* Add the other fields once I have the samples */
193
} xds_meta_program_t;
194
typedef struct
195
{
196
    char *psz_channel_name;
197
    char *psz_channel_call_letter;
198
    char *psz_channel_number;
199
200
    xds_meta_program_t  current;
201
    xds_meta_program_t  future;
202
} xds_meta_t;
203
typedef struct
204
{
205
    /* Are we in XDS mode */
206
    bool b_xds;
207
208
    /* Current class type */
209
    xds_class_t i_class;
210
    int         i_type;
211
    bool  b_future;
212
213
    /* */
214
    xds_packet_t pkt[XDS_MAX_CLASS_COUNT][128]; /* XXX it is way too much, but simpler */
215
216
    /* */
217
    bool  b_meta_changed;
218
    xds_meta_t  meta;
219
220
} xds_t;
221
222
typedef struct
223
{
224
  es_out_id_t *p_video;               /* ptr to video codec */
225
  es_out_id_t *p_audio;               /* holds either ac3 or mpeg codec ptr */
226
227
  cc_data_t   cc;
228
  es_out_id_t *p_cc[4];
229
230
  xds_t       xds;
231
232
  int             i_cur_chunk;
233
  int             i_stuff_cnt;
234
  size_t          i_stream_size;      /* size of input stream (if known) */
235
  //uint64_t        l_program_len;      /* length of this stream in msec */
236
  bool      b_seekable;         /* is this stream seekable? */
237
  bool      b_have_master;      /* are master chunks present? */
238
  tivo_type_t     tivo_type;          /* tivo type (SA / DTiVo) */
239
  tivo_series_t   tivo_series;        /* Series1 or Series2 */
240
  tivo_audio_t    audio_type;         /* AC3 or MPEG */
241
  int             i_Pes_Length;       /* Length of Audio PES header */
242
  int             i_Pts_Offset;       /* offset into audio PES of PTS */
243
  uint8_t         pes_buffer[20];     /* holds incomplete pes headers */
244
  int             i_pes_buf_cnt;      /* how many bytes in our buffer */
245
  size_t          l_ac3_pkt_size;     /* len of ac3 pkt we've seen so far */
246
  uint64_t        l_last_ty_pts;      /* last TY timestamp we've seen */
247
  //vlc_tick_t      l_last_ty_pts_sync; /* audio PTS at time of last TY PTS */
248
  uint64_t        l_first_ty_pts;     /* first TY PTS in this master chunk */
249
  uint64_t        l_final_ty_pts;     /* final TY PTS in this master chunk */
250
  unsigned        i_seq_table_size;   /* number of entries in SEQ table */
251
  unsigned        i_bits_per_seq_entry; /* # of bits in SEQ table bitmask */
252
253
  vlc_tick_t      lastAudioPTS;
254
  vlc_tick_t      lastVideoPTS;
255
256
  ty_rec_hdr_t    *rec_hdrs;          /* record headers array */
257
  int             i_cur_rec;          /* current record in this chunk */
258
  int             i_num_recs;         /* number of recs in this chunk */
259
  int             i_seq_rec;          /* record number where seq start is */
260
  ty_seq_table_t  *seq_table;         /* table of SEQ entries from mstr chk */
261
  bool      eof;
262
  bool      b_first_chunk;
263
} demux_sys_t;
264
265
static int get_chunk_header(demux_t *);
266
static vlc_tick_t get_pts( const uint8_t *buf );
267
static int find_es_header( const uint8_t *header,
268
                           const uint8_t *buffer, size_t buffer_len, size_t i_search_len );
269
static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct);
270
static int ty_stream_seek_time(demux_t *, uint64_t);
271
272
static ty_rec_hdr_t *parse_chunk_headers( const uint8_t *p_buf,
273
                                          int i_num_recs, int *pi_payload_size);
274
static int probe_stream(demux_t *p_demux);
275
static int analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk);
276
static int  parse_master(demux_t *p_demux);
277
278
static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
279
static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
280
static bool DemuxRecCc( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
281
282
static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 );
283
284
static void XdsInit( xds_t * );
285
static void XdsExit( xds_t * );
286
287
4.26k
#define TY_ES_GROUP (1)
288
289
/*
290
 * Open: check file and initialize demux structures
291
 *
292
 * here's what we do:
293
 * 1. peek at the first 12 bytes of the stream for the
294
 *    magic TiVo PART header & stream type & chunk size
295
 * 2. if it's not there, error with VLC_EGENERIC
296
 * 3. set up video (mpgv) codec
297
 * 4. return VLC_SUCCESS
298
 */
299
static int Open(vlc_object_t *p_this)
300
1.27k
{
301
1.27k
    demux_t *p_demux = (demux_t *)p_this;
302
1.27k
    demux_sys_t *p_sys;
303
1.27k
    es_format_t fmt;
304
1.27k
    const uint8_t *p_peek;
305
1.27k
    int i;
306
307
    /* peek at the first 12 bytes. */
308
    /* for TY streams, they're always the same */
309
1.27k
    if( vlc_stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
310
0
        return VLC_EGENERIC;
311
312
1.27k
    if ( U32_AT(p_peek) != TIVO_PES_FILEID ||
313
651
         U32_AT(&p_peek[4]) != 0x02 ||
314
632
         U32_AT(&p_peek[8]) != CHUNK_SIZE )
315
675
    {
316
675
        if( !p_demux->obj.force )
317
525
            return VLC_EGENERIC;
318
150
        msg_Warn( p_demux, "this does not look like a TY file, "
319
150
                           "continuing anyway..." );
320
150
    }
321
322
    /* at this point, we assume we have a valid TY stream */
323
747
    msg_Dbg( p_demux, "valid TY stream detected" );
324
325
747
    p_sys = malloc(sizeof(demux_sys_t));
326
747
    if( unlikely(p_sys == NULL) )
327
0
        return VLC_ENOMEM;
328
329
    /* Set exported functions */
330
747
    p_demux->pf_demux = Demux;
331
747
    p_demux->pf_control = Control;
332
333
    /* create our structure that will hold all data */
334
747
    p_demux->p_sys = p_sys;
335
747
    memset(p_sys, 0, sizeof(demux_sys_t));
336
337
    /* set up our struct (most were zero'd out with the memset above) */
338
747
    p_sys->b_first_chunk = true;
339
747
    p_sys->b_have_master = (U32_AT(p_peek) == TIVO_PES_FILEID);
340
747
    p_sys->lastAudioPTS  = VLC_TICK_INVALID;
341
747
    p_sys->lastVideoPTS  = VLC_TICK_INVALID;
342
747
    p_sys->i_stream_size = stream_Size(p_demux->s);
343
747
    p_sys->tivo_type = TIVO_TYPE_UNKNOWN;
344
747
    p_sys->audio_type = TIVO_AUDIO_UNKNOWN;
345
747
    p_sys->tivo_series = TIVO_SERIES_UNKNOWN;
346
747
    p_sys->i_Pes_Length = 0;
347
747
    p_sys->i_Pts_Offset = 0;
348
747
    p_sys->l_ac3_pkt_size = 0;
349
350
    /* see if this stream is seekable */
351
747
    vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
352
353
747
    if (probe_stream(p_demux) != VLC_SUCCESS) {
354
        //TyClose(p_demux);
355
118
        free(p_sys);
356
118
        return VLC_EGENERIC;
357
118
    }
358
359
629
    if (!p_sys->b_have_master)
360
629
      msg_Warn(p_demux, "No master chunk found; seeking will be limited.");
361
362
    /* register the proper audio codec */
363
629
    if (p_sys->audio_type == TIVO_AUDIO_MPEG) {
364
598
        es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_MPGA );
365
598
    } else {
366
31
        es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_A52 );
367
31
    }
368
629
    fmt.i_group = TY_ES_GROUP;
369
629
    p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
370
371
    /* register the video stream */
372
629
    es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_MPGV );
373
629
    fmt.i_group = TY_ES_GROUP;
374
629
    p_sys->p_video = es_out_Add( p_demux->out, &fmt );
375
376
    /* */
377
3.14k
    for( i = 0; i < 4; i++ )
378
2.51k
        p_sys->p_cc[i] = NULL;
379
629
    cc_Init( &p_sys->cc );
380
381
629
    XdsInit( &p_sys->xds );
382
383
629
    return VLC_SUCCESS;
384
747
}
385
386
/* =========================================================================== */
387
/* Demux: Read & Demux one record from the chunk
388
 *
389
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
390
 *
391
 * NOTE: I think we can return the number of packets sent instead of just 1.
392
 * that means we can demux an entire chunk and shoot it back (may be more efficient)
393
 * -- should try that some day :) --
394
 */
395
static int Demux( demux_t *p_demux )
396
90.6k
{
397
90.6k
    demux_sys_t  *p_sys = p_demux->p_sys;
398
90.6k
    ty_rec_hdr_t *p_rec;
399
90.6k
    block_t      *p_block_in = NULL;
400
401
    /*msg_Dbg(p_demux, "ty demux processing" );*/
402
403
    /* did we hit EOF earlier? */
404
90.6k
    if( p_sys->eof )
405
0
        return VLC_DEMUXER_EOF;
406
407
    /*
408
     * what we do (1 record now.. maybe more later):
409
    * - use vlc_stream_Read() to read the chunk header & record headers
410
    * - discard entire chunk if it is a PART header chunk
411
    * - parse all the headers into record header array
412
    * - keep a pointer of which record we're on
413
    * - use vlc_stream_Block() to fetch each record
414
    * - parse out PTS from PES headers
415
    * - set PTS for data packets
416
    * - pass the data on to the proper codec via es_out_Send()
417
418
    * if this is the first time or
419
    * if we're at the end of this chunk, start a new one
420
    */
421
    /* parse the next chunk's record headers */
422
90.6k
    if( p_sys->b_first_chunk || p_sys->i_cur_rec >= p_sys->i_num_recs )
423
1.78k
    {
424
1.78k
        if( get_chunk_header(p_demux) == 0 || p_sys->i_num_recs == 0 )
425
485
            return VLC_DEMUXER_EOF;
426
1.78k
    }
427
428
    /*======================================================================
429
     * parse & send one record of the chunk
430
     *====================================================================== */
431
90.1k
    p_rec = &p_sys->rec_hdrs[p_sys->i_cur_rec];
432
433
90.1k
    if( !p_rec->b_ext )
434
49.9k
    {
435
49.9k
        const long l_rec_size = p_rec->l_rec_size;
436
        /*msg_Dbg(p_demux, "Record Type 0x%x/%02x %ld bytes",
437
                    subrec_type, p_rec->rec_type, l_rec_size );*/
438
439
        /* some normal records are 0 length, so check for that... */
440
49.9k
        if( l_rec_size <= 0 )
441
12.4k
        {
442
            /* no data in payload; we're done */
443
12.4k
            p_sys->i_cur_rec++;
444
12.4k
            return VLC_DEMUXER_SUCCESS;
445
12.4k
        }
446
447
        /* read in this record's payload */
448
37.4k
        if( !( p_block_in = vlc_stream_Block( p_demux->s, l_rec_size ) ) )
449
1
            return VLC_DEMUXER_EOF;
450
37.4k
        if (p_block_in->i_buffer != (unsigned long) l_rec_size)
451
111
        {
452
111
            msg_Err(p_demux, "Unexpected EOF");
453
111
            block_Release(p_block_in);
454
111
            return VLC_DEMUXER_EOF;
455
111
        }
456
457
        /* set these as 'unknown' for now */
458
37.3k
        p_block_in->i_pts =
459
37.3k
        p_block_in->i_dts = VLC_TICK_INVALID;
460
37.3k
    }
461
    /*else
462
    {
463
        -- don't read any data from the stream, data was in the record header --
464
        msg_Dbg(p_demux,
465
               "Record Type 0x%02x/%02x, ext data = %02x, %02x", subrec_type,
466
                p_rec->rec_type, p_rec->ex1, p_rec->ex2);
467
    }*/
468
469
77.5k
    switch( p_rec->rec_type )
470
77.5k
    {
471
14.1k
        case 0xe0: /* video */
472
14.1k
            if( DemuxRecVideo( p_demux, p_rec, p_block_in ) )
473
32
                return VLC_DEMUXER_EGENERIC;
474
475
14.0k
            break;
476
477
18.1k
        case 0xc0: /* audio */
478
18.1k
            DemuxRecAudio( p_demux, p_rec, p_block_in );
479
18.1k
            break;
480
481
12.3k
        case 0x01:
482
26.1k
        case 0x02:
483
            /* closed captions/XDS */
484
26.1k
            if (!DemuxRecCc( p_demux, p_rec, p_block_in ))
485
0
                return VLC_DEMUXER_EGENERIC;
486
26.1k
            break;
487
488
26.1k
        default:
489
18.3k
            msg_Dbg(p_demux, "Invalid record type 0x%02x", p_rec->rec_type );
490
            /* fall-through */
491
492
19.1k
        case 0x03: /* tivo data services */
493
19.2k
        case 0x05: /* unknown, but seen regularly */
494
19.2k
            if( p_block_in )
495
4.84k
                block_Release( p_block_in );
496
77.5k
    }
497
498
    /* */
499
77.5k
    p_sys->i_cur_rec++;
500
77.5k
    return VLC_DEMUXER_SUCCESS;
501
77.5k
}
502
503
/* Control */
504
static int Control(demux_t *p_demux, int i_query, va_list args)
505
0
{
506
0
    demux_sys_t *p_sys = p_demux->p_sys;
507
0
    double f, *pf;
508
0
    int64_t i64;
509
510
    /*msg_Info(p_demux, "control cmd %d", i_query);*/
511
0
    switch( i_query )
512
0
    {
513
0
    case DEMUX_CAN_SEEK:
514
0
        *va_arg( args, bool * ) = p_sys->b_seekable;
515
0
        return VLC_SUCCESS;
516
517
0
    case DEMUX_GET_POSITION:
518
        /* arg is 0.0 - 1.0 percent of overall file position */
519
0
        if( ( i64 = p_sys->i_stream_size ) > 0 )
520
0
        {
521
0
            pf = va_arg( args, double* );
522
0
            *pf = ((double)1.0) * vlc_stream_Tell( p_demux->s ) / (double) i64;
523
0
            return VLC_SUCCESS;
524
0
        }
525
0
        return VLC_EGENERIC;
526
527
0
    case DEMUX_SET_POSITION:
528
        /* arg is 0.0 - 1.0 percent of overall file position */
529
0
        f = va_arg( args, double );
530
        /* msg_Dbg(p_demux, "Control - set position to %2.3f", f); */
531
0
        if ((i64 = p_sys->i_stream_size) > 0)
532
0
            return ty_stream_seek_pct(p_demux, f);
533
0
        return VLC_EGENERIC;
534
0
    case DEMUX_GET_TIME:
535
        /* return TiVo timestamp */
536
        //*p_i64 = p_sys->lastAudioPTS - p_sys->firstAudioPTS;
537
        //*p_i64 = (p_sys->l_last_ty_pts / 1000) + (p_sys->lastAudioPTS -
538
        //    p_sys->l_last_ty_pts_sync);
539
0
        *va_arg(args, vlc_tick_t *) = VLC_TICK_FROM_NS(p_sys->l_last_ty_pts);
540
0
        return VLC_SUCCESS;
541
0
    case DEMUX_GET_LENGTH:    /* length of program in microseconds, 0 if unk */
542
        /* size / bitrate */
543
0
        *va_arg(args, vlc_tick_t *) = 0;
544
0
        return VLC_SUCCESS;
545
0
    case DEMUX_SET_TIME:      /* arg is time in microsecs */
546
0
        return ty_stream_seek_time(p_demux,
547
0
                                   NS_FROM_VLC_TICK(va_arg( args, vlc_tick_t )));
548
0
    case DEMUX_CAN_PAUSE:
549
0
    case DEMUX_SET_PAUSE_STATE:
550
0
    case DEMUX_CAN_CONTROL_PACE:
551
0
    case DEMUX_GET_PTS_DELAY:
552
0
        return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );
553
0
    case DEMUX_GET_FPS:
554
0
    default:
555
0
        return VLC_EGENERIC;
556
0
    }
557
0
}
558
559
/* Close */
560
static void Close( vlc_object_t *p_this )
561
629
{
562
629
    demux_t *p_demux = (demux_t*)p_this;
563
629
    demux_sys_t *p_sys = p_demux->p_sys;
564
565
629
    XdsExit( &p_sys->xds );
566
629
    cc_Exit( &p_sys->cc );
567
629
    free( p_sys->rec_hdrs );
568
629
    free( p_sys->seq_table );
569
629
    free(p_sys);
570
629
}
571
572
573
/* =========================================================================== */
574
/* Compute Presentation Time Stamp (PTS)
575
 * Assume buf points to beginning of PTS */
576
static vlc_tick_t get_pts( const uint8_t *buf )
577
16.0k
{
578
16.0k
    ts_90khz_t i_pts = GetPESTimestamp( buf );
579
16.0k
    return FROM_SCALE_NZ(i_pts); /* convert PTS (90Khz clock) to microseconds */
580
16.0k
}
581
582
583
/* =========================================================================== */
584
static int find_es_header( const uint8_t *header,
585
                           const uint8_t *buffer, size_t buffer_len, size_t i_search_len )
586
32.1k
{
587
32.1k
    size_t count;
588
589
112k
    for( count = 0; count < i_search_len && count + 4 < buffer_len; count++ )
590
96.9k
    {
591
96.9k
        if( !memcmp( &buffer[count], header, 4 ) )
592
16.6k
            return count;
593
96.9k
    }
594
15.4k
    return -1;
595
32.1k
}
596
597
598
/* =========================================================================== */
599
/* check if we have a full PES header, if not, then save what we have.
600
 * this is called when audio-start packets are encountered.
601
 * Returns:
602
 *     1 partial PES hdr found, some audio data found (buffer adjusted),
603
 *    -1 partial PES hdr found, no audio data found
604
 *     0 otherwise (complete PES found, pts extracted, pts set, buffer adjusted) */
605
/* TODO: HD support -- nothing known about those streams */
606
static int check_sync_pes( demux_t *p_demux, block_t *p_block,
607
                           int32_t offset, int32_t rec_len )
608
18.0k
{
609
18.0k
    demux_sys_t *p_sys = p_demux->p_sys;
610
611
18.0k
    if ( offset < 0 || offset + p_sys->i_Pes_Length > rec_len )
612
8.05k
    {
613
        /* entire PES header not present */
614
8.05k
        msg_Dbg( p_demux, "PES header at %d not complete in record. storing.",
615
8.05k
                 offset );
616
        /* save the partial pes header */
617
8.05k
        if( offset < 0 )
618
8.05k
        {
619
            /* no header found, fake some 00's (this works, believe me) */
620
8.05k
            memset( p_sys->pes_buffer, 0, 4 );
621
8.05k
            p_sys->i_pes_buf_cnt = 4;
622
8.05k
            if( rec_len > 4 )
623
8.05k
                msg_Err( p_demux, "PES header not found in record of %d bytes!",
624
8.05k
                         rec_len );
625
8.05k
            return -1;
626
8.05k
        }
627
        /* copy the partial pes header we found */
628
1
        memcpy( p_sys->pes_buffer, p_block->p_buffer + offset,
629
1
                rec_len - offset );
630
1
        p_sys->i_pes_buf_cnt = rec_len - offset;
631
632
1
        if( offset > 0 )
633
1
        {
634
            /* PES Header was found, but not complete, so trim the end of this record */
635
1
            p_block->i_buffer -= rec_len - offset;
636
1
            return 1;
637
1
        }
638
0
        return -1;    /* partial PES, no audio data */
639
1
    }
640
    /* full PES header present, extract PTS */
641
9.96k
    p_sys->lastAudioPTS = VLC_TICK_0 + get_pts( &p_block->p_buffer[ offset +
642
9.96k
                                   p_sys->i_Pts_Offset ] );
643
9.96k
    p_block->i_pts = p_sys->lastAudioPTS;
644
    /*msg_Dbg(p_demux, "Audio PTS %"PRId64, p_sys->lastAudioPTS );*/
645
    /* adjust audio record to remove PES header */
646
9.96k
    memmove(p_block->p_buffer + offset, p_block->p_buffer + offset +
647
9.96k
            p_sys->i_Pes_Length, rec_len - p_sys->i_Pes_Length);
648
9.96k
    p_block->i_buffer -= p_sys->i_Pes_Length;
649
#if 0
650
    msg_Dbg(p_demux, "pes hdr removed; buffer len=%d and has "
651
             "%02x %02x %02x %02x %02x %02x %02x %02x "
652
             "%02x %02x %02x %02x %02x %02x %02x %02x", p_block->i_buffer,
653
             p_block->p_buffer[0], p_block->p_buffer[1],
654
             p_block->p_buffer[2], p_block->p_buffer[3],
655
             p_block->p_buffer[4], p_block->p_buffer[5],
656
             p_block->p_buffer[6], p_block->p_buffer[7],
657
             p_block->p_buffer[8], p_block->p_buffer[9],
658
             p_block->p_buffer[10], p_block->p_buffer[11],
659
             p_block->p_buffer[12], p_block->p_buffer[13],
660
             p_block->p_buffer[14], p_block->p_buffer[15]);
661
#endif
662
9.96k
    return 0;
663
18.0k
}
664
665
static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
666
14.1k
{
667
14.1k
    demux_sys_t *p_sys = p_demux->p_sys;
668
14.1k
    const int subrec_type = rec_hdr->subrec_type;
669
14.1k
    const long l_rec_size = rec_hdr->l_rec_size;    // p_block_in->i_buffer might be better
670
14.1k
    int esOffset1;
671
14.1k
    int i;
672
673
14.1k
    assert( rec_hdr->rec_type == 0xe0 );
674
14.1k
    if( !p_block_in )
675
32
        return -1;
676
677
#if 0
678
    msg_Dbg(p_demux, "packet buffer has "
679
            "%02x %02x %02x %02x %02x %02x %02x %02x "
680
            "%02x %02x %02x %02x %02x %02x %02x %02x",
681
            p_block_in->p_buffer[0], p_block_in->p_buffer[1],
682
            p_block_in->p_buffer[2], p_block_in->p_buffer[3],
683
            p_block_in->p_buffer[4], p_block_in->p_buffer[5],
684
            p_block_in->p_buffer[6], p_block_in->p_buffer[7],
685
            p_block_in->p_buffer[8], p_block_in->p_buffer[9],
686
            p_block_in->p_buffer[10], p_block_in->p_buffer[11],
687
            p_block_in->p_buffer[12], p_block_in->p_buffer[13],
688
            p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
689
#endif
690
    //if( subrec_type == 0x06 || subrec_type == 0x07 )
691
14.0k
    if( subrec_type != 0x02 && subrec_type != 0x0c &&
692
12.8k
        subrec_type != 0x08 && l_rec_size > 4 )
693
12.3k
    {
694
        /* get the PTS from this packet if it has one.
695
         * on S1, only 0x06 has PES.  On S2, however, most all do.
696
         * Do NOT Pass the PES Header to the MPEG2 codec */
697
12.3k
        size_t search_len = __MIN(l_rec_size - sizeof(ty_VideoPacket), 5);
698
12.3k
        esOffset1 = find_es_header( ty_VideoPacket, p_block_in->p_buffer, p_block_in->i_buffer, search_len );
699
12.3k
        if( esOffset1 != -1 )
700
6.11k
        {
701
            //msg_Dbg(p_demux, "Video PES hdr in pkt type 0x%02x at offset %d",
702
                //subrec_type, esOffset1);
703
6.11k
            p_sys->lastVideoPTS = VLC_TICK_0 + get_pts(
704
6.11k
                    &p_block_in->p_buffer[ esOffset1 + VIDEO_PTS_OFFSET ] );
705
            /*msg_Dbg(p_demux, "Video rec %d PTS %"PRId64, p_sys->i_cur_rec,
706
                        p_sys->lastVideoPTS );*/
707
6.11k
            if (subrec_type != 0x06) {
708
                /* if we found a PES, and it's not type 6, then we're S2 */
709
                /* The packet will have video data (& other headers) so we
710
                 * chop out the PES header and send the rest */
711
6.11k
                if (l_rec_size >= VIDEO_PES_LENGTH) {
712
6.11k
                    p_block_in->p_buffer += VIDEO_PES_LENGTH + esOffset1;
713
6.11k
                    p_block_in->i_buffer -= VIDEO_PES_LENGTH + esOffset1;
714
6.11k
                } else {
715
1
                    msg_Dbg(p_demux, "video rec type 0x%02x has short PES"
716
1
                        " (%ld bytes)", subrec_type, l_rec_size);
717
                    /* nuke this block; it's too short, but has PES marker */
718
1
                    p_block_in->i_buffer = 0;
719
1
                }
720
6.11k
            }
721
6.11k
        }/* else
722
            msg_Dbg(p_demux, "No Video PES hdr in pkt type 0x%02x",
723
                subrec_type); */
724
12.3k
    }
725
726
14.0k
    if(subrec_type == 0x06 )
727
3
    {
728
        /* type 6 (S1 DTivo) has no data, so we're done */
729
3
        block_Release(p_block_in);
730
3
        return 0;
731
3
    }
732
733
    /* if it's not a continue blk, then set PTS */
734
14.0k
    if( subrec_type != 0x02 )
735
13.3k
    {
736
        /*msg_Dbg(p_demux, "Video rec %d type 0x%02X", p_sys->i_cur_rec,
737
                   subrec_type);*/
738
        /* if it's a GOP header, make sure it's legal
739
         * (if we have enough data) */
740
        /* Some ty files don't have this bit set
741
         * and it causes problems */
742
13.3k
        if (subrec_type == 0x0c && l_rec_size >= 6)
743
490
            p_block_in->p_buffer[5] |= 0x08;
744
        /* store the TY PTS if there is one */
745
13.3k
        if (subrec_type == 0x07) {
746
500
            p_sys->l_last_ty_pts = rec_hdr->l_ty_pts;
747
            /* should we use audio or video PTS? */
748
            //p_sys->l_last_ty_pts_sync = p_sys->lastAudioPTS;
749
12.8k
        } else {
750
            /* yes I know this is a cheap hack.  It's the timestamp
751
               used for display and skipping fwd/back, so it
752
               doesn't have to be accurate to the millisecond.
753
               I adjust it here by roughly one 1/30 sec.  Yes it
754
               will be slightly off for UK streams, but it's OK.
755
             */
756
12.8k
            p_sys->l_last_ty_pts += 35000000;
757
            //p_sys->l_last_ty_pts += 33366667;
758
12.8k
        }
759
        /* set PTS for this block before we send */
760
13.3k
        if (p_sys->lastVideoPTS != VLC_TICK_INVALID)
761
6.11k
        {
762
6.11k
            p_block_in->i_pts = p_sys->lastVideoPTS;
763
            /* PTS gets used ONCE.
764
             * Any subsequent frames we get BEFORE next PES
765
             * header will have their PTS computed in the codec */
766
6.11k
            p_sys->lastVideoPTS = VLC_TICK_INVALID;
767
6.11k
        }
768
13.3k
    }
769
770
    /* Register the CC decoders when needed */
771
14.0k
    uint64_t i_chans = p_sys->cc.i_608channels;
772
65.4k
    for( i = 0; i_chans > 0; i++, i_chans >>= 1 )
773
51.3k
    {
774
51.3k
        if( (i_chans & 1) == 0 || p_sys->p_cc[i] )
775
49.5k
            continue;
776
777
1.78k
        static const char *ppsz_description[4] = {
778
1.78k
            N_("Closed captions 1"),
779
1.78k
            N_("Closed captions 2"),
780
1.78k
            N_("Closed captions 3"),
781
1.78k
            N_("Closed captions 4"),
782
1.78k
        };
783
784
1.78k
        es_format_t fmt;
785
786
787
1.78k
        es_format_Init( &fmt, SPU_ES, VLC_CODEC_CEA608 );
788
1.78k
        fmt.subs.cc.i_channel = i;
789
1.78k
        fmt.psz_description = strdup( vlc_gettext(ppsz_description[i]) );
790
1.78k
        fmt.i_group = TY_ES_GROUP;
791
1.78k
        p_sys->p_cc[i] = es_out_Add( p_demux->out, &fmt );
792
1.78k
        es_format_Clean( &fmt );
793
794
1.78k
    }
795
    /* Send the CC data */
796
14.0k
    if( p_block_in->i_pts != VLC_TICK_INVALID && p_sys->cc.i_data > 0 )
797
1.60k
    {
798
8.00k
        for( i = 0; i < 4; i++ )
799
6.40k
        {
800
6.40k
            if( p_sys->p_cc[i] )
801
6.25k
            {
802
6.25k
                block_t *p_cc = block_Alloc( p_sys->cc.i_data );
803
6.25k
                if( unlikely(p_cc == NULL) )
804
0
                {
805
0
                    block_Release(p_block_in);
806
0
                    return -1;
807
0
                }
808
809
6.25k
                p_cc->i_flags |= BLOCK_FLAG_TYPE_I;
810
6.25k
                p_cc->i_pts = p_block_in->i_pts;
811
6.25k
                memcpy( p_cc->p_buffer, p_sys->cc.p_data, p_sys->cc.i_data );
812
813
6.25k
                es_out_Send( p_demux->out, p_sys->p_cc[i], p_cc );
814
6.25k
            }
815
6.40k
        }
816
1.60k
        cc_Flush( &p_sys->cc );
817
1.60k
    }
818
819
    //msg_Dbg(p_demux, "sending rec %d as video type 0x%02x",
820
            //p_sys->i_cur_rec, subrec_type);
821
14.0k
    es_out_Send(p_demux->out, p_sys->p_video, p_block_in);
822
14.0k
    return 0;
823
14.0k
}
824
static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
825
18.1k
{
826
18.1k
    demux_sys_t *p_sys = p_demux->p_sys;
827
18.1k
    const int subrec_type = rec_hdr->subrec_type;
828
18.1k
    const long l_rec_size = rec_hdr->l_rec_size;
829
18.1k
    int esOffset1;
830
831
18.1k
    assert( rec_hdr->rec_type == 0xc0 );
832
18.1k
    if( !p_block_in )
833
42
        return -1;
834
#if 0
835
        int i;
836
        fprintf( stderr, "Audio Packet Header " );
837
        for( i = 0 ; i < 24 ; i++ )
838
            fprintf( stderr, "%2.2x ", p_block_in->p_buffer[i] );
839
        fprintf( stderr, "\n" );
840
#endif
841
842
18.1k
    if( subrec_type == 2 )
843
32
    {
844
        /* SA or DTiVo Audio Data, no PES (continued block)
845
         * ================================================
846
         */
847
848
        /* continue PES if previous was incomplete */
849
32
        if (p_sys->i_pes_buf_cnt > 0)
850
30
        {
851
30
            const int i_need = p_sys->i_Pes_Length - p_sys->i_pes_buf_cnt;
852
853
30
            msg_Dbg(p_demux, "continuing PES header");
854
            /* do we have enough data to complete? */
855
30
            if (i_need >= l_rec_size)
856
1
            {
857
                /* don't have complete PES hdr; save what we have and return */
858
1
                memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
859
1
                        p_block_in->p_buffer, l_rec_size);
860
1
                p_sys->i_pes_buf_cnt += l_rec_size;
861
                /* */
862
1
                block_Release(p_block_in);
863
1
                return 0;
864
1
            }
865
866
            /* we have enough; reconstruct this p_frame with the new hdr */
867
29
            memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
868
29
                   p_block_in->p_buffer, i_need);
869
            /* advance the block past the PES header (don't want to send it) */
870
29
            p_block_in->p_buffer += i_need;
871
29
            p_block_in->i_buffer -= i_need;
872
            /* get the PTS out of this PES header (MPEG or AC3) */
873
29
            if (p_sys->audio_type == TIVO_AUDIO_MPEG)
874
23
                esOffset1 = find_es_header(ty_MPEGAudioPacket,
875
23
                        p_sys->pes_buffer, ARRAY_SIZE(p_sys->pes_buffer), 5);
876
6
            else
877
6
                esOffset1 = find_es_header(ty_AC3AudioPacket,
878
6
                        p_sys->pes_buffer, ARRAY_SIZE(p_sys->pes_buffer), 5);
879
29
            if (esOffset1 < 0)
880
27
            {
881
                /* god help us; something's really wrong */
882
27
                msg_Err(p_demux, "can't find audio PES header in packet");
883
27
            }
884
2
            else
885
2
            {
886
2
                p_sys->lastAudioPTS = VLC_TICK_0 + get_pts(
887
2
                    &p_sys->pes_buffer[ esOffset1 + p_sys->i_Pts_Offset ] );
888
2
                p_block_in->i_pts = p_sys->lastAudioPTS;
889
2
            }
890
29
            p_sys->i_pes_buf_cnt = 0;
891
29
        }
892
        /* S2 DTivo has AC3 packets with 2 padding bytes at end.  This is
893
         * not allowed in the AC3 spec and will cause problems.  So here
894
         * we try to trim things. */
895
        /* Also, S1 DTivo has alternating short / long AC3 packets.  That
896
         * is, one packet is short (incomplete) and the next packet has
897
         * the first one's missing data, plus all of its own.  Strange. */
898
31
        if (p_sys->audio_type == TIVO_AUDIO_AC3 &&
899
7
                p_sys->tivo_series == TIVO_SERIES2) {
900
7
            if (p_sys->l_ac3_pkt_size + p_block_in->i_buffer >
901
7
                    AC3_PKT_LENGTH) {
902
1
                p_block_in->i_buffer -= 2;
903
1
                p_sys->l_ac3_pkt_size = 0;
904
6
            } else {
905
6
                p_sys->l_ac3_pkt_size += p_block_in->i_buffer;
906
6
            }
907
7
        }
908
31
    }
909
18.0k
    else if( subrec_type == 0x03 )
910
18.0k
    {
911
        /* MPEG Audio with PES Header, either SA or DTiVo   */
912
        /* ================================================ */
913
18.0k
        esOffset1 = find_es_header( ty_MPEGAudioPacket,
914
18.0k
                p_block_in->p_buffer, p_block_in->i_buffer, 5 );
915
916
        /*msg_Dbg(p_demux, "buffer has %#02x %#02x %#02x %#02x",
917
           p_block_in->p_buffer[0], p_block_in->p_buffer[1],
918
           p_block_in->p_buffer[2], p_block_in->p_buffer[3]);
919
        msg_Dbg(p_demux, "audio ES hdr at offset %d", esOffset1);*/
920
921
        /* SA PES Header, No Audio Data                     */
922
        /* ================================================ */
923
18.0k
        if ( ( esOffset1 == 0 ) && ( l_rec_size == REC_SIZE ) )
924
7
        {
925
7
            p_sys->lastAudioPTS = VLC_TICK_0 + get_pts( &p_block_in->p_buffer[
926
7
                        SA_PTS_OFFSET ] );
927
928
7
            block_Release(p_block_in);
929
7
            return 0;
930
            /*msg_Dbg(p_demux, "SA Audio PTS %"PRId64, p_sys->lastAudioPTS );*/
931
7
        }
932
        /* DTiVo Audio with PES Header                      */
933
        /* ================================================ */
934
935
        /* Check for complete PES */
936
18.0k
        if (check_sync_pes(p_demux, p_block_in, esOffset1,
937
18.0k
                            l_rec_size) == -1)
938
8.05k
        {
939
            /* partial PES header found, nothing else.
940
             * we're done. */
941
8.05k
            block_Release(p_block_in);
942
8.05k
            return 0;
943
8.05k
        }
944
#if 0
945
        msg_Dbg(p_demux, "packet buffer has "
946
                 "%02x %02x %02x %02x %02x %02x %02x %02x "
947
                 "%02x %02x %02x %02x %02x %02x %02x %02x",
948
                 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
949
                 p_block_in->p_buffer[2], p_block_in->p_buffer[3],
950
                 p_block_in->p_buffer[4], p_block_in->p_buffer[5],
951
                 p_block_in->p_buffer[6], p_block_in->p_buffer[7],
952
                 p_block_in->p_buffer[8], p_block_in->p_buffer[9],
953
                 p_block_in->p_buffer[10], p_block_in->p_buffer[11],
954
                 p_block_in->p_buffer[12], p_block_in->p_buffer[13],
955
                 p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
956
#endif
957
18.0k
    }
958
53
    else if( subrec_type == 0x04 )
959
2
    {
960
        /* SA Audio with no PES Header                      */
961
        /* ================================================ */
962
        /*msg_Dbg(p_demux,
963
                "Adding SA Audio Packet Size %ld", l_rec_size ); */
964
965
2
        if (p_sys->lastAudioPTS != VLC_TICK_INVALID )
966
1
            p_block_in->i_pts = p_sys->lastAudioPTS;
967
2
    }
968
51
    else if( subrec_type == 0x09 )
969
14
    {
970
        /* DTiVo AC3 Audio Data with PES Header             */
971
        /* ================================================ */
972
14
        esOffset1 = find_es_header( ty_AC3AudioPacket,
973
14
                p_block_in->p_buffer, p_block_in->i_buffer, 5 );
974
975
#if 0
976
        msg_Dbg(p_demux, "buffer has "
977
                 "%02x %02x %02x %02x %02x %02x %02x %02x "
978
                 "%02x %02x %02x %02x %02x %02x %02x %02x",
979
                 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
980
                 p_block_in->p_buffer[2], p_block_in->p_buffer[3],
981
                 p_block_in->p_buffer[4], p_block_in->p_buffer[5],
982
                 p_block_in->p_buffer[6], p_block_in->p_buffer[7],
983
                 p_block_in->p_buffer[8], p_block_in->p_buffer[9],
984
                 p_block_in->p_buffer[10], p_block_in->p_buffer[11],
985
                 p_block_in->p_buffer[12], p_block_in->p_buffer[13],
986
                 p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
987
        msg_Dbg(p_demux, "audio ES AC3 hdr at offset %d", esOffset1);
988
#endif
989
990
        /* Check for complete PES */
991
14
        if (check_sync_pes(p_demux, p_block_in, esOffset1,
992
14
                            l_rec_size) == -1)
993
6
        {
994
            /* partial PES header found, nothing else.  we're done. */
995
6
            block_Release(p_block_in);
996
6
            return 0;
997
6
        }
998
        /* S2 DTivo has invalid long AC3 packets */
999
8
        if (p_sys->tivo_series == TIVO_SERIES2) {
1000
8
            if (p_block_in->i_buffer > AC3_PKT_LENGTH) {
1001
0
                p_block_in->i_buffer -= 2;
1002
0
                p_sys->l_ac3_pkt_size = 0;
1003
8
            } else {
1004
8
                p_sys->l_ac3_pkt_size = p_block_in->i_buffer;
1005
8
            }
1006
8
        }
1007
8
    }
1008
37
    else
1009
37
    {
1010
        /* Unsupported/Unknown */
1011
37
        block_Release(p_block_in);
1012
37
        return 0;
1013
37
    }
1014
1015
    /* set PCR before we send (if PTS found) */
1016
9.99k
    if( p_block_in->i_pts != VLC_TICK_INVALID )
1017
9.96k
        es_out_SetPCR( p_demux->out, p_block_in->i_pts );
1018
1019
    /* Send data */
1020
9.99k
    es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
1021
9.99k
    return 0;
1022
18.1k
}
1023
1024
static bool DemuxRecCc( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
1025
26.1k
{
1026
26.1k
    demux_sys_t *p_sys = p_demux->p_sys;
1027
26.1k
    int i_field;
1028
1029
26.1k
    if( p_block_in )
1030
335
        block_Release(p_block_in);
1031
1032
26.1k
    if( rec_hdr->rec_type == 0x01 )
1033
12.3k
        i_field = 0;
1034
13.7k
    else if( rec_hdr->rec_type == 0x02 )
1035
13.7k
        i_field = 1;
1036
0
    else
1037
0
        return 0;
1038
1039
    /* XDS data (extract programs infos) transmitted on field 2 only */
1040
26.1k
    if( i_field == 1 )
1041
13.7k
        DemuxDecodeXds( p_demux, rec_hdr->ex[0], rec_hdr->ex[1] );
1042
1043
26.1k
    return cc_AppendData( &p_sys->cc, CC_PKT_BYTE0(i_field), rec_hdr->ex );
1044
26.1k
}
1045
1046
/* seek to a position within the stream, if possible */
1047
static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct)
1048
0
{
1049
0
    demux_sys_t *p_sys = p_demux->p_sys;
1050
0
    int64_t seek_pos = p_sys->i_stream_size * seek_pct;
1051
0
    uint64_t l_skip_amt;
1052
0
    unsigned i_cur_part;
1053
1054
    /* if we're not seekable, there's nothing to do */
1055
0
    if (!p_sys->b_seekable)
1056
0
        return VLC_EGENERIC;
1057
1058
    /* figure out which part & chunk we want & go there */
1059
0
    i_cur_part = seek_pos / TIVO_PART_LENGTH;
1060
0
    p_sys->i_cur_chunk = seek_pos / CHUNK_SIZE;
1061
1062
    /* try to read the part header (master chunk) if it's there */
1063
0
    if (vlc_stream_Seek( p_demux->s, i_cur_part * TIVO_PART_LENGTH ) ||
1064
0
        parse_master(p_demux) != VLC_SUCCESS)
1065
0
    {
1066
        /* can't seek stream */
1067
0
        return VLC_EGENERIC;
1068
0
    }
1069
1070
    /* now for the actual chunk */
1071
0
    if ( vlc_stream_Seek( p_demux->s, p_sys->i_cur_chunk * CHUNK_SIZE))
1072
0
    {
1073
        /* can't seek stream */
1074
0
        return VLC_EGENERIC;
1075
0
    }
1076
    /* load the chunk */
1077
0
    p_sys->i_stuff_cnt = 0;
1078
0
    get_chunk_header(p_demux);
1079
1080
    /* seek within the chunk to get roughly to where we want */
1081
0
    p_sys->i_cur_rec = (int)
1082
0
      ((double) ((seek_pos % CHUNK_SIZE) / (double) (CHUNK_SIZE)) * p_sys->i_num_recs);
1083
0
    msg_Dbg(p_demux, "Seeked to file pos %"PRId64, seek_pos);
1084
0
    msg_Dbg(p_demux, " (chunk %d, record %d)",
1085
0
             p_sys->i_cur_chunk - 1, p_sys->i_cur_rec);
1086
1087
    /* seek to the start of this record's data.
1088
     * to do that, we have to skip past all prior records */
1089
0
    l_skip_amt = 0;
1090
0
    for ( int i=0; i<p_sys->i_cur_rec; i++)
1091
0
        l_skip_amt += p_sys->rec_hdrs[i].l_rec_size;
1092
0
    if( vlc_stream_Seek(p_demux->s, ((p_sys->i_cur_chunk-1) * CHUNK_SIZE) +
1093
0
                        (p_sys->i_num_recs * REC_SIZE) + l_skip_amt + 4) != VLC_SUCCESS )
1094
0
        return VLC_EGENERIC;
1095
1096
    /* to hell with syncing any audio or video, just start reading records... :) */
1097
    /*p_sys->lastAudioPTS = p_sys->lastVideoPTS = VLC_TICK_INVALID;*/
1098
0
    return VLC_SUCCESS;
1099
0
}
1100
1101
/* XDS decoder */
1102
//#define TY_XDS_DEBUG
1103
static void XdsInit( xds_t *h )
1104
629
{
1105
629
    h->b_xds = false;
1106
629
    h->i_class = XDS_MAX_CLASS_COUNT;
1107
629
    h->i_type = 0;
1108
629
    h->b_future = false;
1109
5.66k
    for( int i = 0; i < XDS_MAX_CLASS_COUNT; i++ )
1110
5.03k
    {
1111
649k
        for( int j = 0; j < 128; j++ )
1112
644k
            h->pkt[i][j].b_started = false;
1113
5.03k
    }
1114
629
    h->b_meta_changed = false;
1115
629
    memset( &h->meta, 0, sizeof(h->meta) );
1116
629
}
1117
static void XdsExit( xds_t *h )
1118
629
{
1119
    /* */
1120
629
    free( h->meta.psz_channel_name );
1121
629
    free( h->meta.psz_channel_call_letter );
1122
629
    free( h->meta.psz_channel_number );
1123
1124
    /* */
1125
629
    free( h->meta.current.psz_name );
1126
629
    free( h->meta.current.psz_rating );
1127
    /* */
1128
629
    free( h->meta.future.psz_name );
1129
629
    free( h->meta.future.psz_rating );
1130
629
}
1131
static void XdsStringUtf8( char dst[2*32+1], const uint8_t *p_src, size_t i_src )
1132
1.47k
{
1133
1.47k
    size_t i_dst = 0;
1134
9.04k
    for( size_t i = 0; i < i_src; i++ )
1135
7.57k
    {
1136
7.57k
        switch( p_src[i] )
1137
7.57k
        {
1138
0
#define E2( c, u1, u2 ) case c: dst[i_dst++] = u1; dst[i_dst++] = u2; break
1139
0
        E2( 0x2a, 0xc3,0xa1); // lowercase a, acute accent
1140
0
        E2( 0x5c, 0xc3,0xa9); // lowercase e, acute accent
1141
0
        E2( 0x5e, 0xc3,0xad); // lowercase i, acute accent
1142
0
        E2( 0x5f, 0xc3,0xb3); // lowercase o, acute accent
1143
0
        E2( 0x60, 0xc3,0xba); // lowercase u, acute accent
1144
0
        E2( 0x7b, 0xc3,0xa7); // lowercase c with cedilla
1145
0
        E2( 0x7c, 0xc3,0xb7); // division symbol
1146
0
        E2( 0x7d, 0xc3,0x91); // uppercase N tilde
1147
0
        E2( 0x7e, 0xc3,0xb1); // lowercase n tilde
1148
0
#undef E2
1149
7.57k
        default:
1150
7.57k
            dst[i_dst++] = p_src[i];
1151
7.57k
            break;
1152
7.57k
        }
1153
7.57k
    }
1154
1.47k
    dst[i_dst++] = '\0';
1155
1.47k
}
1156
static bool XdsChangeString( xds_t *h, char **ppsz_dst, const char *psz_new )
1157
1.47k
{
1158
1.47k
    if( *ppsz_dst && psz_new && !strcmp( *ppsz_dst, psz_new ) )
1159
441
        return false;
1160
1.03k
    if( *ppsz_dst == NULL && psz_new == NULL )
1161
0
        return false;
1162
1163
1.03k
    free( *ppsz_dst );
1164
1.03k
    if( psz_new )
1165
1.03k
        *ppsz_dst = strdup( psz_new );
1166
0
    else
1167
0
        *ppsz_dst = NULL;
1168
1169
1.03k
    h->b_meta_changed = true;
1170
1.03k
    return true;
1171
1.03k
}
1172
1173
static void XdsDecodeCurrentFuture( xds_t *h, xds_packet_t *pk )
1174
159
{
1175
159
    xds_meta_program_t *p_prg = h->b_future ? &h->meta.future : &h->meta.current;
1176
159
    char name[2*32+1];
1177
159
    int i_rating;
1178
1179
159
    switch( h->i_type )
1180
159
    {
1181
159
    case 0x03:
1182
159
        XdsStringUtf8( name, pk->p_data, pk->i_data );
1183
159
        if( XdsChangeString( h, &p_prg->psz_name, name ) )
1184
103
        {
1185
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Program Name) %d'\n", pk->i_data );
1186
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> program name %s\n", name );
1187
103
        }
1188
159
        break;
1189
0
    case 0x05:
1190
0
        i_rating = (pk->p_data[0] & 0x18);
1191
0
        if( i_rating == 0x08 )
1192
0
        {
1193
            /* TPG */
1194
0
            static const char *pppsz_ratings[8][2] = {
1195
0
                { "None",   "No rating (no content advisory)" },
1196
0
                { "TV-Y",   "All Children (no content advisory)" },
1197
0
                { "TV-Y7",  "Directed to Older Children (V = Fantasy Violence)" },
1198
0
                { "TV-G",   "General Audience (no content advisory)" },
1199
0
                { "TV-PG",  "Parental Guidance Suggested" },
1200
0
                { "TV-14",  "Parents Strongly Cautioned" },
1201
0
                { "TV-MA",  "Mature Audience Only" },
1202
0
                { "None",   "No rating (no content advisory)" }
1203
0
            };
1204
0
            p_prg->rating = XDS_META_PROGRAM_RATING_TPG;
1205
0
            if( XdsChangeString( h, &p_prg->psz_rating, pppsz_ratings[pk->p_data[1]&0x07][0] ) )
1206
0
            {
1207
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Rating) %d'\n", pk->i_data );
1208
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> TPG Rating %s (%s)\n",
1209
                //         pppsz_ratings[pk->p_data[1]&0x07][0], pppsz_ratings[pk->p_data[1]&0x07][1] );
1210
0
            }
1211
0
        }
1212
0
        else if( i_rating == 0x00 || i_rating == 0x10 )
1213
0
        {
1214
            /* MPAA */
1215
0
            static const char *pppsz_ratings[8][2] = {
1216
0
                { "N/A",    "N/A" },
1217
0
                { "G",      "General Audiences" },
1218
0
                { "PG",     "Parental Guidance Suggested" },
1219
0
                { "PG-13",  "Parents Strongly Cautioned" },
1220
0
                { "R",      "Restricted" },
1221
0
                { "NC-17",  "No one 17 and under admitted" },
1222
0
                { "X",      "No one under 17 admitted" },
1223
0
                { "NR",     "Not Rated" },
1224
0
            };
1225
0
            p_prg->rating = XDS_META_PROGRAM_RATING_MPAA;
1226
0
            if( XdsChangeString( h, &p_prg->psz_rating, pppsz_ratings[pk->p_data[0]&0x07][0] ) )
1227
0
            {
1228
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Rating) %d'\n", pk->i_data );
1229
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> TPG Rating %s (%s)\n",
1230
                //         pppsz_ratings[pk->p_data[0]&0x07][0], pppsz_ratings[pk->p_data[0]&0x07][1] );
1231
0
            }
1232
0
        }
1233
0
        else
1234
0
        {
1235
            /* Non US Rating TODO */
1236
0
            assert( i_rating == 0x18 ); // only left value possible */
1237
0
            p_prg->rating = XDS_META_PROGRAM_RATING_NONE;
1238
0
            if( XdsChangeString( h, &p_prg->psz_rating, NULL ) )
1239
0
            {
1240
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Rating) %d'\n", pk->i_data );
1241
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> 0x%2.2x 0x%2.2x\n", pk->p_data[0], pk->p_data[1] );
1242
0
            }
1243
0
        }
1244
0
        break;
1245
1246
0
    default:
1247
#ifdef TY_XDS_DEBUG
1248
        fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Unknown 0x%x)'\n", h->i_type );
1249
#endif
1250
0
        break;
1251
159
    }
1252
159
}
1253
1254
static void XdsDecodeChannel( xds_t *h, xds_packet_t *pk )
1255
1.27k
{
1256
1.27k
    char name[2*32+1];
1257
1.27k
    char chan[2*32+1];
1258
1259
1.27k
    switch( h->i_type )
1260
1.27k
    {
1261
181
    case 0x01:
1262
181
        if( pk->i_data < 2 )
1263
0
            return;
1264
181
        XdsStringUtf8( name, pk->p_data, pk->i_data );
1265
181
        if( XdsChangeString( h, &h->meta.psz_channel_name, name ) )
1266
120
        {
1267
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Name) %d'\n", pk->i_data );
1268
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> %s\n", name );
1269
120
        }
1270
181
        break;
1271
1272
566
    case 0x02:
1273
566
        if( pk->i_data < 4 )
1274
0
            return;
1275
1276
566
        XdsStringUtf8( name, pk->p_data, 4 );
1277
566
        if( XdsChangeString( h, &h->meta.psz_channel_call_letter, name ) )
1278
404
        {
1279
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Call Letter)' %d\n", pk->i_data );
1280
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> call letter %s\n", name );
1281
404
        }
1282
566
        if( pk->i_data >= 6 )
1283
566
        {
1284
566
            XdsStringUtf8( chan, &pk->p_data[4], 2 );
1285
566
            if( XdsChangeString( h, &h->meta.psz_channel_number, chan ) )
1286
404
            {
1287
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Call Letter)' %d\n", pk->i_data );
1288
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> channel number %s\n", chan );
1289
404
            }
1290
566
        }
1291
0
        else
1292
0
        {
1293
0
            if( XdsChangeString( h, &h->meta.psz_channel_number, NULL ) )
1294
0
            {
1295
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Call Letter)' %d\n", pk->i_data );
1296
                //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> no channel number letter anymore\n" );
1297
0
            }
1298
0
        }
1299
566
        break;
1300
0
    case 0x03:
1301
        //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Channel Tape Delay)'\n" );
1302
0
        break;
1303
529
    case 0x04:
1304
        //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Transmission Signal Identifier)'\n" );
1305
529
        break;
1306
0
    default:
1307
#ifdef TY_XDS_DEBUG
1308
        fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Unknown 0x%x)'\n", h->i_type );
1309
#endif
1310
0
        break;
1311
1.27k
    }
1312
1.27k
}
1313
1314
static void XdsDecode( xds_t *h, xds_packet_t *pk )
1315
1.43k
{
1316
1.43k
    switch( h->i_class )
1317
1.43k
    {
1318
159
    case XDS_CLASS_CURRENT:
1319
159
    case XDS_CLASS_FUTURE:
1320
159
        XdsDecodeCurrentFuture( h, pk );
1321
159
        break;
1322
1.27k
    case XDS_CLASS_CHANNEL:
1323
1.27k
        XdsDecodeChannel( h, pk );
1324
1.27k
        break;
1325
0
    case XDS_CLASS_MISCELLANEOUS:
1326
#ifdef TY_XDS_DEBUG
1327
        fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Miscellaneous'\n" );
1328
#endif
1329
0
        break;
1330
0
    case XDS_CLASS_PUBLIC_SERVICE:
1331
#ifdef TY_XDS_DEBUG
1332
        fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Public Service'\n" );
1333
#endif
1334
0
        break;
1335
0
    default:
1336
        //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: unknown class\n" );
1337
0
        break;
1338
1.43k
    }
1339
1.43k
}
1340
1341
static void XdsParse( xds_t *h, uint8_t d1, uint8_t d2 )
1342
13.7k
{
1343
    /* TODO check parity */
1344
13.7k
    d1 &= 0x7f;
1345
13.7k
    d2 &= 0x7f;
1346
1347
    /* */
1348
13.7k
    if( d1 >= 0x01 && d1 <= 0x0e )
1349
1.85k
    {
1350
1.85k
        const xds_class_t i_class = ( d1 - 1 ) >> 1;
1351
1.85k
        const int i_type = d2;
1352
1.85k
        const bool b_start = d1 & 0x01;
1353
1.85k
        xds_packet_t *pk = &h->pkt[i_class][i_type];
1354
1355
1.85k
        if( !b_start && !pk->b_started )
1356
3
        {
1357
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS Continuying a non started packet, ignoring\n" );
1358
3
            h->b_xds = false;
1359
3
            return;
1360
3
        }
1361
1362
1.84k
        h->b_xds = true;
1363
1.84k
        h->i_class = i_class;
1364
1.84k
        h->i_type  = i_type;
1365
1.84k
        h->b_future = !b_start;
1366
1.84k
        pk->b_started = true;
1367
1.84k
        if( b_start )
1368
1.84k
        {
1369
1.84k
            pk->i_data = 0;
1370
1.84k
            pk->i_sum = d1 + d2;
1371
1.84k
        }
1372
1.84k
    }
1373
11.9k
    else if( d1 == 0x0f && h->b_xds )
1374
1.47k
    {
1375
1.47k
        xds_packet_t *pk = &h->pkt[h->i_class][h->i_type];
1376
1377
        /* TODO checksum and decode */
1378
1.47k
        pk->i_sum += d1 + d2;
1379
1.47k
        if( pk->i_sum & 0x7f )
1380
38
        {
1381
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS invalid checksum, ignoring ---------------------------------\n" );
1382
38
            pk->b_started = false;
1383
38
            return;
1384
38
        }
1385
1.43k
        if( pk->i_data <= 0 )
1386
0
        {
1387
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS empty packet, ignoring ---------------------------------\n" );
1388
0
            pk->b_started = false;
1389
0
            return;
1390
0
        }
1391
1392
        //if( pk->p_data[pk->i_data-1] == 0x40 ) /* Padding byte */
1393
        //    pk->i_data--;
1394
1.43k
        XdsDecode( h, pk );
1395
1396
        /* Reset it */
1397
1.43k
        pk->b_started = false;
1398
1.43k
    }
1399
10.4k
    else if( d1 >= 0x20 && h->b_xds )
1400
8.13k
    {
1401
8.13k
        xds_packet_t *pk = &h->pkt[h->i_class][h->i_type];
1402
1403
8.13k
        if( pk->i_data+2 > XDS_MAX_DATA_SIZE )
1404
4
        {
1405
            /* Broken -> reinit */
1406
            //fprintf( stderr, "xxxxxxxxxxxxxxxXDS broken, reset\n" );
1407
4
            h->b_xds = false;
1408
4
            pk->b_started = false;
1409
4
            return;
1410
4
        }
1411
        /* TODO check parity bit */
1412
8.13k
        pk->p_data[pk->i_data++] = d1 & 0x7f;
1413
8.13k
        pk->p_data[pk->i_data++] = d2 & 0x7f;
1414
8.13k
        pk->i_sum += d1+d2;
1415
8.13k
    }
1416
2.33k
    else
1417
2.33k
    {
1418
2.33k
        h->b_xds = false;
1419
2.33k
    }
1420
13.7k
}
1421
1422
static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 )
1423
13.7k
{
1424
13.7k
    demux_sys_t *p_sys = p_demux->p_sys;
1425
1426
13.7k
    XdsParse( &p_sys->xds, d1, d2 );
1427
13.7k
    if( p_sys->xds.b_meta_changed )
1428
627
    {
1429
627
        xds_meta_t *m = &p_sys->xds.meta;
1430
627
        vlc_meta_t *p_meta;
1431
1432
        /* Channel meta data */
1433
627
        p_meta = vlc_meta_New();
1434
627
        if( m->psz_channel_name )
1435
627
            vlc_meta_SetPublisher( p_meta, m->psz_channel_name );
1436
627
        if( m->psz_channel_call_letter )
1437
627
            vlc_meta_SetTitle( p_meta, m->psz_channel_call_letter );
1438
627
        if( m->psz_channel_number )
1439
598
            vlc_meta_SetExtra( p_meta, "Channel number", m->psz_channel_number );
1440
627
        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META, TY_ES_GROUP, p_meta );
1441
627
        vlc_meta_Delete( p_meta );
1442
1443
        /* Event meta data (current/future) */
1444
627
        if( m->current.psz_name )
1445
199
        {
1446
199
            vlc_epg_t *p_epg = vlc_epg_New( TY_ES_GROUP, TY_ES_GROUP );
1447
199
            if ( p_epg )
1448
199
            {
1449
199
                vlc_epg_event_t *p_evt = vlc_epg_event_New( 0, 0, 0 );
1450
199
                if ( p_evt )
1451
199
                {
1452
199
                    if( m->current.psz_name )
1453
199
                        p_evt->psz_name = strdup( m->current.psz_name );
1454
199
                    if( !vlc_epg_AddEvent( p_epg, p_evt ) )
1455
0
                        vlc_epg_event_Delete( p_evt );
1456
199
                }
1457
                //if( m->current.psz_rating )
1458
                //  TODO but VLC cannot yet handle rating per epg event
1459
199
                vlc_epg_SetCurrent( p_epg, 0 );
1460
1461
199
                if( m->future.psz_name )
1462
0
                {
1463
0
                }
1464
199
                if( p_epg->i_event > 0 )
1465
199
                    es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG,
1466
199
                                    TY_ES_GROUP, p_epg );
1467
199
                vlc_epg_Delete( p_epg );
1468
199
            }
1469
199
        }
1470
627
    }
1471
13.7k
    p_sys->xds.b_meta_changed = false;
1472
13.7k
}
1473
1474
/* seek to an exact time position within the stream, if possible.
1475
 * l_seek_time is in nanoseconds, the TIVO time standard.
1476
 */
1477
static int ty_stream_seek_time(demux_t *p_demux, uint64_t l_seek_time)
1478
0
{
1479
0
    demux_sys_t *p_sys = p_demux->p_sys;
1480
0
    unsigned i_seq_entry = 0;
1481
0
    unsigned i;
1482
0
    int i_skip_cnt;
1483
0
    int64_t l_cur_pos = vlc_stream_Tell(p_demux->s);
1484
0
    unsigned i_cur_part = l_cur_pos / TIVO_PART_LENGTH;
1485
0
    uint64_t l_seek_secs = l_seek_time / 1000000000;
1486
0
    uint64_t l_fwd_stamp = 1;
1487
1488
    /* if we're not seekable, there's nothing to do */
1489
0
    if (!p_sys->b_seekable || !p_sys->b_have_master)
1490
0
        return VLC_EGENERIC;
1491
1492
0
    msg_Dbg(p_demux, "Skipping to time %02"PRIu64":%02"PRIu64":%02"PRIu64,
1493
0
            l_seek_secs / 3600, (l_seek_secs / 60) % 60, l_seek_secs % 60);
1494
1495
    /* seek to the proper segment if necessary */
1496
    /* first see if we need to go back */
1497
0
    while (l_seek_time < p_sys->l_first_ty_pts) {
1498
0
        msg_Dbg(p_demux, "skipping to prior segment.");
1499
        /* load previous part */
1500
0
        if (i_cur_part == 0) {
1501
0
            p_sys->eof = (vlc_stream_Seek(p_demux->s, l_cur_pos) != VLC_SUCCESS);
1502
0
            msg_Err(p_demux, "Attempt to seek past BOF");
1503
0
            return VLC_EGENERIC;
1504
0
        }
1505
0
        if(vlc_stream_Seek(p_demux->s, (i_cur_part - 1) * TIVO_PART_LENGTH) != VLC_SUCCESS)
1506
0
            return VLC_EGENERIC;
1507
0
        i_cur_part--;
1508
0
        if(parse_master(p_demux) != VLC_SUCCESS)
1509
0
            return VLC_EGENERIC;
1510
0
    }
1511
    /* maybe we need to go forward */
1512
0
    while (l_seek_time > p_sys->l_final_ty_pts) {
1513
0
        msg_Dbg(p_demux, "skipping to next segment.");
1514
        /* load next part */
1515
0
        if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1516
            /* error; restore previous file position */
1517
0
            p_sys->eof = (vlc_stream_Seek(p_demux->s, l_cur_pos) != VLC_SUCCESS);
1518
0
            msg_Err(p_demux, "seek error");
1519
0
            return VLC_EGENERIC;
1520
0
        }
1521
0
        if(vlc_stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH) != VLC_SUCCESS)
1522
0
            return VLC_EGENERIC;
1523
0
        i_cur_part++;
1524
0
        if(parse_master(p_demux) != VLC_SUCCESS)
1525
0
            return VLC_EGENERIC;
1526
0
    }
1527
1528
    /* our target is somewhere within this part;
1529
       find the proper chunk using seq_table */
1530
0
    for (i=1; i<p_sys->i_seq_table_size; i++) {
1531
0
        if (p_sys->seq_table[i].l_timestamp > l_seek_time) {
1532
            /* i-1 is the section we want; remember the next timestamp in case
1533
               we have to use it (this section may not have a proper SEQ hdr
1534
               for the time we're seeking) */
1535
0
            msg_Dbg(p_demux, "stopping at seq entry %d.", i);
1536
0
            l_fwd_stamp = p_sys->seq_table[i].l_timestamp;
1537
0
            i_seq_entry = i-1;
1538
0
            break;
1539
0
        }
1540
0
    }
1541
1542
    /* if we went through the entire last loop and didn't find our target,
1543
       then we skip to the next part.  What has happened is that the actual
1544
       time we're seeking is within this part, but there isn't a SEQ hdr
1545
       for it here.  So we skip to the next part */
1546
0
    if (i == p_sys->i_seq_table_size) {
1547
0
        if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1548
            /* error; restore previous file position */
1549
0
            p_sys->eof = (vlc_stream_Seek(p_demux->s, l_cur_pos) != VLC_SUCCESS);
1550
0
            msg_Err(p_demux, "seek error");
1551
0
            return VLC_EGENERIC;
1552
0
        }
1553
0
        if(vlc_stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH) != VLC_SUCCESS)
1554
0
            return VLC_EGENERIC;
1555
0
        i_cur_part++;
1556
0
        if(parse_master(p_demux) != VLC_SUCCESS)
1557
0
            return VLC_EGENERIC;
1558
0
        i_seq_entry = 0;
1559
0
    }
1560
1561
    /* determine which chunk has our seek_time */
1562
0
    for (i=0; i<p_sys->i_bits_per_seq_entry; i++) {
1563
0
        uint64_t l_chunk_nr = i_seq_entry * p_sys->i_bits_per_seq_entry + i;
1564
0
        uint64_t l_chunk_offset = (l_chunk_nr + 1) * CHUNK_SIZE;
1565
0
        msg_Dbg(p_demux, "testing part %d chunk %"PRIu64" mask 0x%02X bit %d",
1566
0
            i_cur_part, l_chunk_nr,
1567
0
            p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8], i%8);
1568
0
        if (p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8] & (1 << (i%8))) {
1569
            /* check this chunk's SEQ header timestamp */
1570
0
            msg_Dbg(p_demux, "has SEQ. seeking to chunk at 0x%"PRIu64,
1571
0
                (i_cur_part * TIVO_PART_LENGTH) + l_chunk_offset);
1572
0
            if(vlc_stream_Seek(p_demux->s, (i_cur_part * TIVO_PART_LENGTH) +
1573
0
                l_chunk_offset) != VLC_SUCCESS)
1574
0
                return VLC_EGENERIC;
1575
            // TODO: we don't have to parse the full header set;
1576
            // just test the seq_rec entry for its timestamp
1577
0
            p_sys->i_stuff_cnt = 0;
1578
0
            get_chunk_header(p_demux);
1579
            // check ty PTS for the SEQ entry in this chunk
1580
0
            if (p_sys->i_seq_rec < 0 || p_sys->i_seq_rec > p_sys->i_num_recs) {
1581
0
                msg_Err(p_demux, "no SEQ hdr in chunk; table had one.");
1582
                /* Seek to beginning of original chunk & reload it */
1583
0
                if(vlc_stream_Seek(p_demux->s, (l_cur_pos / CHUNK_SIZE) * CHUNK_SIZE) != VLC_SUCCESS)
1584
0
                    p_sys->eof = true;
1585
0
                p_sys->i_stuff_cnt = 0;
1586
0
                get_chunk_header(p_demux);
1587
0
                return VLC_EGENERIC;
1588
0
            }
1589
0
            l_seek_secs = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts /
1590
0
                1000000000;
1591
0
            msg_Dbg(p_demux, "found SEQ hdr for timestamp %02"PRIu64":%02"PRIu64":%02"PRIu64,
1592
0
                l_seek_secs / 3600,
1593
0
                (l_seek_secs / 60) % 60, l_seek_secs % 60);
1594
0
            if (p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts >= l_seek_time) {
1595
                // keep this one?  go back?
1596
                /* for now, we take this one.  it's the first SEQ hdr AFTER
1597
                   the time we were searching for. */
1598
0
                msg_Dbg(p_demux, "seek target found.");
1599
0
                break;
1600
0
            }
1601
0
            msg_Dbg(p_demux, "timestamp too early. still scanning.");
1602
0
        }
1603
0
    }
1604
    /* if we made it through this entire loop without finding our target,
1605
       then we skip to the next section.  What has happened is that the actual
1606
       time we're seeking is within this section, but there isn't a SEQ hdr
1607
       for it here.  So we skip to the next closest one (l_fwd_stamp) */
1608
0
    if (i == p_sys->i_bits_per_seq_entry)
1609
0
        return ty_stream_seek_time(p_demux, l_fwd_stamp);
1610
1611
    /* current stream ptr is at beginning of data for this chunk,
1612
       so we need to skip past any stream data prior to the seq_rec
1613
       in this chunk */
1614
0
    i_skip_cnt = 0;
1615
0
    for (int j=0; j<p_sys->i_seq_rec; j++)
1616
0
        i_skip_cnt += p_sys->rec_hdrs[j].l_rec_size;
1617
0
    if(vlc_stream_Read(p_demux->s, NULL, i_skip_cnt) != i_skip_cnt)
1618
0
        return VLC_EGENERIC;
1619
0
    p_sys->i_cur_rec = p_sys->i_seq_rec;
1620
    //p_sys->l_last_ty_pts = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts;
1621
    //p_sys->l_last_ty_pts_sync = p_sys->lastAudioPTS;
1622
1623
0
    return VLC_SUCCESS;
1624
0
}
1625
1626
1627
/* parse a master chunk, filling the SEQ table and other variables.
1628
 * We assume the stream is currently pointing to it.
1629
 */
1630
static int parse_master(demux_t *p_demux)
1631
599
{
1632
599
    demux_sys_t *p_sys = p_demux->p_sys;
1633
599
    uint8_t mst_buf[32];
1634
599
    int64_t i_save_pos = vlc_stream_Tell(p_demux->s);
1635
599
    int64_t i_pts_secs;
1636
1637
    /* Note that the entries in the SEQ table in the stream may have
1638
       different sizes depending on the bits per entry.  We store them
1639
       all in the same size structure, so we have to parse them out one
1640
       by one.  If we had a dynamic structure, we could simply read the
1641
       entire table directly from the stream into memory in place. */
1642
1643
    /* clear the SEQ table */
1644
599
    free(p_sys->seq_table);
1645
1646
    /* parse header info */
1647
599
    if( vlc_stream_Read(p_demux->s, mst_buf, 32) != 32 )
1648
0
        return VLC_EGENERIC;
1649
1650
599
    uint32_t i_map_size = U32_AT(&mst_buf[20]);  /* size of bitmask, in bytes */
1651
599
    uint32_t i = U32_AT(&mst_buf[28]);   /* size of SEQ table, in bytes */
1652
1653
599
    p_sys->i_bits_per_seq_entry = i_map_size * 8;
1654
599
    p_sys->i_seq_table_size = i / (8 + i_map_size);
1655
1656
599
    if(p_sys->i_seq_table_size == 0)
1657
30
    {
1658
30
        p_sys->seq_table = NULL;
1659
30
        return VLC_SUCCESS;
1660
30
    }
1661
1662
#if (UINT32_MAX > SSIZE_MAX)
1663
    if (i_map_size > SSIZE_MAX)
1664
        return VLC_EGENERIC;
1665
#endif
1666
1667
    /* parse all the entries */
1668
569
    p_sys->seq_table = calloc(p_sys->i_seq_table_size, sizeof(ty_seq_table_t));
1669
569
    if (p_sys->seq_table == NULL)
1670
0
    {
1671
0
        p_sys->i_seq_table_size = 0;
1672
0
        return VLC_SUCCESS;
1673
0
    }
1674
2.57M
    for (unsigned j=0; j<p_sys->i_seq_table_size; j++) {
1675
2.57M
        if(vlc_stream_Read(p_demux->s, mst_buf, 8) != 8)
1676
11
            return VLC_EGENERIC;
1677
2.57M
        p_sys->seq_table[j].l_timestamp = U64_AT(&mst_buf[0]);
1678
2.57M
        if (i_map_size > 8) {
1679
19.7k
            msg_Err(p_demux, "Unsupported SEQ bitmap size in master chunk");
1680
19.7k
            if (vlc_stream_Read(p_demux->s, NULL, i_map_size) != i_map_size )
1681
86
                return VLC_EGENERIC;
1682
2.55M
        } else {
1683
2.55M
            if (vlc_stream_Read(p_demux->s, mst_buf + 8, i_map_size)
1684
2.55M
                                              < (ssize_t)i_map_size)
1685
6
                return VLC_EGENERIC;
1686
2.55M
            memcpy(p_sys->seq_table[j].chunk_bitmask, &mst_buf[8], i_map_size);
1687
2.55M
        }
1688
2.57M
    }
1689
1690
    /* set up a few of our variables */
1691
466
    p_sys->l_first_ty_pts = p_sys->seq_table[0].l_timestamp;
1692
466
    p_sys->l_final_ty_pts =
1693
466
        p_sys->seq_table[p_sys->i_seq_table_size - 1].l_timestamp;
1694
466
    p_sys->b_have_master = true;
1695
1696
466
    i_pts_secs = p_sys->l_first_ty_pts / 1000000000;
1697
466
    msg_Dbg( p_demux,
1698
466
             "first TY pts in master is %02"PRId64":%02"PRId64":%02"PRId64,
1699
466
             i_pts_secs / 3600, (i_pts_secs / 60) % 60, i_pts_secs % 60 );
1700
466
    i_pts_secs = p_sys->l_final_ty_pts / 1000000000;
1701
466
    msg_Dbg( p_demux,
1702
466
             "final TY pts in master is %02"PRId64":%02"PRId64":%02"PRId64,
1703
466
             i_pts_secs / 3600, (i_pts_secs / 60) % 60, i_pts_secs % 60 );
1704
1705
    /* seek past this chunk */
1706
466
    return vlc_stream_Seek(p_demux->s, i_save_pos + CHUNK_SIZE);
1707
569
}
1708
1709
1710
1711
/* ======================================================================== */
1712
/* "Peek" at some chunks.  Skip over the Part header if we find it.
1713
 * We parse the peeked data and determine audio type,
1714
 * SA vs. DTivo, & Tivo Series.
1715
 * Set global vars i_Pes_Length, i_Pts_Offset,
1716
 * p_sys->tivo_series, p_sys->tivo_type, p_sys->audio_type */
1717
static int probe_stream(demux_t *p_demux)
1718
747
{
1719
747
    demux_sys_t *p_sys = p_demux->p_sys;
1720
747
    const uint8_t *p_buf;
1721
747
    int i;
1722
747
    bool b_probe_error = false;
1723
1724
    /* we need CHUNK_PEEK_COUNT chunks of data, first one might be a Part header, so ... */
1725
747
    if (vlc_stream_Peek( p_demux->s, &p_buf, CHUNK_PEEK_COUNT * CHUNK_SIZE ) <
1726
747
            CHUNK_PEEK_COUNT * CHUNK_SIZE) {
1727
0
        msg_Err(p_demux, "Can't peek %d chunks", CHUNK_PEEK_COUNT);
1728
        /* TODO: if seekable, then loop reading chunks into a temp buffer */
1729
0
        return VLC_EGENERIC;
1730
0
    }
1731
1732
    /* the real work: analyze this chunk */
1733
2.10k
    for (i = 0; i < CHUNK_PEEK_COUNT; i++) {
1734
2.05k
        int ret = analyze_chunk(p_demux, p_buf);
1735
2.05k
        if (ret != 0)
1736
67
            return VLC_EGENERIC;
1737
1738
1.98k
        if (p_sys->tivo_series != TIVO_SERIES_UNKNOWN &&
1739
699
            p_sys->audio_type  != TIVO_AUDIO_UNKNOWN &&
1740
670
            p_sys->tivo_type   != TIVO_TYPE_UNKNOWN)
1741
629
            break;
1742
1.35k
        p_buf += CHUNK_SIZE;
1743
1.35k
    }
1744
1745
    /* the final tally */
1746
680
    if (p_sys->tivo_series == TIVO_SERIES_UNKNOWN) {
1747
25
        msg_Err(p_demux, "Can't determine Tivo Series.");
1748
25
        b_probe_error = true;
1749
25
    }
1750
680
    if (p_sys->audio_type == TIVO_AUDIO_UNKNOWN) {
1751
30
        msg_Err(p_demux, "Can't determine Tivo Audio Type.");
1752
30
        b_probe_error = true;
1753
30
    }
1754
680
    if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1755
48
        msg_Err(p_demux, "Can't determine Tivo Type (SA/DTivo).");
1756
48
        b_probe_error = true;
1757
48
    }
1758
680
    return b_probe_error?VLC_EGENERIC:VLC_SUCCESS;
1759
747
}
1760
1761
1762
/* ======================================================================== */
1763
/* gather statistics for this chunk & set our tivo-type vars accordingly */
1764
static int analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
1765
2.05k
{
1766
2.05k
    demux_sys_t *p_sys = p_demux->p_sys;
1767
2.05k
    int i_num_recs, i;
1768
2.05k
    size_t chunk_size = CHUNK_SIZE;
1769
2.05k
    ty_rec_hdr_t *p_hdrs;
1770
2.05k
    int i_num_6e0, i_num_be0, i_num_9c0, i_num_3c0;
1771
2.05k
    int i_payload_size;
1772
1773
    /* skip if it's a Part header */
1774
2.05k
    if( U32_AT( &p_chunk[ 0 ] ) == TIVO_PES_FILEID )
1775
666
        return VLC_SUCCESS;
1776
1777
    /* number of records in chunk (we ignore high order byte;
1778
     * rarely are there > 256 chunks & we don't need that many anyway) */
1779
1.38k
    i_num_recs = p_chunk[0];
1780
1.38k
    if (i_num_recs < 5 || i_num_recs >= MAX_NUM_RECS) {
1781
        /* try again with the next chunk.  Sometimes there are dead ones */
1782
469
        return VLC_SUCCESS;
1783
469
    }
1784
1785
918
    p_chunk += CHUNK_HEADER_SIZE;       /* skip past rec count & SEQ bytes */
1786
918
    chunk_size -= CHUNK_HEADER_SIZE;
1787
    //msg_Dbg(p_demux, "probe: chunk has %d recs", i_num_recs);
1788
918
    p_hdrs = parse_chunk_headers(p_chunk, i_num_recs, &i_payload_size);
1789
918
    if (unlikely(p_hdrs == NULL))
1790
67
        return VLC_ENOMEM;
1791
    /* scan headers.
1792
     * 1. check video packets.  Presence of 0x6e0 means S1.
1793
     *    No 6e0 but have be0 means S2.
1794
     * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg)
1795
     *    If AC-3, then we have DTivo.
1796
     *    If MPEG, search for PTS offset.  This will determine SA vs. DTivo.
1797
     */
1798
851
    i_num_6e0 = i_num_be0 = i_num_9c0 = i_num_3c0 = 0;
1799
103k
    for (i=0; i<i_num_recs; i++) {
1800
        //msg_Dbg(p_demux, "probe: rec is %d/%d = 0x%04x", p_hdrs[i].subrec_type,
1801
            //p_hdrs[i].rec_type,
1802
            //p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type);
1803
102k
        switch (p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type) {
1804
112
            case 0x6e0:
1805
112
                i_num_6e0++;
1806
112
                break;
1807
7.50k
            case 0xbe0:
1808
7.50k
                i_num_be0++;
1809
7.50k
                break;
1810
16.6k
            case 0x3c0:
1811
16.6k
                i_num_3c0++;
1812
16.6k
                break;
1813
46
            case 0x9c0:
1814
46
                i_num_9c0++;
1815
46
                break;
1816
102k
        }
1817
102k
    }
1818
851
    msg_Dbg(p_demux, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.",
1819
851
        i_num_6e0, i_num_be0);
1820
1821
    /* set up our variables */
1822
851
    if (i_num_6e0 > 0) {
1823
22
        msg_Dbg(p_demux, "detected Series 1 Tivo");
1824
22
        p_sys->tivo_series = TIVO_SERIES1;
1825
22
        p_sys->i_Pes_Length = SERIES1_PES_LENGTH;
1826
829
    } else if (i_num_be0 > 0) {
1827
655
        msg_Dbg(p_demux, "detected Series 2 Tivo");
1828
655
        p_sys->tivo_series = TIVO_SERIES2;
1829
655
        p_sys->i_Pes_Length = SERIES2_PES_LENGTH;
1830
655
    }
1831
851
    if (i_num_9c0 > 0) {
1832
46
        msg_Dbg(p_demux, "detected AC-3 Audio (DTivo)" );
1833
46
        p_sys->audio_type = TIVO_AUDIO_AC3;
1834
46
        p_sys->tivo_type = TIVO_TYPE_DTIVO;
1835
46
        p_sys->i_Pts_Offset = AC3_PTS_OFFSET;
1836
46
        p_sys->i_Pes_Length = AC3_PES_LENGTH;
1837
805
    } else if (i_num_3c0 > 0) {
1838
635
        p_sys->audio_type = TIVO_AUDIO_MPEG;
1839
635
        msg_Dbg(p_demux, "detected MPEG Audio" );
1840
635
    }
1841
1842
    /* if tivo_type still unknown, we can check PTS location
1843
     * in MPEG packets to determine tivo_type */
1844
851
    if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1845
792
        uint32_t i_data_offset = (REC_SIZE * i_num_recs);
1846
39.8k
        for (i=0; i<i_num_recs; i++) {
1847
39.6k
            if ((p_hdrs[i].subrec_type << 0x08 | p_hdrs[i].rec_type) == 0x3c0 &&
1848
1.65k
                    p_hdrs[i].l_rec_size > 15) {
1849
                /* first make sure we're aligned */
1850
1.64k
                int i_pes_offset = find_es_header(ty_MPEGAudioPacket,
1851
1.64k
                        &p_chunk[i_data_offset], chunk_size - i_data_offset, 5);
1852
1.64k
                if (i_pes_offset >= 0) {
1853
                    /* pes found. on SA, PES has hdr data at offset 6, not PTS. */
1854
                    //msg_Dbg(p_demux, "probe: mpeg es header found in rec %d at offset %d",
1855
                            //i, i_pes_offset);
1856
590
                    if (i_data_offset + 6 + i_pes_offset < chunk_size &&
1857
590
                        (p_chunk[i_data_offset + 6 + i_pes_offset] & 0x80) == 0x80) {
1858
                        /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */
1859
563
                        if (p_sys->tivo_series == TIVO_SERIES1)
1860
563
                            msg_Dbg(p_demux, "detected Stand-Alone Tivo" );
1861
563
                        p_sys->tivo_type = TIVO_TYPE_SA;
1862
563
                        p_sys->i_Pts_Offset = SA_PTS_OFFSET;
1863
563
                    } else {
1864
27
                        if (p_sys->tivo_series == TIVO_SERIES1)
1865
27
                            msg_Dbg(p_demux, "detected DirecTV Tivo" );
1866
27
                        p_sys->tivo_type = TIVO_TYPE_DTIVO;
1867
27
                        p_sys->i_Pts_Offset = DTIVO_PTS_OFFSET;
1868
27
                    }
1869
590
                    break;
1870
590
                }
1871
1.64k
            }
1872
39.1k
            i_data_offset += p_hdrs[i].l_rec_size;
1873
39.1k
            if (i_data_offset > chunk_size)
1874
5
            {
1875
5
                msg_Dbg(p_demux, "rec[%d] overflows the size of the records %ld, aborting", i, p_hdrs[i].l_rec_size);
1876
5
                break;
1877
5
            }
1878
39.1k
        }
1879
792
    }
1880
851
    free(p_hdrs);
1881
851
    return VLC_SUCCESS;
1882
851
}
1883
1884
1885
/* =========================================================================== */
1886
static int get_chunk_header(demux_t *p_demux)
1887
2.28k
{
1888
2.28k
    int i_readSize, i_num_recs;
1889
2.28k
    uint8_t *p_hdr_buf;
1890
2.28k
    const uint8_t *p_peek;
1891
2.28k
    demux_sys_t *p_sys = p_demux->p_sys;
1892
2.28k
    int i_payload_size;             /* sum of all records' sizes */
1893
1894
2.28k
    msg_Dbg(p_demux, "parsing ty chunk #%d", p_sys->i_cur_chunk );
1895
1896
    /* if we have left-over filler space from the last chunk, get that */
1897
2.28k
    if (p_sys->i_stuff_cnt > 0) {
1898
716
        if(vlc_stream_Read(p_demux->s, NULL, p_sys->i_stuff_cnt) != p_sys->i_stuff_cnt)
1899
33
            return 0;
1900
683
        p_sys->i_stuff_cnt = 0;
1901
683
    }
1902
1903
    /* read the TY packet header */
1904
2.24k
    i_readSize = vlc_stream_Peek( p_demux->s, &p_peek, 4 );
1905
2.24k
    p_sys->i_cur_chunk++;
1906
1907
2.24k
    if ( (i_readSize < 4) || ( U32_AT(&p_peek[ 0 ] ) == 0 ))
1908
100
    {
1909
        /* EOF */
1910
100
        p_sys->eof = 1;
1911
100
        return 0;
1912
100
    }
1913
1914
    /* check if it's a PART Header */
1915
2.14k
    if( U32_AT( &p_peek[ 0 ] ) == TIVO_PES_FILEID )
1916
599
    {
1917
        /* parse master chunk */
1918
599
        if(parse_master(p_demux) != VLC_SUCCESS)
1919
103
            return 0;
1920
496
        return get_chunk_header(p_demux);
1921
599
    }
1922
1923
    /* number of records in chunk (8- or 16-bit number) */
1924
1.54k
    if (p_peek[3] & 0x80)
1925
1.21k
    {
1926
        /* 16 bit rec cnt */
1927
1.21k
        p_sys->i_num_recs = i_num_recs = (p_peek[1] << 8) + p_peek[0];
1928
1.21k
        p_sys->i_seq_rec = (p_peek[3] << 8) + p_peek[2];
1929
1.21k
        if (p_sys->i_seq_rec != 0xffff)
1930
663
        {
1931
663
            p_sys->i_seq_rec &= ~0x8000;
1932
663
        }
1933
1.21k
    }
1934
330
    else
1935
330
    {
1936
        /* 8 bit reclen - tivo 1.3 format */
1937
330
        p_sys->i_num_recs = i_num_recs = p_peek[0];
1938
330
        p_sys->i_seq_rec = p_peek[1];
1939
330
    }
1940
1941
1.54k
    if (i_num_recs >= MAX_NUM_RECS)
1942
101
        return 0;
1943
1944
1.44k
    p_sys->i_cur_rec = 0;
1945
1.44k
    p_sys->b_first_chunk = false;
1946
1947
    /*msg_Dbg( p_demux, "chunk has %d records", i_num_recs );*/
1948
1949
1.44k
    free(p_sys->rec_hdrs);
1950
1.44k
    p_sys->rec_hdrs = NULL;
1951
1952
    /* skip past the 4 bytes we "peeked" earlier */
1953
1.44k
    if(vlc_stream_Read(p_demux->s, NULL, 4) != 4)
1954
0
        return 0;
1955
1956
    /* read the record headers into a temp buffer */
1957
1.44k
    p_hdr_buf = malloc(i_num_recs * REC_SIZE);
1958
1.44k
    if (p_hdr_buf == NULL)
1959
0
        return VLC_ENOMEM;
1960
1.44k
    if (vlc_stream_Read(p_demux->s, p_hdr_buf, i_num_recs * REC_SIZE) < i_num_recs * REC_SIZE) {
1961
58
        free( p_hdr_buf );
1962
58
        p_sys->eof = true;
1963
58
        return 0;
1964
58
    }
1965
    /* parse them */
1966
1.39k
    p_sys->rec_hdrs = parse_chunk_headers(p_hdr_buf, i_num_recs, &i_payload_size);
1967
1.39k
    free(p_hdr_buf);
1968
1.39k
    if (unlikely(p_sys->rec_hdrs == NULL))
1969
68
    {
1970
68
        p_sys->i_num_recs = 0;
1971
68
        return VLC_ENOMEM;
1972
68
    }
1973
1974
1.32k
    p_sys->i_stuff_cnt = CHUNK_SIZE - 4 -
1975
1.32k
        (p_sys->i_num_recs * REC_SIZE) - i_payload_size;
1976
1.32k
    if (p_sys->i_stuff_cnt > 0)
1977
1.32k
        msg_Dbg( p_demux, "chunk has %d stuff bytes at end",
1978
1.32k
                 p_sys->i_stuff_cnt );
1979
1.32k
    return 1;
1980
1.39k
}
1981
1982
1983
static ty_rec_hdr_t *parse_chunk_headers( const uint8_t *p_buf,
1984
                                          int i_num_recs, int *pi_payload_size)
1985
2.30k
{
1986
2.30k
    int i;
1987
2.30k
    ty_rec_hdr_t *p_hdrs, *p_rec_hdr;
1988
1989
2.30k
    *pi_payload_size = 0;
1990
2.30k
    p_hdrs = vlc_alloc(i_num_recs, sizeof(ty_rec_hdr_t));
1991
2.30k
    if (unlikely(p_hdrs == NULL))
1992
0
        return NULL;
1993
1994
2.30k
    long total_l_rec_size = 0;
1995
206k
    for (i = 0; i < i_num_recs; i++)
1996
204k
    {
1997
204k
        const uint8_t *record_header = p_buf + (i * REC_SIZE);
1998
204k
        p_rec_hdr = &p_hdrs[i];     /* for brevity */
1999
204k
        p_rec_hdr->rec_type = record_header[3];
2000
204k
        p_rec_hdr->subrec_type = record_header[2] & 0x0f;
2001
204k
        if ((record_header[ 0 ] & 0x80) == 0x80)
2002
98.5k
        {
2003
98.5k
            uint8_t b1, b2;
2004
            /* marker bit 2 set, so read extended data */
2005
98.5k
            b1 = ( ( ( record_header[ 0 ] & 0x0f ) << 4 ) |
2006
98.5k
                   ( ( record_header[ 1 ] & 0xf0 ) >> 4 ) );
2007
98.5k
            b2 = ( ( ( record_header[ 1 ] & 0x0f ) << 4 ) |
2008
98.5k
                   ( ( record_header[ 2 ] & 0xf0 ) >> 4 ) );
2009
2010
98.5k
            p_rec_hdr->ex[0] = b1;
2011
98.5k
            p_rec_hdr->ex[1] = b2;
2012
98.5k
            p_rec_hdr->l_rec_size = 0;
2013
98.5k
            p_rec_hdr->l_ty_pts = 0;
2014
98.5k
            p_rec_hdr->b_ext = true;
2015
98.5k
        }
2016
106k
        else
2017
106k
        {
2018
106k
            p_rec_hdr->l_rec_size = ( record_header[ 0 ] << 8 |
2019
106k
                record_header[ 1 ] ) << 4 | ( record_header[ 2 ] >> 4 );
2020
106k
            total_l_rec_size += p_rec_hdr->l_rec_size;
2021
106k
            if (total_l_rec_size > (CHUNK_SIZE - CHUNK_HEADER_SIZE))
2022
135
            {
2023
135
                free(p_hdrs);
2024
135
                return NULL;
2025
135
            }
2026
105k
            *pi_payload_size += p_rec_hdr->l_rec_size;
2027
105k
            p_rec_hdr->b_ext = false;
2028
105k
            p_rec_hdr->l_ty_pts = U64_AT( &record_header[ 8 ] );
2029
105k
        }
2030
        //fprintf( stderr, "parse_chunk_headers[%d] t=0x%x s=%d\n", i, p_rec_hdr->rec_type, p_rec_hdr->subrec_type );
2031
204k
    } /* end of record-header loop */
2032
2.17k
    return p_hdrs;
2033
2.30k
}