]> git.sesse.net Git - vlc/blob - modules/demux/ty.c
Added closed captions decoding for tivo files.
[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 #include <vlc/vlc.h>
39 #include <vlc_demux.h>
40 #include "vlc_codec.h"
41 #include "../codec/cc.h"
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 static int  Open ( vlc_object_t * );
47 static void Close( vlc_object_t * );
48
49 vlc_module_begin();
50     set_shortname( _("TY") );
51     set_description(_("TY Stream audio/video demux"));
52     set_category( CAT_INPUT );
53     set_subcategory( SUBCAT_INPUT_DEMUX );
54     set_capability("demux2", 6);
55     /* FIXME: there seems to be a segfault when using PVR access
56      * and TY demux has a bigger priority than PS
57      * Something must be wrong.
58      */
59     set_callbacks( Open, Close );
60     add_shortcut("ty");
61     add_shortcut("tivo");
62 vlc_module_end();
63
64 /*****************************************************************************
65  * Local prototypes
66  *****************************************************************************/
67 static int Demux  ( demux_t * );
68 static int Control( demux_t *, int, va_list );
69
70 #define SERIES1_PES_LENGTH  (11)    /* length of audio PES hdr on S1 */
71 #define SERIES2_PES_LENGTH  (16)    /* length of audio PES hdr on S2 */
72 #define AC3_PES_LENGTH      (14)    /* length of audio PES hdr for AC3 */
73 #define VIDEO_PES_LENGTH    (16)    /* length of video PES header */
74 #define DTIVO_PTS_OFFSET    (6)     /* offs into PES for MPEG PTS on DTivo */
75 #define SA_PTS_OFFSET       (9)     /* offset into PES for MPEG PTS on SA */
76 #define AC3_PTS_OFFSET      (9)     /* offset into PES for AC3 PTS on DTivo */
77 #define VIDEO_PTS_OFFSET    (9)     /* offset into PES for video PTS on all */
78 #define AC3_PKT_LENGTH      (1536)  /* size of TiVo AC3 pkts (w/o PES hdr) */
79 static const uint8_t ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 };
80 static const uint8_t ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 };
81 static const uint8_t ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd };
82
83 #define CHUNK_PEEK_COUNT    (3)         /* number of chunks to probe */
84
85 /* packet types for reference:
86  2/c0: audio data continued
87  3/c0: audio packet header (PES header)
88  4/c0: audio data (S/A only?)
89  9/c0: audio packet header, AC-3 audio
90  2/e0: video data continued
91  6/e0: video packet header (PES header)
92  7/e0: video sequence header start
93  8/e0: video I-frame header start
94  a/e0: video P-frame header start
95  b/e0: video B-frame header start
96  c/e0: video GOP header start
97  e/01: closed-caption data
98  e/02: Extended data services data 
99  e/03: ipreview data ("thumbs up to record" signal)
100  e/05: UK Teletext
101 */
102
103 #define TIVO_PES_FILEID   ( 0xf5467abd )
104 #define TIVO_PART_LENGTH  ( 0x20000000 )    /* 536,870,912 bytes */
105 #define CHUNK_SIZE        ( 128 * 1024 )
106
107 typedef struct
108 {
109   long l_rec_size;
110   uint8_t ex1, ex2;
111   uint8_t rec_type;
112   uint8_t subrec_type;
113   vlc_bool_t b_ext;
114   uint64_t l_ty_pts;            /* TY PTS in the record header */
115 } ty_rec_hdr_t;
116
117 typedef struct
118 {
119     uint64_t l_timestamp;
120     uint8_t chunk_bitmask[8];
121 } ty_seq_table_t;
122
123 typedef enum
124 {
125     TIVO_TYPE_UNKNOWN,
126     TIVO_TYPE_SA,
127     TIVO_TYPE_DTIVO
128 } tivo_type_t;
129
130 typedef enum
131 {
132     TIVO_SERIES_UNKNOWN,
133     TIVO_SERIES1,
134     TIVO_SERIES2
135 } tivo_series_t;
136
137 typedef enum
138 {
139     TIVO_AUDIO_UNKNOWN,
140     TIVO_AUDIO_AC3,
141     TIVO_AUDIO_MPEG
142 } tivo_audio_t;
143
144 struct demux_sys_t
145 {
146   es_out_id_t *p_video;               /* ptr to video codec */
147   es_out_id_t *p_audio;               /* holds either ac3 or mpeg codec ptr */
148
149   cc_data_t   cc;
150   es_out_id_t *p_cc[4];
151
152   int             i_cur_chunk;
153   int             i_stuff_cnt;
154   size_t          i_stream_size;      /* size of input stream (if known) */
155   //uint64_t        l_program_len;      /* length of this stream in msec */
156   vlc_bool_t      b_seekable;         /* is this stream seekable? */
157   vlc_bool_t      b_have_master;      /* are master chunks present? */
158   tivo_type_t     tivo_type;          /* tivo type (SA / DTiVo) */
159   tivo_series_t   tivo_series;        /* Series1 or Series2 */
160   tivo_audio_t    audio_type;         /* AC3 or MPEG */
161   int             i_Pes_Length;       /* Length of Audio PES header */
162   int             i_Pts_Offset;       /* offset into audio PES of PTS */
163   uint8_t         pes_buffer[20];     /* holds incomplete pes headers */
164   int             i_pes_buf_cnt;      /* how many bytes in our buffer */
165   size_t          l_ac3_pkt_size;     /* len of ac3 pkt we've seen so far */
166   uint64_t        l_last_ty_pts;      /* last TY timestamp we've seen */
167   //mtime_t         l_last_ty_pts_sync; /* audio PTS at time of last TY PTS */
168   uint64_t        l_first_ty_pts;     /* first TY PTS in this master chunk */
169   uint64_t        l_final_ty_pts;     /* final TY PTS in this master chunk */
170   int             i_seq_table_size;   /* number of entries in SEQ table */
171   int             i_bits_per_seq_entry; /* # of bits in SEQ table bitmask */
172
173   mtime_t         firstAudioPTS;
174   mtime_t         lastAudioPTS;
175   mtime_t         lastVideoPTS;
176
177   ty_rec_hdr_t    *rec_hdrs;          /* record headers array */
178   int             i_cur_rec;          /* current record in this chunk */
179   int             i_num_recs;         /* number of recs in this chunk */
180   int             i_seq_rec;          /* record number where seq start is */
181   ty_seq_table_t  *seq_table;         /* table of SEQ entries from mstr chk */
182   vlc_bool_t      eof;
183   vlc_bool_t      b_first_chunk;
184 };
185
186 static int get_chunk_header(demux_t *);
187 static mtime_t get_pts( const uint8_t *buf );
188 static int find_es_header( const uint8_t *header,
189                            const uint8_t *buffer, int i_search_len );
190 static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct);
191 static int ty_stream_seek_time(demux_t *, uint64_t);
192
193 static ty_rec_hdr_t *parse_chunk_headers( demux_t *p_demux, const uint8_t *p_buf,
194                                           int i_num_recs, int *pi_payload_size);
195 static int probe_stream(demux_t *p_demux);
196 static void analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk);
197 static void parse_master(demux_t *p_demux);
198
199 static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
200 static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
201 static int DemuxRecCc( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
202
203 static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 );
204
205 /*
206  * Open: check file and initialize demux structures
207  *
208  * here's what we do:
209  * 1. peek at the first 12 bytes of the stream for the
210  *    magic TiVo PART header & stream type & chunk size
211  * 2. if it's not there, error with VLC_EGENERIC
212  * 3. set up video (mpgv) codec
213  * 4. return VLC_SUCCESS
214  */
215 static int Open(vlc_object_t *p_this)
216 {
217     demux_t *p_demux = (demux_t *)p_this;
218     demux_sys_t *p_sys;
219     es_format_t fmt;
220     const uint8_t *p_peek;
221     int i;
222
223     /* peek at the first 12 bytes. */
224     /* for TY streams, they're always the same */
225     if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
226         return VLC_EGENERIC;
227
228     if ( U32_AT(p_peek) != TIVO_PES_FILEID ||
229          U32_AT(&p_peek[4]) != 0x02 ||
230          U32_AT(&p_peek[8]) != CHUNK_SIZE )
231     {
232         if( !p_demux->b_force &&
233             !demux2_IsPathExtension( p_demux, ".ty" ) &&
234             !demux2_IsPathExtension( p_demux, ".ty+" ) )
235             return VLC_EGENERIC;
236         msg_Warn( p_demux, "this does not look like a TY file, "
237                            "continuing anyway..." );
238     }
239
240         /* at this point, we assume we have a valid TY stream */  
241     msg_Dbg( p_demux, "valid TY stream detected" );
242
243     /* Set exported functions */
244     p_demux->pf_demux = Demux;
245     p_demux->pf_control = Control;
246
247     /* create our structure that will hold all data */
248     p_demux->p_sys = p_sys = malloc(sizeof(demux_sys_t));
249     memset(p_sys, 0, sizeof(demux_sys_t));
250
251     /* set up our struct (most were zero'd out with the memset above) */
252     p_sys->b_first_chunk = VLC_TRUE;
253     p_sys->b_have_master = (U32_AT(p_peek) == TIVO_PES_FILEID);
254     p_sys->firstAudioPTS = -1;
255     p_sys->i_stream_size = stream_Size(p_demux->s);
256     p_sys->tivo_type = TIVO_TYPE_UNKNOWN;
257     p_sys->audio_type = TIVO_AUDIO_UNKNOWN;
258     p_sys->tivo_series = TIVO_SERIES_UNKNOWN;
259     p_sys->i_Pes_Length = 0;
260     p_sys->i_Pts_Offset = 0;
261     p_sys->l_ac3_pkt_size = 0;
262   
263     /* see if this stream is seekable */
264     stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
265
266     if (probe_stream(p_demux) != VLC_SUCCESS) {
267         //TyClose(p_demux);
268         return VLC_EGENERIC;
269     }
270
271     if (!p_sys->b_have_master)
272       msg_Warn(p_demux, "No master chunk found; seeking will be limited.");
273
274     /* register the proper audio codec */
275     if (p_sys->audio_type == TIVO_AUDIO_MPEG) {
276         es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
277     } else {
278         es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', ' ' ) );
279     }
280     p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
281
282     /* register the video stream */
283     es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', 'g', 'v' ) );
284     p_sys->p_video = es_out_Add( p_demux->out, &fmt );
285
286     /* */
287     for( i = 0; i < 4; i++ )
288         p_sys->p_cc[i] = NULL;
289     cc_Init( &p_sys->cc );
290
291     return VLC_SUCCESS;
292 }
293
294 /* =========================================================================== */
295 /* Demux: Read & Demux one record from the chunk
296  *
297  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
298  *
299  * NOTE: I think we can return the number of packets sent instead of just 1.
300  * that means we can demux an entire chunk and shoot it back (may be more efficient)
301  * -- should try that some day :) --
302  */
303 static int Demux( demux_t *p_demux )
304 {
305     demux_sys_t  *p_sys = p_demux->p_sys;
306     ty_rec_hdr_t *p_rec;
307     block_t      *p_block_in = NULL;
308
309     /*msg_Dbg(p_demux, "ty demux processing" );*/
310    
311     /* did we hit EOF earlier? */
312     if( p_sys->eof )
313         return 0;
314
315     /*
316      * what we do (1 record now.. maybe more later):
317     * - use stream_Read() to read the chunk header & record headers
318     * - discard entire chunk if it is a PART header chunk
319     * - parse all the headers into record header array
320     * - keep a pointer of which record we're on
321     * - use stream_Block() to fetch each record
322     * - parse out PTS from PES headers
323     * - set PTS for data packets
324     * - pass the data on to the proper codec via es_out_Send()
325
326     * if this is the first time or  
327     * if we're at the end of this chunk, start a new one
328     */
329     /* parse the next chunk's record headers */
330     if( p_sys->b_first_chunk || p_sys->i_cur_rec >= p_sys->i_num_recs )
331     {
332         if( get_chunk_header(p_demux) == 0 )
333             return 0;
334     }
335
336     /*======================================================================
337      * parse & send one record of the chunk
338      *====================================================================== */
339     p_rec = &p_sys->rec_hdrs[p_sys->i_cur_rec];
340
341     if( !p_rec->b_ext )
342     {
343         const long l_rec_size = p_rec->l_rec_size;
344         /*msg_Dbg(p_demux, "Record Type 0x%x/%02x %ld bytes",
345                     subrec_type, p_rec->rec_type, l_rec_size );*/
346   
347         /* some normal records are 0 length, so check for that... */
348         if( l_rec_size <= 0 )
349         {
350             /* no data in payload; we're done */
351             p_sys->i_cur_rec++;
352             return 1;
353         }
354
355         /* read in this record's payload */
356         if( !( p_block_in = stream_Block( p_demux->s, l_rec_size ) ) )
357             return 0;
358
359         /* set these as 'unknown' for now */
360         p_block_in->i_pts =
361         p_block_in->i_dts = 0;
362     }
363     /*else
364     {
365         -- don't read any data from the stream, data was in the record header --
366         msg_Dbg(p_demux,
367                "Record Type 0x%02x/%02x, ext data = %02x, %02x", subrec_type,
368                 p_rec->rec_type, p_rec->ex1, p_rec->ex2);
369     }*/
370
371     if( p_rec->rec_type == 0xe0 )
372     {
373         /* Video */
374         DemuxRecVideo( p_demux, p_rec, p_block_in );
375     }
376     else if ( p_rec->rec_type == 0xc0 )
377     {
378         /* Audio */
379         DemuxRecAudio( p_demux, p_rec, p_block_in );
380     }
381     else if( p_rec->rec_type == 0x01 || p_rec->rec_type == 0x02 )
382     {
383         /* Closed Captions/XDS */
384         DemuxRecCc( p_demux, p_rec, p_block_in );
385     }
386     else if ( p_rec->rec_type == 0x03 )
387     {
388         /* Tivo data services (e.g. "thumbs-up to record!")  useless for us */
389         if( p_block_in )
390             block_Release(p_block_in);
391     }
392     else if ( p_rec->rec_type == 0x05 )
393     {
394         /* Unknown, but seen regularly */
395         if( p_block_in )
396             block_Release(p_block_in);
397     }
398     else
399     {
400         msg_Dbg(p_demux, "Invalid record type 0x%02x", p_rec->rec_type );
401         if( p_block_in )
402             block_Release(p_block_in);
403     }
404
405     /* */
406     p_sys->i_cur_rec++;
407     return 1;
408 }
409
410 /* Control */
411 static int Control(demux_t *p_demux, int i_query, va_list args)
412 {
413     demux_sys_t *p_sys = p_demux->p_sys;
414     double f, *pf;
415     int64_t i64, *p_i64;
416
417     /*msg_Info(p_demux, "control cmd %d", i_query);*/
418     switch( i_query )
419     {
420     case DEMUX_GET_POSITION:
421         /* arg is 0.0 - 1.0 percent of overall file position */
422         if( ( i64 = p_sys->i_stream_size ) > 0 )
423         {
424             pf = (double*) va_arg( args, double* );
425             *pf = (double)stream_Tell( p_demux->s ) / (double) i64;
426             return VLC_SUCCESS;
427         }
428         return VLC_EGENERIC;
429
430     case DEMUX_SET_POSITION:
431         /* arg is 0.0 - 1.0 percent of overall file position */
432         f = (double) va_arg( args, double );
433         /* msg_Dbg(p_demux, "Control - set position to %2.3f", f); */
434         if ((i64 = p_sys->i_stream_size) > 0)
435             return ty_stream_seek_pct(p_demux, f);
436         return VLC_EGENERIC;
437     case DEMUX_GET_TIME:
438         /* return TiVo timestamp */
439         p_i64 = (int64_t *) va_arg(args, int64_t *);
440         //*p_i64 = p_sys->lastAudioPTS - p_sys->firstAudioPTS;
441         //*p_i64 = (p_sys->l_last_ty_pts / 1000) + (p_sys->lastAudioPTS -
442         //    p_sys->l_last_ty_pts_sync);
443         *p_i64 = (p_sys->l_last_ty_pts / 1000);
444         return VLC_SUCCESS;
445     case DEMUX_GET_LENGTH:    /* length of program in microseconds, 0 if unk */
446         /* size / bitrate */
447         p_i64 = (int64_t *) va_arg(args, int64_t *);
448         *p_i64 = 0;
449         return VLC_SUCCESS;
450     case DEMUX_SET_TIME:      /* arg is time in microsecs */
451         i64 = (int64_t) va_arg( args, int64_t );
452         return ty_stream_seek_time(p_demux, i64 * 1000);
453     case DEMUX_GET_FPS:
454     default:
455         return VLC_EGENERIC;
456     }
457 }
458
459 /* Close */
460 static void Close( vlc_object_t *p_this )
461 {
462     demux_t *p_demux = (demux_t*)p_this;
463     demux_sys_t *p_sys = p_demux->p_sys;
464
465     cc_Exit( &p_sys->cc );
466     free( p_sys->rec_hdrs );
467     if( p_sys->seq_table )
468         free( p_sys->seq_table );
469     free(p_sys);
470 }
471
472
473 /* =========================================================================== */
474 /* Compute Presentation Time Stamp (PTS)
475  * Assume buf points to beginning of PTS */
476 static mtime_t get_pts( const uint8_t *buf )
477 {
478     mtime_t i_pts;
479
480     i_pts = ((mtime_t)(buf[0]&0x0e ) << 29)|
481              (mtime_t)(buf[1] << 22)|
482             ((mtime_t)(buf[2]&0xfe) << 14)|
483              (mtime_t)(buf[3] << 7)|
484              (mtime_t)(buf[4] >> 1);
485     i_pts *= 100 / 9;   /* convert PTS (90Khz clock) to microseconds */
486     return i_pts;
487 }
488
489
490 /* =========================================================================== */
491 static int find_es_header( const uint8_t *header,
492                            const uint8_t *buffer, int i_search_len )
493 {
494     int count;
495
496     for( count = 0; count < i_search_len; count++ )
497     {
498         if( !memcmp( &buffer[count], header, 4 ) )
499             return count;
500     }
501     return -1;
502 }
503
504
505 /* =========================================================================== */
506 /* check if we have a full PES header, if not, then save what we have.
507  * this is called when audio-start packets are encountered.
508  * Returns:
509  *     1 partial PES hdr found, some audio data found (buffer adjusted),
510  *    -1 partial PES hdr found, no audio data found
511  *     0 otherwise (complete PES found, pts extracted, pts set, buffer adjusted) */
512 /* TODO: HD support -- nothing known about those streams */
513 static int check_sync_pes( demux_t *p_demux, block_t *p_block,
514                            int32_t offset, int32_t rec_len )
515 {
516     demux_sys_t *p_sys = p_demux->p_sys;
517
518     if ( offset < 0 || offset + p_sys->i_Pes_Length > rec_len )
519     {
520         /* entire PES header not present */
521         msg_Dbg( p_demux, "PES header at %d not complete in record. storing.",
522                  offset );
523         /* save the partial pes header */
524         if( offset < 0 )
525         {
526             /* no header found, fake some 00's (this works, believe me) */
527             memset( p_sys->pes_buffer, 4, 0 );
528             p_sys->i_pes_buf_cnt = 4;
529             if( rec_len > 4 )
530                 msg_Err( p_demux, "PES header not found in record of %d bytes!",
531                          rec_len );
532             return -1;
533         }
534         /* copy the partial pes header we found */
535         memcpy( p_sys->pes_buffer, p_block->p_buffer + offset,
536                 rec_len - offset );
537         p_sys->i_pes_buf_cnt = rec_len - offset;
538
539         if( offset > 0 )
540         {
541             /* PES Header was found, but not complete, so trim the end of this record */
542             p_block->i_buffer -= rec_len - offset;
543             return 1;
544         }
545         return -1;    /* partial PES, no audio data */
546     }
547     /* full PES header present, extract PTS */
548     p_sys->lastAudioPTS = get_pts( &p_block->p_buffer[ offset +
549             p_sys->i_Pts_Offset ] );
550     if (p_sys->firstAudioPTS < 0)
551         p_sys->firstAudioPTS = p_sys->lastAudioPTS;
552     p_block->i_pts = p_sys->lastAudioPTS;
553     /*msg_Dbg(p_demux, "Audio PTS %lld", p_sys->lastAudioPTS );*/
554     /* adjust audio record to remove PES header */
555     memmove(p_block->p_buffer + offset, p_block->p_buffer + offset +
556             p_sys->i_Pes_Length, rec_len - p_sys->i_Pes_Length);
557     p_block->i_buffer -= p_sys->i_Pes_Length;
558 #if 0
559     msg_Dbg(p_demux, "pes hdr removed; buffer len=%d and has "
560              "%02x %02x %02x %02x %02x %02x %02x %02x "
561              "%02x %02x %02x %02x %02x %02x %02x %02x", p_block->i_buffer,
562              p_block->p_buffer[0], p_block->p_buffer[1],
563              p_block->p_buffer[2], p_block->p_buffer[3],
564              p_block->p_buffer[4], p_block->p_buffer[5],
565              p_block->p_buffer[6], p_block->p_buffer[7],
566              p_block->p_buffer[8], p_block->p_buffer[9],
567              p_block->p_buffer[10], p_block->p_buffer[11],
568              p_block->p_buffer[12], p_block->p_buffer[13],
569              p_block->p_buffer[14], p_block->p_buffer[15]);
570 #endif
571     return 0;
572 }
573
574 static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
575 {
576     demux_sys_t *p_sys = p_demux->p_sys;
577     const int subrec_type = rec_hdr->subrec_type;
578     const long l_rec_size = rec_hdr->l_rec_size;    // p_block_in->i_buffer might be better
579     int esOffset1;
580     int i;
581
582     assert( rec_hdr->rec_type == 0xe0 );
583     if( !p_block_in )
584         return -1;
585
586 #if 0
587     msg_Dbg(p_demux, "packet buffer has "
588             "%02x %02x %02x %02x %02x %02x %02x %02x "
589             "%02x %02x %02x %02x %02x %02x %02x %02x",
590             p_block_in->p_buffer[0], p_block_in->p_buffer[1],
591             p_block_in->p_buffer[2], p_block_in->p_buffer[3],
592             p_block_in->p_buffer[4], p_block_in->p_buffer[5],
593             p_block_in->p_buffer[6], p_block_in->p_buffer[7],
594             p_block_in->p_buffer[8], p_block_in->p_buffer[9],
595             p_block_in->p_buffer[10], p_block_in->p_buffer[11],
596             p_block_in->p_buffer[12], p_block_in->p_buffer[13],
597             p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
598 #endif
599     //if( subrec_type == 0x06 || subrec_type == 0x07 )
600     if( subrec_type != 0x02 && subrec_type != 0x0c &&
601         subrec_type != 0x08 && l_rec_size > 4 )
602     {
603         /* get the PTS from this packet if it has one.
604          * on S1, only 0x06 has PES.  On S2, however, most all do.
605          * Do NOT Pass the PES Header to the MPEG2 codec */
606         esOffset1 = find_es_header( ty_VideoPacket, p_block_in->p_buffer, 5 );
607         if( esOffset1 != -1 )
608         {
609             //msg_Dbg(p_demux, "Video PES hdr in pkt type 0x%02x at offset %d",
610                 //subrec_type, esOffset1);
611             p_sys->lastVideoPTS = get_pts(
612                     &p_block_in->p_buffer[ esOffset1 + VIDEO_PTS_OFFSET ] );
613             /*msg_Dbg(p_demux, "Video rec %d PTS "I64Fd, p_sys->i_cur_rec,
614                         p_sys->lastVideoPTS );*/
615             if (subrec_type != 0x06) {
616                 /* if we found a PES, and it's not type 6, then we're S2 */
617                 /* The packet will have video data (& other headers) so we
618                  * chop out the PES header and send the rest */
619                 if (l_rec_size >= VIDEO_PES_LENGTH) {
620                     p_block_in->p_buffer += VIDEO_PES_LENGTH + esOffset1;
621                     p_block_in->i_buffer -= VIDEO_PES_LENGTH + esOffset1;
622                 } else {
623                     msg_Dbg(p_demux, "video rec type 0x%02x has short PES"
624                         " (%ld bytes)", subrec_type, l_rec_size);
625                     /* nuke this block; it's too short, but has PES marker */
626                     p_block_in->i_buffer = 0;
627                 }
628             }
629         }/* else
630             msg_Dbg(p_demux, "No Video PES hdr in pkt type 0x%02x",
631                 subrec_type); */
632     }
633
634     if(subrec_type == 0x06 )
635     {
636         /* type 6 (S1 DTivo) has no data, so we're done */
637         block_Release(p_block_in);
638         return 0;
639     }
640
641     /* if it's not a continue blk, then set PTS */
642     if( subrec_type != 0x02 )
643     {
644         /*msg_Dbg(p_demux, "Video rec %d type 0x%02X", p_sys->i_cur_rec,
645                    subrec_type);*/
646         /* if it's a GOP header, make sure it's legal
647          * (if we have enough data) */
648         /* Some ty files don't have this bit set
649          * and it causes problems */
650         if (subrec_type == 0x0c && l_rec_size >= 6)
651             p_block_in->p_buffer[5] |= 0x08;
652         /* store the TY PTS if there is one */
653         if (subrec_type == 0x07) {
654             p_sys->l_last_ty_pts = rec_hdr->l_ty_pts;
655             /* should we use audio or video PTS? */
656             //p_sys->l_last_ty_pts_sync = p_sys->lastAudioPTS;
657         } else {
658             /* yes I know this is a cheap hack.  It's the timestamp
659                used for display and skipping fwd/back, so it
660                doesn't have to be accurate to the millisecond.
661                I adjust it here by roughly one 1/30 sec.  Yes it
662                will be slightly off for UK streams, but it's OK.
663              */
664             p_sys->l_last_ty_pts += 35000000;
665             //p_sys->l_last_ty_pts += 33366667;
666         }
667         /* set PTS for this block before we send */
668         if (p_sys->lastVideoPTS > 0)
669         {
670             p_block_in->i_pts = p_sys->lastVideoPTS;
671             /* PTS gets used ONCE. 
672              * Any subsequent frames we get BEFORE next PES
673              * header will have their PTS computed in the codec */
674             p_sys->lastVideoPTS = 0;
675         }
676     }
677
678     /* Register the CC decoders when needed */
679     for( i = 0; i < 4; i++ )
680     {
681         static const vlc_fourcc_t fcc[4] = {
682             VLC_FOURCC('c', 'c', '1', ' '),
683             VLC_FOURCC('c', 'c', '2', ' '),
684             VLC_FOURCC('c', 'c', '3', ' '),
685             VLC_FOURCC('c', 'c', '4', ' ')
686         };
687         static const char *ppsz_description[4] = {
688             N_("Closed captions 1"),
689             N_("Closed captions 2"),
690             N_("Closed captions 3"),
691             N_("Closed captions 4"),
692         };
693
694         es_format_t fmt;
695
696         if( !p_sys->cc.pb_present[i] || p_sys->p_cc[i] )
697             continue;
698
699         es_format_Init( &fmt, SPU_ES, fcc[i] );
700         fmt.psz_description = strdup( _(ppsz_description[i]) );
701         p_sys->p_cc[i] = es_out_Add( p_demux->out, &fmt );
702         es_format_Clean( &fmt );
703
704     }
705     /* Send the CC data */
706     if( p_block_in->i_pts > 0 && p_sys->cc.i_data > 0 )
707     {
708         int i_cc_count;
709
710         block_t *p_cc = block_New( p_demux, p_sys->cc.i_data );
711         p_cc->i_flags |= BLOCK_FLAG_TYPE_I;
712         p_cc->i_pts = p_block_in->i_pts;
713         memcpy( p_cc->p_buffer, p_sys->cc.p_data, p_sys->cc.i_data );
714
715         for( i = 0, i_cc_count = 0; i < 4; i++ )
716             i_cc_count += p_sys->p_cc[i] ? 1 : 0;
717
718         for( i = 0; i < 4; i++ )
719         {
720             if( !p_sys->p_cc[i] )
721                 continue;
722             if( i_cc_count > 1 )
723                 es_out_Send( p_demux->out, p_sys->p_cc[i], block_Duplicate( p_cc ) );
724             else
725                 es_out_Send( p_demux->out, p_sys->p_cc[i], p_cc );
726         }
727         cc_Flush( &p_sys->cc );
728     }
729
730     //msg_Dbg(p_demux, "sending rec %d as video type 0x%02x",
731             //p_sys->i_cur_rec, subrec_type);
732     es_out_Send(p_demux->out, p_sys->p_video, p_block_in);
733     return 0;
734 }
735 static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
736 {
737     demux_sys_t *p_sys = p_demux->p_sys;
738     const int subrec_type = rec_hdr->subrec_type;
739     const long l_rec_size = rec_hdr->l_rec_size;
740     int esOffset1;
741
742     assert( rec_hdr->rec_type == 0xc0 );
743     if( !p_block_in )
744         return -1;
745 #if 0
746         int i;
747         printf( "Audio Packet Header " );
748         for( i = 0 ; i < 24 ; i++ )
749             printf( "%2.2x ", p_block_in->p_buffer[i] );
750         printf( "\n" );
751 #endif
752
753     if( subrec_type == 2 )
754     {
755         /* SA or DTiVo Audio Data, no PES (continued block)
756          * ================================================
757          */
758
759         /* continue PES if previous was incomplete */
760         if (p_sys->i_pes_buf_cnt > 0)
761         {
762             const int i_need = p_sys->i_Pes_Length - p_sys->i_pes_buf_cnt;
763
764             msg_Dbg(p_demux, "continuing PES header");
765             /* do we have enough data to complete? */
766             if (i_need >= l_rec_size)
767             {
768                 /* don't have complete PES hdr; save what we have and return */
769                 memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
770                         p_block_in->p_buffer, l_rec_size);
771                 p_sys->i_pes_buf_cnt += l_rec_size;
772                 /* */
773                 block_Release(p_block_in);
774                 return 0;
775             }
776
777             /* we have enough; reconstruct this p_frame with the new hdr */
778             memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
779                    p_block_in->p_buffer, i_need);
780             /* advance the block past the PES header (don't want to send it) */
781             p_block_in->p_buffer += i_need;
782             p_block_in->i_buffer -= i_need;
783             /* get the PTS out of this PES header (MPEG or AC3) */
784             if (p_sys->audio_type == TIVO_AUDIO_MPEG)
785                 esOffset1 = find_es_header(ty_MPEGAudioPacket,
786                         p_sys->pes_buffer, 5);
787             else
788                 esOffset1 = find_es_header(ty_AC3AudioPacket,
789                         p_sys->pes_buffer, 5);
790             if (esOffset1 < 0)
791             {
792                 /* god help us; something's really wrong */
793                 msg_Err(p_demux, "can't find audio PES header in packet");
794             }
795             else
796             {
797                 p_sys->lastAudioPTS = get_pts( 
798                     &p_sys->pes_buffer[ esOffset1 + p_sys->i_Pts_Offset ] );
799                 p_block_in->i_pts = p_sys->lastAudioPTS;
800             }
801             p_sys->i_pes_buf_cnt = 0;
802         }
803         /* S2 DTivo has AC3 packets with 2 padding bytes at end.  This is
804          * not allowed in the AC3 spec and will cause problems.  So here
805          * we try to trim things. */
806         /* Also, S1 DTivo has alternating short / long AC3 packets.  That
807          * is, one packet is short (incomplete) and the next packet has
808          * the first one's missing data, plus all of its own.  Strange. */
809         if (p_sys->audio_type == TIVO_AUDIO_AC3 &&
810                 p_sys->tivo_series == TIVO_SERIES2) {
811             if (p_sys->l_ac3_pkt_size + p_block_in->i_buffer >
812                     AC3_PKT_LENGTH) {
813                 p_block_in->i_buffer -= 2;
814                 p_sys->l_ac3_pkt_size = 0;
815             } else {
816                 p_sys->l_ac3_pkt_size += p_block_in->i_buffer;
817             }
818         }
819     }
820     else if( subrec_type == 0x03 )
821     {
822         /* MPEG Audio with PES Header, either SA or DTiVo   */
823         /* ================================================ */
824         esOffset1 = find_es_header( ty_MPEGAudioPacket,
825                 p_block_in->p_buffer, 5 );
826
827         /*msg_Dbg(p_demux, "buffer has %#02x %#02x %#02x %#02x",
828            p_block_in->p_buffer[0], p_block_in->p_buffer[1],
829            p_block_in->p_buffer[2], p_block_in->p_buffer[3]);
830         msg_Dbg(p_demux, "audio ES hdr at offset %d", esOffset1);*/
831
832         /* SA PES Header, No Audio Data                     */
833         /* ================================================ */
834         if ( ( esOffset1 == 0 ) && ( l_rec_size == 16 ) )
835         {
836             p_sys->lastAudioPTS = get_pts( &p_block_in->p_buffer[
837                         SA_PTS_OFFSET ] );
838             if (p_sys->firstAudioPTS < 0)
839                 p_sys->firstAudioPTS = p_sys->lastAudioPTS;
840
841             block_Release(p_block_in);
842             return 0;
843             /*msg_Dbg(p_demux, "SA Audio PTS %lld",
844                        p_sys->lastAudioPTS );*/
845         }
846         /* DTiVo Audio with PES Header                      */
847         /* ================================================ */
848
849         /* Check for complete PES */
850         if (check_sync_pes(p_demux, p_block_in, esOffset1,
851                             l_rec_size) == -1)
852         {
853             /* partial PES header found, nothing else. 
854              * we're done. */
855             block_Release(p_block_in);
856             return 0;
857         }
858 #if 0
859         msg_Dbg(p_demux, "packet buffer has "
860                  "%02x %02x %02x %02x %02x %02x %02x %02x "
861                  "%02x %02x %02x %02x %02x %02x %02x %02x",
862                  p_block_in->p_buffer[0], p_block_in->p_buffer[1],
863                  p_block_in->p_buffer[2], p_block_in->p_buffer[3],
864                  p_block_in->p_buffer[4], p_block_in->p_buffer[5],
865                  p_block_in->p_buffer[6], p_block_in->p_buffer[7],
866                  p_block_in->p_buffer[8], p_block_in->p_buffer[9],
867                  p_block_in->p_buffer[10], p_block_in->p_buffer[11],
868                  p_block_in->p_buffer[12], p_block_in->p_buffer[13],
869                  p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
870 #endif
871     }
872     else if( subrec_type == 0x04 )
873     {
874         /* SA Audio with no PES Header                      */
875         /* ================================================ */
876         /*msg_Dbg(p_demux,
877                 "Adding SA Audio Packet Size %ld", l_rec_size ); */
878
879         if (p_sys->lastAudioPTS > 0)
880             p_block_in->i_pts = p_sys->lastAudioPTS;
881     }
882     else if( subrec_type == 0x09 )
883     {
884         /* DTiVo AC3 Audio Data with PES Header             */
885         /* ================================================ */
886         esOffset1 = find_es_header( ty_AC3AudioPacket,
887                 p_block_in->p_buffer, 5 );
888
889 #if 0
890         msg_Dbg(p_demux, "buffer has "
891                  "%02x %02x %02x %02x %02x %02x %02x %02x "
892                  "%02x %02x %02x %02x %02x %02x %02x %02x",
893                  p_block_in->p_buffer[0], p_block_in->p_buffer[1],
894                  p_block_in->p_buffer[2], p_block_in->p_buffer[3],
895                  p_block_in->p_buffer[4], p_block_in->p_buffer[5],
896                  p_block_in->p_buffer[6], p_block_in->p_buffer[7],
897                  p_block_in->p_buffer[8], p_block_in->p_buffer[9],
898                  p_block_in->p_buffer[10], p_block_in->p_buffer[11],
899                  p_block_in->p_buffer[12], p_block_in->p_buffer[13],
900                  p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
901         msg_Dbg(p_demux, "audio ES AC3 hdr at offset %d", esOffset1);
902 #endif
903
904         /* Check for complete PES */
905         if (check_sync_pes(p_demux, p_block_in, esOffset1,
906                             l_rec_size) == -1)
907         {
908             /* partial PES header found, nothing else.  we're done. */
909             block_Release(p_block_in);
910             return 0;
911         }
912         /* S2 DTivo has invalid long AC3 packets */
913         if (p_sys->tivo_series == TIVO_SERIES2) {
914             if (p_block_in->i_buffer > AC3_PKT_LENGTH) {
915                 p_block_in->i_buffer -= 2;
916                 p_sys->l_ac3_pkt_size = 0;
917             } else {
918                 p_sys->l_ac3_pkt_size = p_block_in->i_buffer;
919             }
920         }
921     }
922     else
923     {
924         /* Unsupported/Unknown */
925         block_Release(p_block_in);
926         return 0;
927     }
928
929     /* set PCR before we send (if PTS found) */
930     if( p_block_in->i_pts > 0 )
931         es_out_Control( p_demux->out, ES_OUT_SET_PCR,
932                         p_block_in->i_pts );
933     /* Send data */
934     es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
935     return 0;
936 }
937
938 static int DemuxRecCc( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
939 {
940     demux_sys_t *p_sys = p_demux->p_sys;
941     int i_field;
942     int i_channel;
943
944     if( p_block_in )
945         block_Release(p_block_in);
946
947     if( rec_hdr->rec_type == 0x01 )
948         i_field = 0;
949     else if( rec_hdr->rec_type == 0x02 )
950         i_field = 1;
951     else
952         return 0;
953
954     /* XDS data (extract programs infos) transmitted on field 2 only */
955     if( i_field == 1 )
956         DemuxDecodeXds( p_demux, rec_hdr->ex1, rec_hdr->ex2 );
957
958     if( p_sys->cc.i_data + 3 > CC_MAX_DATA_SIZE )
959         return 0;
960
961     p_sys->cc.p_data[p_sys->cc.i_data+0] = i_field;
962     p_sys->cc.p_data[p_sys->cc.i_data+1] = rec_hdr->ex1;
963     p_sys->cc.p_data[p_sys->cc.i_data+2] = rec_hdr->ex2;
964     p_sys->cc.i_data += 3;
965
966     i_channel = cc_Channel( i_field, &p_sys->cc.p_data[p_sys->cc.i_data+1] );
967     if( i_channel >= 0 && i_channel < 4 )
968         p_sys->cc.pb_present[i_channel] = VLC_TRUE;
969     return 0;
970 }
971
972 /* seek to a position within the stream, if possible */
973 static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct)
974 {
975     demux_sys_t *p_sys = p_demux->p_sys;
976     int64_t seek_pos = p_sys->i_stream_size * seek_pct;
977     int i, i_cur_part;
978     long l_skip_amt;
979
980     /* if we're not seekable, there's nothing to do */
981     if (!p_sys->b_seekable)
982         return VLC_EGENERIC;
983
984     /* figure out which part & chunk we want & go there */
985     i_cur_part = seek_pos / TIVO_PART_LENGTH;
986     p_sys->i_cur_chunk = seek_pos / CHUNK_SIZE;
987     
988     /* try to read the part header (master chunk) if it's there */
989     if ( stream_Seek( p_demux->s, i_cur_part * TIVO_PART_LENGTH ))
990     {
991         /* can't seek stream */
992         return VLC_EGENERIC;
993     }
994     parse_master(p_demux);
995
996     /* now for the actual chunk */
997     if ( stream_Seek( p_demux->s, p_sys->i_cur_chunk * CHUNK_SIZE))
998     {
999         /* can't seek stream */
1000         return VLC_EGENERIC;
1001     }
1002     /* load the chunk */
1003     p_sys->i_stuff_cnt = 0;
1004     get_chunk_header(p_demux);
1005   
1006     /* seek within the chunk to get roughly to where we want */
1007     p_sys->i_cur_rec = (int)
1008       ((double) ((seek_pos % CHUNK_SIZE) / (double) (CHUNK_SIZE)) * p_sys->i_num_recs);
1009     msg_Dbg(p_demux, "Seeked to file pos " I64Fd, seek_pos);
1010     msg_Dbg(p_demux, " (chunk %d, record %d)",
1011              p_sys->i_cur_chunk - 1, p_sys->i_cur_rec);
1012
1013     /* seek to the start of this record's data.
1014      * to do that, we have to skip past all prior records */
1015     l_skip_amt = 0;
1016     for (i=0; i<p_sys->i_cur_rec; i++)
1017         l_skip_amt += p_sys->rec_hdrs[i].l_rec_size;
1018     stream_Seek(p_demux->s, ((p_sys->i_cur_chunk-1) * CHUNK_SIZE) +
1019                  (p_sys->i_num_recs * 16) + l_skip_amt + 4);
1020
1021     /* to hell with syncing any audio or video, just start reading records... :) */
1022     /*p_sys->lastAudioPTS = p_sys->lastVideoPTS = 0;*/
1023     es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
1024     return VLC_SUCCESS;
1025 }
1026
1027 static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 )
1028 {
1029     /* TODO */
1030 }
1031
1032 /* seek to an exact time position within the stream, if possible.
1033  * l_seek_time is in nanoseconds, the TIVO time standard.
1034  */
1035 static int ty_stream_seek_time(demux_t *p_demux, uint64_t l_seek_time)
1036 {
1037     demux_sys_t *p_sys = p_demux->p_sys;
1038     int i, i_seq_entry = 0;
1039     int i_skip_cnt;
1040     long l_cur_pos = stream_Tell(p_demux->s);
1041     int i_cur_part = l_cur_pos / TIVO_PART_LENGTH;
1042     long l_seek_secs = l_seek_time / 1000000000;
1043     uint64_t l_fwd_stamp = 1;
1044
1045     /* if we're not seekable, there's nothing to do */
1046     if (!p_sys->b_seekable || !p_sys->b_have_master)
1047         return VLC_EGENERIC;
1048
1049     msg_Dbg(p_demux, "Skipping to time %02ld:%02ld:%02ld",
1050             l_seek_secs / 3600, (l_seek_secs / 60) % 60, l_seek_secs % 60);
1051
1052     /* seek to the proper segment if necessary */
1053     /* first see if we need to go back */
1054     while (l_seek_time < p_sys->l_first_ty_pts) {
1055         msg_Dbg(p_demux, "skipping to prior segment.");
1056         /* load previous part */
1057         if (i_cur_part == 0) {
1058             stream_Seek(p_demux->s, l_cur_pos);
1059             msg_Err(p_demux, "Attempt to seek past BOF");
1060             return VLC_EGENERIC;
1061         }
1062         stream_Seek(p_demux->s, (i_cur_part - 1) * TIVO_PART_LENGTH);
1063         i_cur_part--;
1064         parse_master(p_demux);
1065     }
1066     /* maybe we need to go forward */
1067     while (l_seek_time > p_sys->l_final_ty_pts) {
1068         msg_Dbg(p_demux, "skipping to next segment.");
1069         /* load next part */
1070         if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1071             /* error; restore previous file position */
1072             stream_Seek(p_demux->s, l_cur_pos);
1073             msg_Err(p_demux, "seek error");
1074             return VLC_EGENERIC;
1075         }
1076         stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
1077         i_cur_part++;
1078         parse_master(p_demux);
1079     }
1080
1081     /* our target is somewhere within this part;
1082        find the proper chunk using seq_table */
1083     for (i=1; i<p_sys->i_seq_table_size; i++) {
1084         if (p_sys->seq_table[i].l_timestamp > l_seek_time) {
1085             /* i-1 is the section we want; remember the next timestamp in case
1086                we have to use it (this section may not have a proper SEQ hdr
1087                for the time we're seeking) */
1088             msg_Dbg(p_demux, "stopping at seq entry %d.", i);
1089             l_fwd_stamp = p_sys->seq_table[i].l_timestamp;
1090             i_seq_entry = i-1;
1091             break;
1092         }
1093     }
1094     
1095     /* if we went through the entire last loop and didn't find our target,
1096        then we skip to the next part.  What has happened is that the actual
1097        time we're seeking is within this part, but there isn't a SEQ hdr
1098        for it here.  So we skip to the next part */
1099     if (i == p_sys->i_seq_table_size) {
1100         if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1101             /* error; restore previous file position */
1102             stream_Seek(p_demux->s, l_cur_pos);
1103             msg_Err(p_demux, "seek error");
1104             return VLC_EGENERIC;
1105         }
1106         stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
1107         i_cur_part++;
1108         parse_master(p_demux);
1109         i_seq_entry = 0;
1110     }     
1111      
1112     /* determine which chunk has our seek_time */
1113     for (i=0; i<p_sys->i_bits_per_seq_entry; i++) {
1114         long l_chunk_nr = i_seq_entry * p_sys->i_bits_per_seq_entry + i;
1115         long l_chunk_offset = (l_chunk_nr + 1) * CHUNK_SIZE;
1116         msg_Dbg(p_demux, "testing part %d chunk %ld mask 0x%02X bit %d",
1117             i_cur_part, l_chunk_nr,
1118             p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8], i%8);
1119         if (p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8] & (1 << (i%8))) {
1120             /* check this chunk's SEQ header timestamp */
1121             msg_Dbg(p_demux, "has SEQ. seeking to chunk at 0x%lX",
1122                 (i_cur_part * TIVO_PART_LENGTH) + l_chunk_offset);
1123             stream_Seek(p_demux->s, (i_cur_part * TIVO_PART_LENGTH) +
1124                 l_chunk_offset);
1125             // TODO: we don't have to parse the full header set;
1126             // just test the seq_rec entry for its timestamp
1127             p_sys->i_stuff_cnt = 0;
1128             get_chunk_header(p_demux);
1129             // check ty PTS for the SEQ entry in this chunk
1130             if (p_sys->i_seq_rec < 0 || p_sys->i_seq_rec > p_sys->i_num_recs) {
1131                 msg_Err(p_demux, "no SEQ hdr in chunk; table had one.");
1132                 /* Seek to beginning of original chunk & reload it */
1133                 stream_Seek(p_demux->s, (l_cur_pos / CHUNK_SIZE) * CHUNK_SIZE);
1134                 p_sys->i_stuff_cnt = 0;
1135                 get_chunk_header(p_demux);
1136                 return VLC_EGENERIC;
1137             }
1138             l_seek_secs = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts /
1139                 1000000000;
1140             msg_Dbg(p_demux, "found SEQ hdr for timestamp %02ld:%02ld:%02ld",
1141                 l_seek_secs / 3600,
1142                 (l_seek_secs / 60) % 60, l_seek_secs % 60);
1143             if (p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts >= l_seek_time) {
1144                 // keep this one?  go back?
1145                 /* for now, we take this one.  it's the first SEQ hdr AFTER
1146                    the time we were searching for. */
1147                 msg_Dbg(p_demux, "seek target found.");
1148                 break;
1149             }
1150             msg_Dbg(p_demux, "timestamp too early. still scanning.");
1151         }
1152     }
1153     /* if we made it through this entire loop without finding our target,
1154        then we skip to the next section.  What has happened is that the actual
1155        time we're seeking is within this section, but there isn't a SEQ hdr
1156        for it here.  So we skip to the next closest one (l_fwd_stamp) */
1157     if (i == p_sys->i_bits_per_seq_entry)
1158         return ty_stream_seek_time(p_demux, l_fwd_stamp);
1159
1160     /* current stream ptr is at beginning of data for this chunk,
1161        so we need to skip past any stream data prior to the seq_rec
1162        in this chunk */
1163     i_skip_cnt = 0;
1164     for (i=0; i<p_sys->i_seq_rec; i++)
1165         i_skip_cnt += p_sys->rec_hdrs[i].l_rec_size;
1166     stream_Read(p_demux->s, NULL, i_skip_cnt);
1167     p_sys->i_cur_rec = p_sys->i_seq_rec;
1168     //p_sys->l_last_ty_pts = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts;
1169     //p_sys->l_last_ty_pts_sync = p_sys->lastAudioPTS;
1170
1171     return VLC_SUCCESS;
1172 }
1173
1174
1175 /* parse a master chunk, filling the SEQ table and other variables.
1176  * We assume the stream is currently pointing to it.
1177  */
1178 static void parse_master(demux_t *p_demux)
1179 {
1180     demux_sys_t *p_sys = p_demux->p_sys;
1181     uint8_t mst_buf[32];
1182     int i, i_map_size;
1183     int64_t i_save_pos = stream_Tell(p_demux->s);
1184     int64_t i_pts_secs;
1185
1186     /* Note that the entries in the SEQ table in the stream may have
1187        different sizes depending on the bits per entry.  We store them
1188        all in the same size structure, so we have to parse them out one
1189        by one.  If we had a dynamic structure, we could simply read the
1190        entire table directly from the stream into memory in place. */
1191
1192     /* clear the SEQ table */
1193     if (p_sys->seq_table != NULL)
1194         free(p_sys->seq_table);
1195     
1196     /* parse header info */
1197     stream_Read(p_demux->s, mst_buf, 32);
1198     i_map_size = U32_AT(&mst_buf[20]);  /* size of bitmask, in bytes */
1199     p_sys->i_bits_per_seq_entry = i_map_size * 8;
1200     i = U32_AT(&mst_buf[28]);   /* size of SEQ table, in bytes */
1201     p_sys->i_seq_table_size = i / (8 + i_map_size);
1202
1203     /* parse all the entries */
1204     p_sys->seq_table = malloc(p_sys->i_seq_table_size * sizeof(ty_seq_table_t));
1205     for (i=0; i<p_sys->i_seq_table_size; i++) {
1206         stream_Read(p_demux->s, mst_buf, 8 + i_map_size);
1207         p_sys->seq_table[i].l_timestamp = U64_AT(&mst_buf[0]);
1208         if (i_map_size > 8) {
1209             msg_Err(p_demux, "Unsupported SEQ bitmap size in master chunk");
1210             memset(p_sys->seq_table[i].chunk_bitmask, i_map_size, 0);
1211         } else {
1212             memcpy(p_sys->seq_table[i].chunk_bitmask, &mst_buf[8], i_map_size);
1213         }
1214     }
1215
1216     /* set up a few of our variables */
1217     p_sys->l_first_ty_pts = p_sys->seq_table[0].l_timestamp;
1218     p_sys->l_final_ty_pts =
1219         p_sys->seq_table[p_sys->i_seq_table_size - 1].l_timestamp;
1220     p_sys->b_have_master = VLC_TRUE;
1221
1222     i_pts_secs = p_sys->l_first_ty_pts / 1000000000;
1223     msg_Dbg( p_demux, "first TY pts in master is %02d:%02d:%02d",
1224              (int)(i_pts_secs / 3600), (int)((i_pts_secs / 60) % 60), (int)(i_pts_secs % 60) );
1225     i_pts_secs = p_sys->l_final_ty_pts / 1000000000;
1226     msg_Dbg( p_demux, "final TY pts in master is %02d:%02d:%02d",
1227              (int)(i_pts_secs / 3600), (int)((i_pts_secs / 60) % 60), (int)(i_pts_secs % 60) );
1228
1229     /* seek past this chunk */
1230     stream_Seek(p_demux->s, i_save_pos + CHUNK_SIZE);
1231 }
1232
1233
1234 /* ======================================================================== */
1235 /* "Peek" at some chunks.  Skip over the Part header if we find it.
1236  * We parse the peeked data and determine audio type,
1237  * SA vs. DTivo, & Tivo Series.
1238  * Set global vars i_Pes_Length, i_Pts_Offset,
1239  * p_sys->tivo_series, p_sys->tivo_type, p_sys->audio_type */
1240 static int probe_stream(demux_t *p_demux)
1241 {
1242     demux_sys_t *p_sys = p_demux->p_sys;
1243     const uint8_t *p_buf;
1244     int i;
1245     vlc_bool_t b_probe_error = VLC_FALSE;
1246
1247     /* we need CHUNK_PEEK_COUNT chunks of data, first one might be a Part header, so ... */
1248     if (stream_Peek( p_demux->s, &p_buf, CHUNK_PEEK_COUNT * CHUNK_SIZE ) <
1249             CHUNK_PEEK_COUNT * CHUNK_SIZE) {
1250         msg_Err(p_demux, "Can't peek %d chunks", CHUNK_PEEK_COUNT);
1251         /* TODO: if seekable, then loop reading chunks into a temp buffer */
1252         return VLC_EGENERIC;
1253     }
1254     
1255     /* the real work: analyze this chunk */
1256     for (i = 0; i < CHUNK_PEEK_COUNT; i++) {
1257         analyze_chunk(p_demux, p_buf);
1258         if (p_sys->tivo_series != TIVO_SERIES_UNKNOWN &&
1259             p_sys->audio_type  != TIVO_AUDIO_UNKNOWN &&
1260             p_sys->tivo_type   != TIVO_TYPE_UNKNOWN)
1261             break;
1262         p_buf += CHUNK_SIZE;
1263     }
1264     
1265     /* the final tally */
1266     if (p_sys->tivo_series == TIVO_SERIES_UNKNOWN) {
1267         msg_Err(p_demux, "Can't determine Tivo Series.");
1268         b_probe_error = VLC_TRUE;
1269     }
1270     if (p_sys->audio_type == TIVO_AUDIO_UNKNOWN) {
1271         msg_Err(p_demux, "Can't determine Tivo Audio Type.");
1272         b_probe_error = VLC_TRUE;
1273     }
1274     if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1275         msg_Err(p_demux, "Can't determine Tivo Type (SA/DTivo).");
1276         b_probe_error = VLC_TRUE;
1277     }
1278     return b_probe_error?VLC_EGENERIC:VLC_SUCCESS;
1279 }
1280
1281
1282 /* ======================================================================== */
1283 /* gather statistics for this chunk & set our tivo-type vars accordingly */
1284 static void analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
1285 {
1286     demux_sys_t *p_sys = p_demux->p_sys;
1287     int i_num_recs, i;
1288     ty_rec_hdr_t *p_hdrs;
1289     int i_num_6e0, i_num_be0, i_num_9c0, i_num_3c0;
1290     uint32_t i_payload_size;
1291
1292     /* skip if it's a Part header */
1293     if( U32_AT( &p_chunk[ 0 ] ) == TIVO_PES_FILEID )
1294         return;
1295
1296     /* number of records in chunk (we ignore high order byte;
1297      * rarely are there > 256 chunks & we don't need that many anyway) */
1298     i_num_recs = p_chunk[0];
1299     if (i_num_recs < 5) {
1300         /* try again with the next chunk.  Sometimes there are dead ones */
1301         return;
1302     }
1303     
1304     p_chunk += 4;       /* skip past rec count & SEQ bytes */
1305     //msg_Dbg(p_demux, "probe: chunk has %d recs", i_num_recs);
1306     p_hdrs = parse_chunk_headers(p_demux, p_chunk, i_num_recs, &i_payload_size);
1307     /* scan headers.
1308      * 1. check video packets.  Presence of 0x6e0 means S1.
1309      *    No 6e0 but have be0 means S2.
1310      * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg)
1311      *    If AC-3, then we have DTivo.
1312      *    If MPEG, search for PTS offset.  This will determine SA vs. DTivo.
1313      */
1314     i_num_6e0 = i_num_be0 = i_num_9c0 = i_num_3c0 = 0;
1315     for (i=0; i<i_num_recs; i++) {
1316         //msg_Dbg(p_demux, "probe: rec is %d/%d = 0x%04x", p_hdrs[i].subrec_type,
1317             //p_hdrs[i].rec_type,
1318             //p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type);
1319         switch (p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type) {
1320             case 0x6e0:
1321                 i_num_6e0++;
1322                 break;
1323             case 0xbe0:
1324                 i_num_be0++;
1325                 break;
1326             case 0x3c0:
1327                 i_num_3c0++;
1328                 break;
1329             case 0x9c0:
1330                 i_num_9c0++;
1331                 break;
1332         }
1333     }
1334     msg_Dbg(p_demux, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.",
1335         i_num_6e0, i_num_be0);
1336
1337     /* set up our variables */
1338     if (i_num_6e0 > 0) {
1339         msg_Dbg(p_demux, "detected Series 1 Tivo");
1340         p_sys->tivo_series = TIVO_SERIES1;
1341         p_sys->i_Pes_Length = SERIES1_PES_LENGTH;
1342     } else if (i_num_be0 > 0) {
1343         msg_Dbg(p_demux, "detected Series 2 Tivo");
1344         p_sys->tivo_series = TIVO_SERIES2;
1345         p_sys->i_Pes_Length = SERIES2_PES_LENGTH;
1346     }
1347     if (i_num_9c0 > 0) {
1348         msg_Dbg(p_demux, "detected AC-3 Audio (DTivo)" );
1349         p_sys->audio_type = TIVO_AUDIO_AC3;
1350         p_sys->tivo_type = TIVO_TYPE_DTIVO;
1351         p_sys->i_Pts_Offset = AC3_PTS_OFFSET;
1352         p_sys->i_Pes_Length = AC3_PES_LENGTH;
1353     } else if (i_num_3c0 > 0) {
1354         p_sys->audio_type = TIVO_AUDIO_MPEG;
1355         msg_Dbg(p_demux, "detected MPEG Audio" );
1356     }
1357
1358     /* if tivo_type still unknown, we can check PTS location
1359      * in MPEG packets to determine tivo_type */
1360     if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1361         uint32_t i_data_offset = (16 * i_num_recs);
1362         for (i=0; i<i_num_recs; i++) {
1363             if ((p_hdrs[i].subrec_type << 0x08 | p_hdrs[i].rec_type) == 0x3c0 &&
1364                     p_hdrs[i].l_rec_size > 15) {
1365                 /* first make sure we're aligned */
1366                 int i_pes_offset = find_es_header(ty_MPEGAudioPacket,
1367                         &p_chunk[i_data_offset], 5);
1368                 if (i_pes_offset >= 0) {
1369                     /* pes found. on SA, PES has hdr data at offset 6, not PTS. */
1370                     //msg_Dbg(p_demux, "probe: mpeg es header found in rec %d at offset %d",
1371                             //i, i_pes_offset);
1372                     if ((p_chunk[i_data_offset + 6 + i_pes_offset] & 0x80) == 0x80) {
1373                         /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */
1374                         if (p_sys->tivo_series == TIVO_SERIES1)
1375                             msg_Dbg(p_demux, "detected Stand-Alone Tivo" );
1376                         p_sys->tivo_type = TIVO_TYPE_SA;
1377                         p_sys->i_Pts_Offset = SA_PTS_OFFSET;
1378                     } else {
1379                         if (p_sys->tivo_series == TIVO_SERIES1)
1380                             msg_Dbg(p_demux, "detected DirecTV Tivo" );
1381                         p_sys->tivo_type = TIVO_TYPE_DTIVO;
1382                         p_sys->i_Pts_Offset = DTIVO_PTS_OFFSET;
1383                     }
1384                     break;
1385                 }
1386             }
1387             i_data_offset += p_hdrs[i].l_rec_size;
1388         }
1389     }
1390     free(p_hdrs);
1391 }
1392
1393
1394 /* =========================================================================== */
1395 static int get_chunk_header(demux_t *p_demux)
1396 {
1397     int i_readSize, i_num_recs;
1398     uint8_t *p_hdr_buf;
1399     const uint8_t *p_peek;
1400     demux_sys_t *p_sys = p_demux->p_sys;
1401     int i_payload_size;             /* sum of all records' sizes */
1402
1403     msg_Dbg(p_demux, "parsing ty chunk #%d", p_sys->i_cur_chunk );
1404
1405     /* if we have left-over filler space from the last chunk, get that */
1406     if (p_sys->i_stuff_cnt > 0) {
1407         stream_Read( p_demux->s, NULL, p_sys->i_stuff_cnt);
1408         p_sys->i_stuff_cnt = 0;
1409     }
1410
1411     /* read the TY packet header */
1412     i_readSize = stream_Peek( p_demux->s, &p_peek, 4 );
1413     p_sys->i_cur_chunk++;
1414   
1415     if ( (i_readSize < 4) || ( U32_AT(&p_peek[ 0 ] ) == 0 ))
1416     {
1417         /* EOF */
1418         p_sys->eof = 1;
1419         return 0;
1420     }
1421   
1422     /* check if it's a PART Header */
1423     if( U32_AT( &p_peek[ 0 ] ) == TIVO_PES_FILEID )
1424     {
1425         /* parse master chunk */
1426         parse_master(p_demux);
1427         return get_chunk_header(p_demux);
1428     }
1429     
1430     /* number of records in chunk (8- or 16-bit number) */
1431     if (p_peek[3] & 0x80)
1432     {
1433         /* 16 bit rec cnt */
1434         p_sys->i_num_recs = i_num_recs = (p_peek[1] << 8) + p_peek[0];
1435         p_sys->i_seq_rec = (p_peek[3] << 8) + p_peek[2];
1436         if (p_sys->i_seq_rec != 0xffff)
1437         {
1438             p_sys->i_seq_rec &= ~0x8000;
1439         }
1440     }
1441     else
1442     {
1443         /* 8 bit reclen - tivo 1.3 format */
1444         p_sys->i_num_recs = i_num_recs = p_peek[0];
1445         p_sys->i_seq_rec = p_peek[1];
1446     }
1447     p_sys->i_cur_rec = 0;
1448     p_sys->b_first_chunk = VLC_FALSE;
1449   
1450     /*msg_Dbg( p_demux, "chunk has %d records", i_num_recs );*/
1451
1452     if (p_sys->rec_hdrs)
1453         free(p_sys->rec_hdrs);
1454
1455     /* skip past the 4 bytes we "peeked" earlier */
1456     stream_Read( p_demux->s, NULL, 4 );
1457
1458     /* read the record headers into a temp buffer */
1459     p_hdr_buf = malloc(i_num_recs * 16);
1460     if (stream_Read(p_demux->s, p_hdr_buf, i_num_recs * 16) < i_num_recs * 16) {
1461         free( p_hdr_buf );
1462         p_sys->eof = VLC_TRUE;
1463         return 0;
1464     }
1465     /* parse them */
1466     p_sys->rec_hdrs = parse_chunk_headers(p_demux, p_hdr_buf, i_num_recs,
1467             &i_payload_size);
1468     free(p_hdr_buf);
1469
1470     p_sys->i_stuff_cnt = CHUNK_SIZE - 4 -
1471         (p_sys->i_num_recs * 16) - i_payload_size;
1472     if (p_sys->i_stuff_cnt > 0)
1473         msg_Dbg( p_demux, "chunk has %d stuff bytes at end",
1474                  p_sys->i_stuff_cnt );
1475     return 1;
1476 }
1477
1478
1479 static ty_rec_hdr_t *parse_chunk_headers( demux_t *p_demux, const uint8_t *p_buf,
1480                                           int i_num_recs, int *pi_payload_size)
1481 {
1482     int i;
1483     ty_rec_hdr_t *p_hdrs, *p_rec_hdr;
1484
1485     *pi_payload_size = 0;
1486     p_hdrs = malloc(i_num_recs * sizeof(ty_rec_hdr_t));
1487
1488     for (i = 0; i < i_num_recs; i++)
1489     {
1490         const uint8_t *record_header = p_buf + (i * 16);
1491         p_rec_hdr = &p_hdrs[i];     /* for brevity */
1492         p_rec_hdr->rec_type = record_header[3];
1493         p_rec_hdr->subrec_type = record_header[2] & 0x0f;
1494         if ((record_header[ 0 ] & 0x80) == 0x80)
1495         {
1496             uint8_t b1, b2;
1497             /* marker bit 2 set, so read extended data */
1498             b1 = ( ( ( record_header[ 0 ] & 0x0f ) << 4 ) | 
1499                    ( ( record_header[ 1 ] & 0xf0 ) >> 4 ) );
1500             b1 &= 0x7f;
1501             b2 = ( ( ( record_header[ 1 ] & 0x0f ) << 4 ) | 
1502                    ( ( record_header[ 2 ] & 0xf0 ) >> 4 ) );
1503             b2 &= 0x7f;
1504
1505             p_rec_hdr->ex1 = b1;
1506             p_rec_hdr->ex2 = b2;
1507             p_rec_hdr->l_rec_size = 0;
1508             p_rec_hdr->l_ty_pts = 0;
1509             p_rec_hdr->b_ext = VLC_TRUE;
1510         }
1511         else
1512         {
1513             p_rec_hdr->l_rec_size = ( record_header[ 0 ] << 8 |
1514                 record_header[ 1 ] ) << 4 | ( record_header[ 2 ] >> 4 );
1515             *pi_payload_size += p_rec_hdr->l_rec_size;
1516             p_rec_hdr->b_ext = VLC_FALSE;
1517             p_rec_hdr->l_ty_pts = U64_AT( &record_header[ 8 ] );
1518         }
1519         //fprintf( stderr, "parse_chunk_headers[%d] t=0x%x s=%d\n", i, p_rec_hdr->rec_type, p_rec_hdr->subrec_type );
1520     } /* end of record-header loop */
1521     return p_hdrs;
1522 }