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