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