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