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