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