]> git.sesse.net Git - vlc/blob - modules/demux/ty.c
Include vlc_plugin.h as needed
[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_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 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 static int  Open ( vlc_object_t * );
54 static void Close( vlc_object_t * );
55
56 vlc_module_begin();
57     set_shortname( _("TY") );
58     set_description(_("TY Stream audio/video demux"));
59     set_category( CAT_INPUT );
60     set_subcategory( SUBCAT_INPUT_DEMUX );
61     set_capability("demux", 6);
62     /* FIXME: there seems to be a segfault when using PVR access
63      * and TY demux has a bigger priority than PS
64      * Something must be wrong.
65      */
66     set_callbacks( Open, Close );
67     add_shortcut("ty");
68     add_shortcut("tivo");
69 vlc_module_end();
70
71 /*****************************************************************************
72  * Local prototypes
73  *****************************************************************************/
74 static int Demux  ( demux_t * );
75 static int Control( demux_t *, int, va_list );
76
77 #define SERIES1_PES_LENGTH  (11)    /* length of audio PES hdr on S1 */
78 #define SERIES2_PES_LENGTH  (16)    /* length of audio PES hdr on S2 */
79 #define AC3_PES_LENGTH      (14)    /* length of audio PES hdr for AC3 */
80 #define VIDEO_PES_LENGTH    (16)    /* length of video PES header */
81 #define DTIVO_PTS_OFFSET    (6)     /* offs into PES for MPEG PTS on DTivo */
82 #define SA_PTS_OFFSET       (9)     /* offset into PES for MPEG PTS on SA */
83 #define AC3_PTS_OFFSET      (9)     /* offset into PES for AC3 PTS on DTivo */
84 #define VIDEO_PTS_OFFSET    (9)     /* offset into PES for video PTS on all */
85 #define AC3_PKT_LENGTH      (1536)  /* size of TiVo AC3 pkts (w/o PES hdr) */
86 static const uint8_t ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 };
87 static const uint8_t ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 };
88 static const uint8_t ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd };
89
90 #define CHUNK_PEEK_COUNT    (3)         /* number of chunks to probe */
91
92 /* packet types for reference:
93  2/c0: audio data continued
94  3/c0: audio packet header (PES header)
95  4/c0: audio data (S/A only?)
96  9/c0: audio packet header, AC-3 audio
97  2/e0: video data continued
98  6/e0: video packet header (PES header)
99  7/e0: video sequence header start
100  8/e0: video I-frame header start
101  a/e0: video P-frame header start
102  b/e0: video B-frame header start
103  c/e0: video GOP header start
104  e/01: closed-caption data
105  e/02: Extended data services data 
106  e/03: ipreview data ("thumbs up to record" signal)
107  e/05: UK Teletext
108 */
109
110 #define TIVO_PES_FILEID   ( 0xf5467abd )
111 #define TIVO_PART_LENGTH  ( 0x20000000 )    /* 536,870,912 bytes */
112 #define CHUNK_SIZE        ( 128 * 1024 )
113
114 typedef struct
115 {
116   long l_rec_size;
117   uint8_t ex1, ex2;
118   uint8_t rec_type;
119   uint8_t subrec_type;
120   bool b_ext;
121   uint64_t l_ty_pts;            /* TY PTS in the record header */
122 } ty_rec_hdr_t;
123
124 typedef struct
125 {
126     uint64_t l_timestamp;
127     uint8_t chunk_bitmask[8];
128 } ty_seq_table_t;
129
130 typedef enum
131 {
132     TIVO_TYPE_UNKNOWN,
133     TIVO_TYPE_SA,
134     TIVO_TYPE_DTIVO
135 } tivo_type_t;
136
137 typedef enum
138 {
139     TIVO_SERIES_UNKNOWN,
140     TIVO_SERIES1,
141     TIVO_SERIES2
142 } tivo_series_t;
143
144 typedef enum
145 {
146     TIVO_AUDIO_UNKNOWN,
147     TIVO_AUDIO_AC3,
148     TIVO_AUDIO_MPEG
149 } tivo_audio_t;
150
151 #define XDS_MAX_DATA_SIZE (32)
152 typedef enum
153 {
154     XDS_CLASS_CURRENT        = 0,
155     XDS_CLASS_FUTURE         = 1,
156     XDS_CLASS_CHANNEL        = 2,
157     XDS_CLASS_MISCELLANEOUS  = 3,
158     XDS_CLASS_PUBLIC_SERVICE = 4,
159     XDS_CLASS_RESERVED       = 5,
160     XDS_CLASS_UNDEFINED      = 6,
161     XDS_CLASS_OTHER          = 7,
162
163     XDS_MAX_CLASS_COUNT
164 } xds_class_t;
165 typedef struct
166 {
167     bool b_started;
168     int        i_data;
169     uint8_t    p_data[XDS_MAX_DATA_SIZE];
170     int        i_sum;
171 } xds_packet_t;
172 typedef enum
173 {
174     XDS_META_PROGRAM_RATING_NONE,
175     XDS_META_PROGRAM_RATING_MPAA,
176     XDS_META_PROGRAM_RATING_TPG,
177     /* TODO add CA/CE rating */
178 } xds_meta_program_rating_t;
179 typedef struct
180 {
181     char *psz_name;
182     xds_meta_program_rating_t rating;
183     char *psz_rating;
184     /* Add the other fields once I have the samples */
185 } xds_meta_program_t;
186 typedef struct
187 {
188     char *psz_channel_name;
189     char *psz_channel_call_letter;
190     char *psz_channel_number;
191
192     xds_meta_program_t  current;
193     xds_meta_program_t  future;
194 } xds_meta_t;
195 typedef struct
196 {
197     /* Are we in XDS mode */
198     bool b_xds;
199
200     /* Current class type */
201     xds_class_t i_class;
202     int         i_type;
203     bool  b_future;
204
205     /* */
206     xds_packet_t pkt[XDS_MAX_CLASS_COUNT][128]; /* XXX it is way too much, but simpler */
207
208     /* */
209     bool  b_meta_changed;
210     xds_meta_t  meta;
211
212 } xds_t;
213
214 struct demux_sys_t
215 {
216   es_out_id_t *p_video;               /* ptr to video codec */
217   es_out_id_t *p_audio;               /* holds either ac3 or mpeg codec ptr */
218
219   cc_data_t   cc;
220   es_out_id_t *p_cc[4];
221
222   xds_t       xds;
223
224   int             i_cur_chunk;
225   int             i_stuff_cnt;
226   size_t          i_stream_size;      /* size of input stream (if known) */
227   //uint64_t        l_program_len;      /* length of this stream in msec */
228   bool      b_seekable;         /* is this stream seekable? */
229   bool      b_have_master;      /* are master chunks present? */
230   tivo_type_t     tivo_type;          /* tivo type (SA / DTiVo) */
231   tivo_series_t   tivo_series;        /* Series1 or Series2 */
232   tivo_audio_t    audio_type;         /* AC3 or MPEG */
233   int             i_Pes_Length;       /* Length of Audio PES header */
234   int             i_Pts_Offset;       /* offset into audio PES of PTS */
235   uint8_t         pes_buffer[20];     /* holds incomplete pes headers */
236   int             i_pes_buf_cnt;      /* how many bytes in our buffer */
237   size_t          l_ac3_pkt_size;     /* len of ac3 pkt we've seen so far */
238   uint64_t        l_last_ty_pts;      /* last TY timestamp we've seen */
239   //mtime_t         l_last_ty_pts_sync; /* audio PTS at time of last TY PTS */
240   uint64_t        l_first_ty_pts;     /* first TY PTS in this master chunk */
241   uint64_t        l_final_ty_pts;     /* final TY PTS in this master chunk */
242   int             i_seq_table_size;   /* number of entries in SEQ table */
243   int             i_bits_per_seq_entry; /* # of bits in SEQ table bitmask */
244
245   mtime_t         firstAudioPTS;
246   mtime_t         lastAudioPTS;
247   mtime_t         lastVideoPTS;
248
249   ty_rec_hdr_t    *rec_hdrs;          /* record headers array */
250   int             i_cur_rec;          /* current record in this chunk */
251   int             i_num_recs;         /* number of recs in this chunk */
252   int             i_seq_rec;          /* record number where seq start is */
253   ty_seq_table_t  *seq_table;         /* table of SEQ entries from mstr chk */
254   bool      eof;
255   bool      b_first_chunk;
256 };
257
258 static int get_chunk_header(demux_t *);
259 static mtime_t get_pts( const uint8_t *buf );
260 static int find_es_header( const uint8_t *header,
261                            const uint8_t *buffer, int i_search_len );
262 static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct);
263 static int ty_stream_seek_time(demux_t *, uint64_t);
264
265 static ty_rec_hdr_t *parse_chunk_headers( demux_t *p_demux, const uint8_t *p_buf,
266                                           int i_num_recs, int *pi_payload_size);
267 static int probe_stream(demux_t *p_demux);
268 static void analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk);
269 static void parse_master(demux_t *p_demux);
270
271 static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
272 static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
273 static int DemuxRecCc( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
274
275 static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 );
276
277 static void XdsInit( xds_t * );
278 static void XdsExit( xds_t * );
279
280 #define TY_ES_GROUP (1)
281
282 /*
283  * Open: check file and initialize demux structures
284  *
285  * here's what we do:
286  * 1. peek at the first 12 bytes of the stream for the
287  *    magic TiVo PART header & stream type & chunk size
288  * 2. if it's not there, error with VLC_EGENERIC
289  * 3. set up video (mpgv) codec
290  * 4. return VLC_SUCCESS
291  */
292 static int Open(vlc_object_t *p_this)
293 {
294     demux_t *p_demux = (demux_t *)p_this;
295     demux_sys_t *p_sys;
296     es_format_t fmt;
297     const uint8_t *p_peek;
298     int i;
299
300     /* peek at the first 12 bytes. */
301     /* for TY streams, they're always the same */
302     if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
303         return VLC_EGENERIC;
304
305     if ( U32_AT(p_peek) != TIVO_PES_FILEID ||
306          U32_AT(&p_peek[4]) != 0x02 ||
307          U32_AT(&p_peek[8]) != CHUNK_SIZE )
308     {
309         if( !p_demux->b_force &&
310             !demux_IsPathExtension( p_demux, ".ty" ) &&
311             !demux_IsPathExtension( p_demux, ".ty+" ) )
312             return VLC_EGENERIC;
313         msg_Warn( p_demux, "this does not look like a TY file, "
314                            "continuing anyway..." );
315     }
316
317         /* at this point, we assume we have a valid TY stream */  
318     msg_Dbg( p_demux, "valid TY stream detected" );
319
320     /* Set exported functions */
321     p_demux->pf_demux = Demux;
322     p_demux->pf_control = Control;
323
324     /* create our structure that will hold all data */
325     p_demux->p_sys = p_sys = malloc(sizeof(demux_sys_t));
326     memset(p_sys, 0, sizeof(demux_sys_t));
327
328     /* set up our struct (most were zero'd out with the memset above) */
329     p_sys->b_first_chunk = true;
330     p_sys->b_have_master = (U32_AT(p_peek) == TIVO_PES_FILEID);
331     p_sys->firstAudioPTS = -1;
332     p_sys->i_stream_size = stream_Size(p_demux->s);
333     p_sys->tivo_type = TIVO_TYPE_UNKNOWN;
334     p_sys->audio_type = TIVO_AUDIO_UNKNOWN;
335     p_sys->tivo_series = TIVO_SERIES_UNKNOWN;
336     p_sys->i_Pes_Length = 0;
337     p_sys->i_Pts_Offset = 0;
338     p_sys->l_ac3_pkt_size = 0;
339   
340     /* see if this stream is seekable */
341     stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
342
343     if (probe_stream(p_demux) != VLC_SUCCESS) {
344         //TyClose(p_demux);
345         return VLC_EGENERIC;
346     }
347
348     if (!p_sys->b_have_master)
349       msg_Warn(p_demux, "No master chunk found; seeking will be limited.");
350
351     /* register the proper audio codec */
352     if (p_sys->audio_type == TIVO_AUDIO_MPEG) {
353         es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
354     } else {
355         es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', ' ' ) );
356     }
357     fmt.i_group = TY_ES_GROUP;
358     p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
359
360     /* register the video stream */
361     es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', 'g', 'v' ) );
362     fmt.i_group = TY_ES_GROUP;
363     p_sys->p_video = es_out_Add( p_demux->out, &fmt );
364
365     /* */
366     for( i = 0; i < 4; i++ )
367         p_sys->p_cc[i] = NULL;
368     cc_Init( &p_sys->cc );
369
370     XdsInit( &p_sys->xds );
371
372     return VLC_SUCCESS;
373 }
374
375 /* =========================================================================== */
376 /* Demux: Read & Demux one record from the chunk
377  *
378  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
379  *
380  * NOTE: I think we can return the number of packets sent instead of just 1.
381  * that means we can demux an entire chunk and shoot it back (may be more efficient)
382  * -- should try that some day :) --
383  */
384 static int Demux( demux_t *p_demux )
385 {
386     demux_sys_t  *p_sys = p_demux->p_sys;
387     ty_rec_hdr_t *p_rec;
388     block_t      *p_block_in = NULL;
389
390     /*msg_Dbg(p_demux, "ty demux processing" );*/
391    
392     /* did we hit EOF earlier? */
393     if( p_sys->eof )
394         return 0;
395
396     /*
397      * what we do (1 record now.. maybe more later):
398     * - use stream_Read() to read the chunk header & record headers
399     * - discard entire chunk if it is a PART header chunk
400     * - parse all the headers into record header array
401     * - keep a pointer of which record we're on
402     * - use stream_Block() to fetch each record
403     * - parse out PTS from PES headers
404     * - set PTS for data packets
405     * - pass the data on to the proper codec via es_out_Send()
406
407     * if this is the first time or  
408     * if we're at the end of this chunk, start a new one
409     */
410     /* parse the next chunk's record headers */
411     if( p_sys->b_first_chunk || p_sys->i_cur_rec >= p_sys->i_num_recs )
412     {
413         if( get_chunk_header(p_demux) == 0 )
414             return 0;
415     }
416
417     /*======================================================================
418      * parse & send one record of the chunk
419      *====================================================================== */
420     p_rec = &p_sys->rec_hdrs[p_sys->i_cur_rec];
421
422     if( !p_rec->b_ext )
423     {
424         const long l_rec_size = p_rec->l_rec_size;
425         /*msg_Dbg(p_demux, "Record Type 0x%x/%02x %ld bytes",
426                     subrec_type, p_rec->rec_type, l_rec_size );*/
427   
428         /* some normal records are 0 length, so check for that... */
429         if( l_rec_size <= 0 )
430         {
431             /* no data in payload; we're done */
432             p_sys->i_cur_rec++;
433             return 1;
434         }
435
436         /* read in this record's payload */
437         if( !( p_block_in = stream_Block( p_demux->s, l_rec_size ) ) )
438             return 0;
439
440         /* set these as 'unknown' for now */
441         p_block_in->i_pts =
442         p_block_in->i_dts = 0;
443     }
444     /*else
445     {
446         -- don't read any data from the stream, data was in the record header --
447         msg_Dbg(p_demux,
448                "Record Type 0x%02x/%02x, ext data = %02x, %02x", subrec_type,
449                 p_rec->rec_type, p_rec->ex1, p_rec->ex2);
450     }*/
451
452     if( p_rec->rec_type == 0xe0 )
453     {
454         /* Video */
455         DemuxRecVideo( p_demux, p_rec, p_block_in );
456     }
457     else if ( p_rec->rec_type == 0xc0 )
458     {
459         /* Audio */
460         DemuxRecAudio( p_demux, p_rec, p_block_in );
461     }
462     else if( p_rec->rec_type == 0x01 || p_rec->rec_type == 0x02 )
463     {
464         /* Closed Captions/XDS */
465         DemuxRecCc( p_demux, p_rec, p_block_in );
466     }
467     else if ( p_rec->rec_type == 0x03 )
468     {
469         /* Tivo data services (e.g. "thumbs-up to record!")  useless for us */
470         if( p_block_in )
471             block_Release(p_block_in);
472     }
473     else if ( p_rec->rec_type == 0x05 )
474     {
475         /* Unknown, but seen regularly */
476         if( p_block_in )
477             block_Release(p_block_in);
478     }
479     else
480     {
481         msg_Dbg(p_demux, "Invalid record type 0x%02x", p_rec->rec_type );
482         if( p_block_in )
483             block_Release(p_block_in);
484     }
485
486     /* */
487     p_sys->i_cur_rec++;
488     return 1;
489 }
490
491 /* Control */
492 static int Control(demux_t *p_demux, int i_query, va_list args)
493 {
494     demux_sys_t *p_sys = p_demux->p_sys;
495     double f, *pf;
496     int64_t i64, *p_i64;
497
498     /*msg_Info(p_demux, "control cmd %d", i_query);*/
499     switch( i_query )
500     {
501     case DEMUX_GET_POSITION:
502         /* arg is 0.0 - 1.0 percent of overall file position */
503         if( ( i64 = p_sys->i_stream_size ) > 0 )
504         {
505             pf = (double*) va_arg( args, double* );
506             *pf = (double)stream_Tell( p_demux->s ) / (double) i64;
507             return VLC_SUCCESS;
508         }
509         return VLC_EGENERIC;
510
511     case DEMUX_SET_POSITION:
512         /* arg is 0.0 - 1.0 percent of overall file position */
513         f = (double) va_arg( args, double );
514         /* msg_Dbg(p_demux, "Control - set position to %2.3f", f); */
515         if ((i64 = p_sys->i_stream_size) > 0)
516             return ty_stream_seek_pct(p_demux, f);
517         return VLC_EGENERIC;
518     case DEMUX_GET_TIME:
519         /* return TiVo timestamp */
520         p_i64 = (int64_t *) va_arg(args, int64_t *);
521         //*p_i64 = p_sys->lastAudioPTS - p_sys->firstAudioPTS;
522         //*p_i64 = (p_sys->l_last_ty_pts / 1000) + (p_sys->lastAudioPTS -
523         //    p_sys->l_last_ty_pts_sync);
524         *p_i64 = (p_sys->l_last_ty_pts / 1000);
525         return VLC_SUCCESS;
526     case DEMUX_GET_LENGTH:    /* length of program in microseconds, 0 if unk */
527         /* size / bitrate */
528         p_i64 = (int64_t *) va_arg(args, int64_t *);
529         *p_i64 = 0;
530         return VLC_SUCCESS;
531     case DEMUX_SET_TIME:      /* arg is time in microsecs */
532         i64 = (int64_t) va_arg( args, int64_t );
533         return ty_stream_seek_time(p_demux, i64 * 1000);
534     case DEMUX_GET_FPS:
535     default:
536         return VLC_EGENERIC;
537     }
538 }
539
540 /* Close */
541 static void Close( vlc_object_t *p_this )
542 {
543     demux_t *p_demux = (demux_t*)p_this;
544     demux_sys_t *p_sys = p_demux->p_sys;
545
546     XdsExit( &p_sys->xds );
547     cc_Exit( &p_sys->cc );
548     free( p_sys->rec_hdrs );
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 %"PRId64, 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] = 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 %"PRId64, 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 = false;
1116     h->i_class = XDS_MAX_CLASS_COUNT;
1117     h->i_type = 0;
1118     h->b_future = 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 = false;
1123     }
1124     h->b_meta_changed = false;
1125     memset( &h->meta, 0, sizeof(h->meta) );
1126 }
1127 static void XdsExit( xds_t *h )
1128 {
1129     /* */
1130     free( h->meta.psz_channel_name );
1131     free( h->meta.psz_channel_call_letter );
1132     free( h->meta.psz_channel_number );
1133
1134     /* */
1135     free( h->meta.current.psz_name );
1136     free( h->meta.current.psz_rating );
1137     /* */
1138     free( h->meta.future.psz_name );
1139     free( h->meta.future.psz_rating );
1140 }
1141 static void XdsStringUtf8( char dst[2*32+1], const uint8_t *p_src, int i_src )
1142 {
1143     int i;
1144     int i_dst;
1145
1146     for( i = 0, i_dst = 0; i < i_src; i++ )
1147     {
1148         switch( p_src[i] )
1149         {
1150 #define E2( c, u1, u2 ) case c: dst[i_dst++] = u1; dst[i_dst++] = u2; break
1151         E2( 0x2a, 0xc3,0xa1); // lowercase a, acute accent
1152         E2( 0x5c, 0xc3,0xa9); // lowercase e, acute accent
1153         E2( 0x5e, 0xc3,0xad); // lowercase i, acute accent
1154         E2( 0x5f, 0xc3,0xb3); // lowercase o, acute accent
1155         E2( 0x60, 0xc3,0xba); // lowercase u, acute accent
1156         E2( 0x7b, 0xc3,0xa7); // lowercase c with cedilla
1157         E2( 0x7c, 0xc3,0xb7); // division symbol
1158         E2( 0x7d, 0xc3,0x91); // uppercase N tilde
1159         E2( 0x7e, 0xc3,0xb1); // lowercase n tilde
1160 #undef E2
1161         default:
1162             dst[i_dst++] = p_src[i];
1163             break;
1164         }
1165     }
1166     dst[i_dst++] = '\0';
1167 }
1168 static bool XdsChangeString( xds_t *h, char **ppsz_dst, const char *psz_new )
1169 {
1170     if( *ppsz_dst && psz_new && !strcmp( *ppsz_dst, psz_new ) )
1171         return false;
1172     if( *ppsz_dst == NULL && psz_new == NULL )
1173         return false;
1174
1175     free( *ppsz_dst );
1176     if( psz_new )
1177         *ppsz_dst = strdup( psz_new );
1178     else
1179         *ppsz_dst = NULL;
1180
1181     h->b_meta_changed = true;
1182     return true;
1183 }
1184
1185 static void XdsDecodeCurrentFuture( xds_t *h, xds_packet_t *pk )
1186 {
1187     xds_meta_program_t *p_prg = h->b_future ? &h->meta.future : &h->meta.current;
1188     char name[2*32+1];
1189     int i_rating;
1190
1191     switch( h->i_type )
1192     {
1193     case 0x03:
1194         XdsStringUtf8( name, pk->p_data, pk->i_data );
1195         if( XdsChangeString( h, &p_prg->psz_name, name ) )
1196         {
1197             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Program Name) %d'\n", pk->i_data );
1198             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> program name %s\n", name );
1199         }
1200         break;
1201     case 0x05:
1202         i_rating = (pk->p_data[0] & 0x18);
1203         if( i_rating == 0x08 )
1204         {
1205             /* TPG */
1206             static const char *pppsz_ratings[8][2] = {
1207                 { "None",   "No rating (no content advisory)" },
1208                 { "TV-Y",   "All Children (no content advisory)" },
1209                 { "TV-Y7",  "Directed to Older Children (V = Fantasy Violence)" },
1210                 { "TV-G",   "General Audience (no content advisory)" },
1211                 { "TV-PG",  "Parental Guidance Suggested" },
1212                 { "TV-14",  "Parents Strongly Cautioned" },
1213                 { "TV-MA",  "Mature Audience Only" },
1214                 { "None",   "No rating (no content advisory)" }
1215             };
1216             p_prg->rating = XDS_META_PROGRAM_RATING_TPG;
1217             if( XdsChangeString( h, &p_prg->psz_rating, pppsz_ratings[pk->p_data[1]&0x07][0] ) )
1218             {
1219                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Rating) %d'\n", pk->i_data );
1220                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> TPG Rating %s (%s)\n",
1221                 //         pppsz_ratings[pk->p_data[1]&0x07][0], pppsz_ratings[pk->p_data[1]&0x07][1] );
1222             }
1223         }
1224         else if( i_rating == 0x00 || i_rating == 0x10 )
1225         {
1226             /* MPAA */
1227             static const char *pppsz_ratings[8][2] = {
1228                 { "N/A",    "N/A" },
1229                 { "G",      "General Audiences" },
1230                 { "PG",     "Parental Guidance Suggested" },
1231                 { "PG-13",  "Parents Strongly Cautioned" },
1232                 { "R",      "Restricted" },
1233                 { "NC-17",  "No one 17 and under admitted" },
1234                 { "X",      "No one under 17 admitted" },
1235                 { "NR",     "Not Rated" },
1236             };
1237             p_prg->rating = XDS_META_PROGRAM_RATING_MPAA;
1238             if( XdsChangeString( h, &p_prg->psz_rating, pppsz_ratings[pk->p_data[0]&0x07][0] ) )
1239             {
1240                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Rating) %d'\n", pk->i_data );
1241                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> TPG Rating %s (%s)\n",
1242                 //         pppsz_ratings[pk->p_data[0]&0x07][0], pppsz_ratings[pk->p_data[0]&0x07][1] );
1243             }
1244         }
1245         else
1246         {
1247             /* Non US Rating TODO */
1248             assert( i_rating == 0x18 ); // only left value possible */
1249             p_prg->rating = XDS_META_PROGRAM_RATING_NONE;
1250             if( XdsChangeString( h, &p_prg->psz_rating, NULL ) )
1251             {
1252                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Rating) %d'\n", pk->i_data );
1253                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> 0x%2.2x 0x%2.2x\n", pk->p_data[0], pk->p_data[1] );
1254             }
1255         }
1256         break;
1257
1258     default:
1259 #ifdef TY_XDS_DEBUG
1260         fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Current/Future (Unknown 0x%x)'\n", h->i_type );
1261 #endif
1262         break;
1263     }
1264 }
1265
1266 static void XdsDecodeChannel( xds_t *h, xds_packet_t *pk )
1267 {
1268     char name[2*32+1];
1269     char chan[2*32+1];
1270
1271     switch( h->i_type )
1272     {
1273     case 0x01:
1274         if( pk->i_data < 2 )
1275             return;
1276         XdsStringUtf8( name, pk->p_data, pk->i_data );
1277         if( XdsChangeString( h, &h->meta.psz_channel_name, name ) )
1278         {
1279             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Name) %d'\n", pk->i_data );
1280             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> %s\n", name );
1281         }
1282         break;
1283
1284     case 0x02:
1285         if( pk->i_data < 4 )
1286             return;
1287
1288         XdsStringUtf8( name, pk->p_data, 4 );
1289         if( XdsChangeString( h, &h->meta.psz_channel_call_letter, name ) )
1290         {
1291             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Call Letter)' %d\n", pk->i_data );
1292             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> call letter %s\n", name );
1293         }
1294         if( pk->i_data >= 6 )
1295         {
1296             XdsStringUtf8( chan, &pk->p_data[4], 2 );
1297             if( XdsChangeString( h, &h->meta.psz_channel_number, chan ) )
1298             {
1299                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Call Letter)' %d\n", pk->i_data );
1300                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> channel number %s\n", chan );
1301             }
1302         }
1303         else
1304         {
1305             if( XdsChangeString( h, &h->meta.psz_channel_number, NULL ) )
1306             {
1307                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Network Call Letter)' %d\n", pk->i_data );
1308                 //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: ====> no channel number letter anymore\n" );
1309             }
1310         }
1311         break;
1312     case 0x03:
1313         //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Channel Tape Delay)'\n" );
1314         break;
1315     case 0x04:
1316         //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Transmission Signal Identifier)'\n" );
1317         break;
1318     default:
1319 #ifdef TY_XDS_DEBUG
1320         fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Channel (Unknown 0x%x)'\n", h->i_type );
1321 #endif
1322         break;
1323     }
1324 }
1325
1326 static void XdsDecode( xds_t *h, xds_packet_t *pk )
1327 {
1328     switch( h->i_class )
1329     {
1330     case XDS_CLASS_CURRENT:
1331     case XDS_CLASS_FUTURE:
1332         XdsDecodeCurrentFuture( h, pk );
1333         break;
1334     case XDS_CLASS_CHANNEL:
1335         XdsDecodeChannel( h, pk );
1336         break;
1337     case XDS_CLASS_MISCELLANEOUS:
1338 #ifdef TY_XDS_DEBUG
1339         fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Miscellaneous'\n" );
1340 #endif
1341         break;
1342     case XDS_CLASS_PUBLIC_SERVICE:
1343 #ifdef TY_XDS_DEBUG
1344         fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: class 'Public Service'\n" );
1345 #endif
1346         break;
1347     default:
1348         //fprintf( stderr, "xxxxxxxxxxxxxxxXDS XdsDecode: unknown class\n" );
1349         break;
1350     }
1351 }
1352
1353 static void XdsParse( xds_t *h, uint8_t d1, uint8_t d2 )
1354 {
1355     /* TODO check parity */
1356     d1 &= 0x7f;
1357     d2 &= 0x7f;
1358
1359     /* */
1360     if( d1 >= 0x01 && d1 <= 0x0e )
1361     {
1362         const xds_class_t i_class = ( d1 - 1 ) >> 1;
1363         const int i_type = d2;
1364         const bool b_start = d1 & 0x01;
1365         xds_packet_t *pk = &h->pkt[i_class][i_type];
1366
1367         if( !b_start && !pk->b_started )
1368         {
1369             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS Continuying a non started packet, ignoring\n" );
1370             h->b_xds = false;
1371             return;
1372         }
1373
1374         h->b_xds = true;
1375         h->i_class = i_class;
1376         h->i_type  = i_type;
1377         h->b_future = !b_start;
1378         pk->b_started = true;
1379         if( b_start )
1380         {
1381             pk->i_data = 0;
1382             pk->i_sum = d1 + d2;
1383         }
1384     }
1385     else if( d1 == 0x0f && h->b_xds )
1386     {
1387         xds_packet_t *pk = &h->pkt[h->i_class][h->i_type];
1388
1389         /* TODO checksum and decode */
1390         pk->i_sum += d1 + d2;
1391         if( pk->i_sum & 0x7f )
1392         {
1393             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS invalid checksum, ignoring ---------------------------------\n" );
1394             pk->b_started = false;
1395             return;
1396         }
1397         if( pk->i_data <= 0 )
1398         {
1399             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS empty packet, ignoring ---------------------------------\n" );
1400             pk->b_started = false;
1401             return;
1402         }
1403
1404         //if( pk->p_data[pk->i_data-1] == 0x40 ) /* Padding byte */
1405         //    pk->i_data--;
1406         XdsDecode( h, pk );
1407
1408         /* Reset it */
1409         pk->b_started = false;
1410     }
1411     else if( d1 >= 0x20 && h->b_xds )
1412     {
1413         xds_packet_t *pk = &h->pkt[h->i_class][h->i_type];
1414
1415         if( pk->i_data+2 > XDS_MAX_DATA_SIZE )
1416         {
1417             /* Broken -> reinit */
1418             //fprintf( stderr, "xxxxxxxxxxxxxxxXDS broken, reset\n" );
1419             h->b_xds = false;
1420             pk->b_started = false;
1421             return;
1422         }
1423         /* TODO check parity bit */
1424         pk->p_data[pk->i_data++] = d1 & 0x7f;
1425         pk->p_data[pk->i_data++] = d2 & 0x7f;
1426         pk->i_sum += d1+d2;
1427     }
1428     else
1429     {
1430         h->b_xds = false;
1431     }
1432 }
1433
1434 static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 )
1435 {
1436     demux_sys_t *p_sys = p_demux->p_sys;
1437
1438     XdsParse( &p_demux->p_sys->xds, d1, d2 );
1439     if( p_demux->p_sys->xds.b_meta_changed )
1440     {
1441         xds_meta_t *m = &p_sys->xds.meta;
1442         vlc_meta_t *p_meta;
1443         vlc_epg_t *p_epg;
1444
1445         /* Channel meta data */
1446         p_meta = vlc_meta_New();
1447         if( m->psz_channel_name )
1448             vlc_meta_SetPublisher( p_meta, m->psz_channel_name );
1449         if( m->psz_channel_call_letter )
1450             vlc_meta_SetTitle( p_meta, m->psz_channel_call_letter );
1451         if( m->psz_channel_number )
1452             vlc_meta_AddExtra( p_meta, "Channel number", m->psz_channel_number );
1453         es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META, TY_ES_GROUP, p_meta );
1454         vlc_meta_Delete( p_meta );
1455
1456         /* Event meta data (current/future) */
1457         p_epg = vlc_epg_New( NULL );
1458         if( m->current.psz_name )
1459         {
1460             vlc_epg_AddEvent( p_epg, 0, 0, m->current.psz_name, NULL, NULL );
1461             //if( m->current.psz_rating )
1462             //  TODO but VLC cannot yet handle rating per epg event
1463             vlc_epg_SetCurrent( p_epg, 0 );
1464         }
1465         if( m->future.psz_name )
1466         {
1467         }
1468         if( p_epg->i_event > 0 )
1469             es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, TY_ES_GROUP, p_epg );
1470         vlc_epg_Delete( p_epg );
1471     }
1472     p_demux->p_sys->xds.b_meta_changed = false;
1473 }
1474
1475 /* seek to an exact time position within the stream, if possible.
1476  * l_seek_time is in nanoseconds, the TIVO time standard.
1477  */
1478 static int ty_stream_seek_time(demux_t *p_demux, uint64_t l_seek_time)
1479 {
1480     demux_sys_t *p_sys = p_demux->p_sys;
1481     int i, i_seq_entry = 0;
1482     int i_skip_cnt;
1483     long l_cur_pos = stream_Tell(p_demux->s);
1484     int i_cur_part = l_cur_pos / TIVO_PART_LENGTH;
1485     long l_seek_secs = l_seek_time / 1000000000;
1486     uint64_t l_fwd_stamp = 1;
1487
1488     /* if we're not seekable, there's nothing to do */
1489     if (!p_sys->b_seekable || !p_sys->b_have_master)
1490         return VLC_EGENERIC;
1491
1492     msg_Dbg(p_demux, "Skipping to time %02ld:%02ld:%02ld",
1493             l_seek_secs / 3600, (l_seek_secs / 60) % 60, l_seek_secs % 60);
1494
1495     /* seek to the proper segment if necessary */
1496     /* first see if we need to go back */
1497     while (l_seek_time < p_sys->l_first_ty_pts) {
1498         msg_Dbg(p_demux, "skipping to prior segment.");
1499         /* load previous part */
1500         if (i_cur_part == 0) {
1501             stream_Seek(p_demux->s, l_cur_pos);
1502             msg_Err(p_demux, "Attempt to seek past BOF");
1503             return VLC_EGENERIC;
1504         }
1505         stream_Seek(p_demux->s, (i_cur_part - 1) * TIVO_PART_LENGTH);
1506         i_cur_part--;
1507         parse_master(p_demux);
1508     }
1509     /* maybe we need to go forward */
1510     while (l_seek_time > p_sys->l_final_ty_pts) {
1511         msg_Dbg(p_demux, "skipping to next segment.");
1512         /* load next part */
1513         if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1514             /* error; restore previous file position */
1515             stream_Seek(p_demux->s, l_cur_pos);
1516             msg_Err(p_demux, "seek error");
1517             return VLC_EGENERIC;
1518         }
1519         stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
1520         i_cur_part++;
1521         parse_master(p_demux);
1522     }
1523
1524     /* our target is somewhere within this part;
1525        find the proper chunk using seq_table */
1526     for (i=1; i<p_sys->i_seq_table_size; i++) {
1527         if (p_sys->seq_table[i].l_timestamp > l_seek_time) {
1528             /* i-1 is the section we want; remember the next timestamp in case
1529                we have to use it (this section may not have a proper SEQ hdr
1530                for the time we're seeking) */
1531             msg_Dbg(p_demux, "stopping at seq entry %d.", i);
1532             l_fwd_stamp = p_sys->seq_table[i].l_timestamp;
1533             i_seq_entry = i-1;
1534             break;
1535         }
1536     }
1537     
1538     /* if we went through the entire last loop and didn't find our target,
1539        then we skip to the next part.  What has happened is that the actual
1540        time we're seeking is within this part, but there isn't a SEQ hdr
1541        for it here.  So we skip to the next part */
1542     if (i == p_sys->i_seq_table_size) {
1543         if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1544             /* error; restore previous file position */
1545             stream_Seek(p_demux->s, l_cur_pos);
1546             msg_Err(p_demux, "seek error");
1547             return VLC_EGENERIC;
1548         }
1549         stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
1550         i_cur_part++;
1551         parse_master(p_demux);
1552         i_seq_entry = 0;
1553     }     
1554      
1555     /* determine which chunk has our seek_time */
1556     for (i=0; i<p_sys->i_bits_per_seq_entry; i++) {
1557         long l_chunk_nr = i_seq_entry * p_sys->i_bits_per_seq_entry + i;
1558         long l_chunk_offset = (l_chunk_nr + 1) * CHUNK_SIZE;
1559         msg_Dbg(p_demux, "testing part %d chunk %ld mask 0x%02X bit %d",
1560             i_cur_part, l_chunk_nr,
1561             p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8], i%8);
1562         if (p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8] & (1 << (i%8))) {
1563             /* check this chunk's SEQ header timestamp */
1564             msg_Dbg(p_demux, "has SEQ. seeking to chunk at 0x%lX",
1565                 (i_cur_part * TIVO_PART_LENGTH) + l_chunk_offset);
1566             stream_Seek(p_demux->s, (i_cur_part * TIVO_PART_LENGTH) +
1567                 l_chunk_offset);
1568             // TODO: we don't have to parse the full header set;
1569             // just test the seq_rec entry for its timestamp
1570             p_sys->i_stuff_cnt = 0;
1571             get_chunk_header(p_demux);
1572             // check ty PTS for the SEQ entry in this chunk
1573             if (p_sys->i_seq_rec < 0 || p_sys->i_seq_rec > p_sys->i_num_recs) {
1574                 msg_Err(p_demux, "no SEQ hdr in chunk; table had one.");
1575                 /* Seek to beginning of original chunk & reload it */
1576                 stream_Seek(p_demux->s, (l_cur_pos / CHUNK_SIZE) * CHUNK_SIZE);
1577                 p_sys->i_stuff_cnt = 0;
1578                 get_chunk_header(p_demux);
1579                 return VLC_EGENERIC;
1580             }
1581             l_seek_secs = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts /
1582                 1000000000;
1583             msg_Dbg(p_demux, "found SEQ hdr for timestamp %02ld:%02ld:%02ld",
1584                 l_seek_secs / 3600,
1585                 (l_seek_secs / 60) % 60, l_seek_secs % 60);
1586             if (p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts >= l_seek_time) {
1587                 // keep this one?  go back?
1588                 /* for now, we take this one.  it's the first SEQ hdr AFTER
1589                    the time we were searching for. */
1590                 msg_Dbg(p_demux, "seek target found.");
1591                 break;
1592             }
1593             msg_Dbg(p_demux, "timestamp too early. still scanning.");
1594         }
1595     }
1596     /* if we made it through this entire loop without finding our target,
1597        then we skip to the next section.  What has happened is that the actual
1598        time we're seeking is within this section, but there isn't a SEQ hdr
1599        for it here.  So we skip to the next closest one (l_fwd_stamp) */
1600     if (i == p_sys->i_bits_per_seq_entry)
1601         return ty_stream_seek_time(p_demux, l_fwd_stamp);
1602
1603     /* current stream ptr is at beginning of data for this chunk,
1604        so we need to skip past any stream data prior to the seq_rec
1605        in this chunk */
1606     i_skip_cnt = 0;
1607     for (i=0; i<p_sys->i_seq_rec; i++)
1608         i_skip_cnt += p_sys->rec_hdrs[i].l_rec_size;
1609     stream_Read(p_demux->s, NULL, i_skip_cnt);
1610     p_sys->i_cur_rec = p_sys->i_seq_rec;
1611     //p_sys->l_last_ty_pts = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts;
1612     //p_sys->l_last_ty_pts_sync = p_sys->lastAudioPTS;
1613
1614     return VLC_SUCCESS;
1615 }
1616
1617
1618 /* parse a master chunk, filling the SEQ table and other variables.
1619  * We assume the stream is currently pointing to it.
1620  */
1621 static void parse_master(demux_t *p_demux)
1622 {
1623     demux_sys_t *p_sys = p_demux->p_sys;
1624     uint8_t mst_buf[32];
1625     int i, i_map_size;
1626     int64_t i_save_pos = stream_Tell(p_demux->s);
1627     int64_t i_pts_secs;
1628
1629     /* Note that the entries in the SEQ table in the stream may have
1630        different sizes depending on the bits per entry.  We store them
1631        all in the same size structure, so we have to parse them out one
1632        by one.  If we had a dynamic structure, we could simply read the
1633        entire table directly from the stream into memory in place. */
1634
1635     /* clear the SEQ table */
1636     free(p_sys->seq_table);
1637     
1638     /* parse header info */
1639     stream_Read(p_demux->s, mst_buf, 32);
1640     i_map_size = U32_AT(&mst_buf[20]);  /* size of bitmask, in bytes */
1641     p_sys->i_bits_per_seq_entry = i_map_size * 8;
1642     i = U32_AT(&mst_buf[28]);   /* size of SEQ table, in bytes */
1643     p_sys->i_seq_table_size = i / (8 + i_map_size);
1644
1645     /* parse all the entries */
1646     p_sys->seq_table = malloc(p_sys->i_seq_table_size * sizeof(ty_seq_table_t));
1647     for (i=0; i<p_sys->i_seq_table_size; i++) {
1648         stream_Read(p_demux->s, mst_buf, 8 + i_map_size);
1649         p_sys->seq_table[i].l_timestamp = U64_AT(&mst_buf[0]);
1650         if (i_map_size > 8) {
1651             msg_Err(p_demux, "Unsupported SEQ bitmap size in master chunk");
1652             memset(p_sys->seq_table[i].chunk_bitmask, i_map_size, 0);
1653         } else {
1654             memcpy(p_sys->seq_table[i].chunk_bitmask, &mst_buf[8], i_map_size);
1655         }
1656     }
1657
1658     /* set up a few of our variables */
1659     p_sys->l_first_ty_pts = p_sys->seq_table[0].l_timestamp;
1660     p_sys->l_final_ty_pts =
1661         p_sys->seq_table[p_sys->i_seq_table_size - 1].l_timestamp;
1662     p_sys->b_have_master = true;
1663
1664     i_pts_secs = p_sys->l_first_ty_pts / 1000000000;
1665     msg_Dbg( p_demux, "first TY pts in master is %02d:%02d:%02d",
1666              (int)(i_pts_secs / 3600), (int)((i_pts_secs / 60) % 60), (int)(i_pts_secs % 60) );
1667     i_pts_secs = p_sys->l_final_ty_pts / 1000000000;
1668     msg_Dbg( p_demux, "final TY pts in master is %02d:%02d:%02d",
1669              (int)(i_pts_secs / 3600), (int)((i_pts_secs / 60) % 60), (int)(i_pts_secs % 60) );
1670
1671     /* seek past this chunk */
1672     stream_Seek(p_demux->s, i_save_pos + CHUNK_SIZE);
1673 }
1674
1675
1676 /* ======================================================================== */
1677 /* "Peek" at some chunks.  Skip over the Part header if we find it.
1678  * We parse the peeked data and determine audio type,
1679  * SA vs. DTivo, & Tivo Series.
1680  * Set global vars i_Pes_Length, i_Pts_Offset,
1681  * p_sys->tivo_series, p_sys->tivo_type, p_sys->audio_type */
1682 static int probe_stream(demux_t *p_demux)
1683 {
1684     demux_sys_t *p_sys = p_demux->p_sys;
1685     const uint8_t *p_buf;
1686     int i;
1687     bool b_probe_error = false;
1688
1689     /* we need CHUNK_PEEK_COUNT chunks of data, first one might be a Part header, so ... */
1690     if (stream_Peek( p_demux->s, &p_buf, CHUNK_PEEK_COUNT * CHUNK_SIZE ) <
1691             CHUNK_PEEK_COUNT * CHUNK_SIZE) {
1692         msg_Err(p_demux, "Can't peek %d chunks", CHUNK_PEEK_COUNT);
1693         /* TODO: if seekable, then loop reading chunks into a temp buffer */
1694         return VLC_EGENERIC;
1695     }
1696     
1697     /* the real work: analyze this chunk */
1698     for (i = 0; i < CHUNK_PEEK_COUNT; i++) {
1699         analyze_chunk(p_demux, p_buf);
1700         if (p_sys->tivo_series != TIVO_SERIES_UNKNOWN &&
1701             p_sys->audio_type  != TIVO_AUDIO_UNKNOWN &&
1702             p_sys->tivo_type   != TIVO_TYPE_UNKNOWN)
1703             break;
1704         p_buf += CHUNK_SIZE;
1705     }
1706     
1707     /* the final tally */
1708     if (p_sys->tivo_series == TIVO_SERIES_UNKNOWN) {
1709         msg_Err(p_demux, "Can't determine Tivo Series.");
1710         b_probe_error = true;
1711     }
1712     if (p_sys->audio_type == TIVO_AUDIO_UNKNOWN) {
1713         msg_Err(p_demux, "Can't determine Tivo Audio Type.");
1714         b_probe_error = true;
1715     }
1716     if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1717         msg_Err(p_demux, "Can't determine Tivo Type (SA/DTivo).");
1718         b_probe_error = true;
1719     }
1720     return b_probe_error?VLC_EGENERIC:VLC_SUCCESS;
1721 }
1722
1723
1724 /* ======================================================================== */
1725 /* gather statistics for this chunk & set our tivo-type vars accordingly */
1726 static void analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
1727 {
1728     demux_sys_t *p_sys = p_demux->p_sys;
1729     int i_num_recs, i;
1730     ty_rec_hdr_t *p_hdrs;
1731     int i_num_6e0, i_num_be0, i_num_9c0, i_num_3c0;
1732     uint32_t i_payload_size;
1733
1734     /* skip if it's a Part header */
1735     if( U32_AT( &p_chunk[ 0 ] ) == TIVO_PES_FILEID )
1736         return;
1737
1738     /* number of records in chunk (we ignore high order byte;
1739      * rarely are there > 256 chunks & we don't need that many anyway) */
1740     i_num_recs = p_chunk[0];
1741     if (i_num_recs < 5) {
1742         /* try again with the next chunk.  Sometimes there are dead ones */
1743         return;
1744     }
1745     
1746     p_chunk += 4;       /* skip past rec count & SEQ bytes */
1747     //msg_Dbg(p_demux, "probe: chunk has %d recs", i_num_recs);
1748     p_hdrs = parse_chunk_headers(p_demux, p_chunk, i_num_recs, &i_payload_size);
1749     /* scan headers.
1750      * 1. check video packets.  Presence of 0x6e0 means S1.
1751      *    No 6e0 but have be0 means S2.
1752      * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg)
1753      *    If AC-3, then we have DTivo.
1754      *    If MPEG, search for PTS offset.  This will determine SA vs. DTivo.
1755      */
1756     i_num_6e0 = i_num_be0 = i_num_9c0 = i_num_3c0 = 0;
1757     for (i=0; i<i_num_recs; i++) {
1758         //msg_Dbg(p_demux, "probe: rec is %d/%d = 0x%04x", p_hdrs[i].subrec_type,
1759             //p_hdrs[i].rec_type,
1760             //p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type);
1761         switch (p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type) {
1762             case 0x6e0:
1763                 i_num_6e0++;
1764                 break;
1765             case 0xbe0:
1766                 i_num_be0++;
1767                 break;
1768             case 0x3c0:
1769                 i_num_3c0++;
1770                 break;
1771             case 0x9c0:
1772                 i_num_9c0++;
1773                 break;
1774         }
1775     }
1776     msg_Dbg(p_demux, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.",
1777         i_num_6e0, i_num_be0);
1778
1779     /* set up our variables */
1780     if (i_num_6e0 > 0) {
1781         msg_Dbg(p_demux, "detected Series 1 Tivo");
1782         p_sys->tivo_series = TIVO_SERIES1;
1783         p_sys->i_Pes_Length = SERIES1_PES_LENGTH;
1784     } else if (i_num_be0 > 0) {
1785         msg_Dbg(p_demux, "detected Series 2 Tivo");
1786         p_sys->tivo_series = TIVO_SERIES2;
1787         p_sys->i_Pes_Length = SERIES2_PES_LENGTH;
1788     }
1789     if (i_num_9c0 > 0) {
1790         msg_Dbg(p_demux, "detected AC-3 Audio (DTivo)" );
1791         p_sys->audio_type = TIVO_AUDIO_AC3;
1792         p_sys->tivo_type = TIVO_TYPE_DTIVO;
1793         p_sys->i_Pts_Offset = AC3_PTS_OFFSET;
1794         p_sys->i_Pes_Length = AC3_PES_LENGTH;
1795     } else if (i_num_3c0 > 0) {
1796         p_sys->audio_type = TIVO_AUDIO_MPEG;
1797         msg_Dbg(p_demux, "detected MPEG Audio" );
1798     }
1799
1800     /* if tivo_type still unknown, we can check PTS location
1801      * in MPEG packets to determine tivo_type */
1802     if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1803         uint32_t i_data_offset = (16 * i_num_recs);
1804         for (i=0; i<i_num_recs; i++) {
1805             if ((p_hdrs[i].subrec_type << 0x08 | p_hdrs[i].rec_type) == 0x3c0 &&
1806                     p_hdrs[i].l_rec_size > 15) {
1807                 /* first make sure we're aligned */
1808                 int i_pes_offset = find_es_header(ty_MPEGAudioPacket,
1809                         &p_chunk[i_data_offset], 5);
1810                 if (i_pes_offset >= 0) {
1811                     /* pes found. on SA, PES has hdr data at offset 6, not PTS. */
1812                     //msg_Dbg(p_demux, "probe: mpeg es header found in rec %d at offset %d",
1813                             //i, i_pes_offset);
1814                     if ((p_chunk[i_data_offset + 6 + i_pes_offset] & 0x80) == 0x80) {
1815                         /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */
1816                         if (p_sys->tivo_series == TIVO_SERIES1)
1817                             msg_Dbg(p_demux, "detected Stand-Alone Tivo" );
1818                         p_sys->tivo_type = TIVO_TYPE_SA;
1819                         p_sys->i_Pts_Offset = SA_PTS_OFFSET;
1820                     } else {
1821                         if (p_sys->tivo_series == TIVO_SERIES1)
1822                             msg_Dbg(p_demux, "detected DirecTV Tivo" );
1823                         p_sys->tivo_type = TIVO_TYPE_DTIVO;
1824                         p_sys->i_Pts_Offset = DTIVO_PTS_OFFSET;
1825                     }
1826                     break;
1827                 }
1828             }
1829             i_data_offset += p_hdrs[i].l_rec_size;
1830         }
1831     }
1832     free(p_hdrs);
1833 }
1834
1835
1836 /* =========================================================================== */
1837 static int get_chunk_header(demux_t *p_demux)
1838 {
1839     int i_readSize, i_num_recs;
1840     uint8_t *p_hdr_buf;
1841     const uint8_t *p_peek;
1842     demux_sys_t *p_sys = p_demux->p_sys;
1843     int i_payload_size;             /* sum of all records' sizes */
1844
1845     msg_Dbg(p_demux, "parsing ty chunk #%d", p_sys->i_cur_chunk );
1846
1847     /* if we have left-over filler space from the last chunk, get that */
1848     if (p_sys->i_stuff_cnt > 0) {
1849         stream_Read( p_demux->s, NULL, p_sys->i_stuff_cnt);
1850         p_sys->i_stuff_cnt = 0;
1851     }
1852
1853     /* read the TY packet header */
1854     i_readSize = stream_Peek( p_demux->s, &p_peek, 4 );
1855     p_sys->i_cur_chunk++;
1856   
1857     if ( (i_readSize < 4) || ( U32_AT(&p_peek[ 0 ] ) == 0 ))
1858     {
1859         /* EOF */
1860         p_sys->eof = 1;
1861         return 0;
1862     }
1863   
1864     /* check if it's a PART Header */
1865     if( U32_AT( &p_peek[ 0 ] ) == TIVO_PES_FILEID )
1866     {
1867         /* parse master chunk */
1868         parse_master(p_demux);
1869         return get_chunk_header(p_demux);
1870     }
1871     
1872     /* number of records in chunk (8- or 16-bit number) */
1873     if (p_peek[3] & 0x80)
1874     {
1875         /* 16 bit rec cnt */
1876         p_sys->i_num_recs = i_num_recs = (p_peek[1] << 8) + p_peek[0];
1877         p_sys->i_seq_rec = (p_peek[3] << 8) + p_peek[2];
1878         if (p_sys->i_seq_rec != 0xffff)
1879         {
1880             p_sys->i_seq_rec &= ~0x8000;
1881         }
1882     }
1883     else
1884     {
1885         /* 8 bit reclen - tivo 1.3 format */
1886         p_sys->i_num_recs = i_num_recs = p_peek[0];
1887         p_sys->i_seq_rec = p_peek[1];
1888     }
1889     p_sys->i_cur_rec = 0;
1890     p_sys->b_first_chunk = false;
1891   
1892     /*msg_Dbg( p_demux, "chunk has %d records", i_num_recs );*/
1893
1894     free(p_sys->rec_hdrs);
1895
1896     /* skip past the 4 bytes we "peeked" earlier */
1897     stream_Read( p_demux->s, NULL, 4 );
1898
1899     /* read the record headers into a temp buffer */
1900     p_hdr_buf = malloc(i_num_recs * 16);
1901     if (stream_Read(p_demux->s, p_hdr_buf, i_num_recs * 16) < i_num_recs * 16) {
1902         free( p_hdr_buf );
1903         p_sys->eof = true;
1904         return 0;
1905     }
1906     /* parse them */
1907     p_sys->rec_hdrs = parse_chunk_headers(p_demux, p_hdr_buf, i_num_recs,
1908             &i_payload_size);
1909     free(p_hdr_buf);
1910
1911     p_sys->i_stuff_cnt = CHUNK_SIZE - 4 -
1912         (p_sys->i_num_recs * 16) - i_payload_size;
1913     if (p_sys->i_stuff_cnt > 0)
1914         msg_Dbg( p_demux, "chunk has %d stuff bytes at end",
1915                  p_sys->i_stuff_cnt );
1916     return 1;
1917 }
1918
1919
1920 static ty_rec_hdr_t *parse_chunk_headers( demux_t *p_demux, const uint8_t *p_buf,
1921                                           int i_num_recs, int *pi_payload_size)
1922 {
1923     int i;
1924     ty_rec_hdr_t *p_hdrs, *p_rec_hdr;
1925
1926     *pi_payload_size = 0;
1927     p_hdrs = malloc(i_num_recs * sizeof(ty_rec_hdr_t));
1928
1929     for (i = 0; i < i_num_recs; i++)
1930     {
1931         const uint8_t *record_header = p_buf + (i * 16);
1932         p_rec_hdr = &p_hdrs[i];     /* for brevity */
1933         p_rec_hdr->rec_type = record_header[3];
1934         p_rec_hdr->subrec_type = record_header[2] & 0x0f;
1935         if ((record_header[ 0 ] & 0x80) == 0x80)
1936         {
1937             uint8_t b1, b2;
1938             /* marker bit 2 set, so read extended data */
1939             b1 = ( ( ( record_header[ 0 ] & 0x0f ) << 4 ) | 
1940                    ( ( record_header[ 1 ] & 0xf0 ) >> 4 ) );
1941             b1 &= 0x7f;
1942             b2 = ( ( ( record_header[ 1 ] & 0x0f ) << 4 ) | 
1943                    ( ( record_header[ 2 ] & 0xf0 ) >> 4 ) );
1944             b2 &= 0x7f;
1945
1946             p_rec_hdr->ex1 = b1;
1947             p_rec_hdr->ex2 = b2;
1948             p_rec_hdr->l_rec_size = 0;
1949             p_rec_hdr->l_ty_pts = 0;
1950             p_rec_hdr->b_ext = true;
1951         }
1952         else
1953         {
1954             p_rec_hdr->l_rec_size = ( record_header[ 0 ] << 8 |
1955                 record_header[ 1 ] ) << 4 | ( record_header[ 2 ] >> 4 );
1956             *pi_payload_size += p_rec_hdr->l_rec_size;
1957             p_rec_hdr->b_ext = false;
1958             p_rec_hdr->l_ty_pts = U64_AT( &record_header[ 8 ] );
1959         }
1960         //fprintf( stderr, "parse_chunk_headers[%d] t=0x%x s=%d\n", i, p_rec_hdr->rec_type, p_rec_hdr->subrec_type );
1961     } /* end of record-header loop */
1962     return p_hdrs;
1963 }