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