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
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.
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.
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.
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 *****************************************************************************/
34 /*****************************************************************************
36 *****************************************************************************/
39 #include <vlc_demux.h>
40 #include "vlc_codec.h"
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Open ( vlc_object_t * );
46 static void Close( vlc_object_t * );
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.
58 set_callbacks( Open, Close );
63 /*****************************************************************************
65 *****************************************************************************/
66 static int Demux ( demux_t * );
67 static int Control( demux_t *, int, va_list );
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 };
82 #define CHUNK_PEEK_COUNT (3) /* number of chunks to probe */
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)
102 #define TIVO_PES_FILEID ( 0xf5467abd )
103 #define TIVO_PART_LENGTH ( 0x20000000 ) /* 536,870,912 bytes */
104 #define CHUNK_SIZE ( 128 * 1024 )
113 uint64_t l_ty_pts; /* TY PTS in the record header */
118 uint64_t l_timestamp;
119 uint8_t chunk_bitmask[8];
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 */
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 */
169 mtime_t firstAudioPTS;
170 mtime_t lastAudioPTS;
171 mtime_t lastVideoPTS;
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 */
179 vlc_bool_t b_first_chunk;
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);
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);
196 * Open: check file and initialize demux structures
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
205 static int Open(vlc_object_t *p_this)
207 demux_t *p_demux = (demux_t *)p_this;
210 const uint8_t *p_peek;
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 )
217 if ( U32_AT(p_peek) != TIVO_PES_FILEID ||
218 U32_AT(&p_peek[4]) != 0x02 ||
219 U32_AT(&p_peek[8]) != CHUNK_SIZE )
221 if( !p_demux->b_force &&
222 !demux2_IsPathExtension( p_demux, ".ty" ) &&
223 !demux2_IsPathExtension( p_demux, ".ty+" ) )
225 msg_Warn( p_demux, "this does not look like a TY file, "
226 "continuing anyway..." );
229 /* at this point, we assume we have a valid TY stream */
230 msg_Dbg( p_demux, "valid TY stream detected" );
232 /* Set exported functions */
233 p_demux->pf_demux = Demux;
234 p_demux->pf_control = Control;
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));
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;
252 /* see if this stream is seekable */
253 stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
255 if (probe_stream(p_demux) != VLC_SUCCESS) {
260 if (!p_sys->b_have_master)
261 msg_Warn(p_demux, "No master chunk found; seeking will be limited.");
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' ) );
267 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', ' ' ) );
269 p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
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 );
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);
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 )
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 */
302 /* =========================================================================== */
303 static int find_es_header( const uint8_t *header,
304 const uint8_t *buffer, int i_search_len )
308 for( count = 0; count < i_search_len; count++ )
310 if( !memcmp( &buffer[count], header, 4 ) )
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.
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 )
328 demux_sys_t *p_sys = p_demux->p_sys;
330 if ( offset < 0 || offset + p_sys->i_Pes_Length > rec_len )
332 /* entire PES header not present */
333 msg_Dbg( p_demux, "PES header at %d not complete in record. storing.",
335 /* save the partial pes header */
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;
342 msg_Err( p_demux, "PES header not found in record of %d bytes!",
346 /* copy the partial pes header we found */
347 memcpy( p_sys->pes_buffer, p_block->p_buffer + offset,
349 p_sys->i_pes_buf_cnt = rec_len - offset;
353 /* PES Header was found, but not complete, so trim the end of this record */
354 p_block->i_buffer -= rec_len - offset;
357 return -1; /* partial PES, no audio data */
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;
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]);
387 /* =========================================================================== */
388 /* Demux: Read & Demux one record from the chunk
390 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
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 :) --
396 static int Demux( demux_t *p_demux )
398 demux_sys_t *p_sys = p_demux->p_sys;
401 int recordsDecoded = 0;
407 ty_rec_hdr_t *rec_hdr;
409 block_t *p_block_in = NULL;
412 uint8_t lastCC[ 16 ];
413 uint8_t lastXDS[ 16 ];
415 /*msg_Dbg(p_demux, "ty demux processing" );*/
417 /* did we hit EOF earlier? */
418 if (p_sys->eof) return 0;
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()
431 * if this is the first time or
432 * if we're at the end of this chunk, start a new one
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)
439 /*======================================================================
440 * parse & send one record of the chunk
441 *====================================================================== */
442 i_cur_rec = p_sys->i_cur_rec;
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;
451 /*msg_Dbg(p_demux, "Record Type 0x%x/%02x %ld bytes",
452 subrec_type, rec_type, l_rec_size );*/
454 /* some normal records are 0 length, so check for that... */
457 /* read in this record's payload */
458 if( !( p_block_in = stream_Block( p_demux->s, l_rec_size ) ) )
464 /* set these as 'unknown' for now */
465 p_block_in->i_pts = p_block_in->i_dts = 0;
469 /* no data in payload; we're done */
476 -- don't read any data from the stream, data was in the record header --
478 "Record Type 0x%02x/%02x, ext data = %02x, %02x", subrec_type,
479 rec_type, rec_hdr->ex1, rec_hdr->ex2);
482 /*================================================================*
484 *================================================================*/
485 if ( rec_type == 0xe0 )
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]);
500 //if( subrec_type == 0x06 || subrec_type == 0x07 )
501 if( subrec_type != 0x02 && subrec_type != 0x0c
502 && subrec_type != 0x08 && l_rec_size > 4 )
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,
509 if ( esOffset1 != -1 )
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;
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;
532 msg_Dbg(p_demux, "No Video PES hdr in pkt type 0x%02x",
535 if (subrec_type == 0x06) {
536 /* type 6 (S1 DTivo) has no data, so we're done */
537 block_Release(p_block_in);
539 /* if it's not a continue blk, then set PTS */
540 if (subrec_type != 0x02)
542 /*msg_Dbg(p_demux, "Video rec %d type 0x%02X", p_sys->i_cur_rec,
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;
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.
562 p_sys->l_last_ty_pts += 35000000;
563 //p_sys->l_last_ty_pts += 33366667;
565 /* set PTS for this block before we send */
566 if (p_sys->lastVideoPTS > 0)
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;
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);
579 } /* end if video rec type */
580 /* ================================================================
582 * ================================================================
583 * parse PES headers and send the rest to the codec
585 else if ( rec_type == 0xc0 )
589 printf( "Audio Packet Header " );
590 for( i = 0 ; i < 24 ; i++ )
591 printf( "%2.2x ", p_block_in->p_buffer[i] );
595 /* SA or DTiVo Audio Data, no PES (continued block)
596 * ================================================
598 if ( subrec_type == 2 )
600 /* continue PES if previous was incomplete */
601 if (p_sys->i_pes_buf_cnt > 0)
603 int i_need = p_sys->i_Pes_Length - p_sys->i_pes_buf_cnt;
605 msg_Dbg(p_demux, "continuing PES header");
606 /* do we have enough data to complete? */
607 if (i_need < l_rec_size)
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);
620 esOffset1 = find_es_header(ty_AC3AudioPacket,
621 p_sys->pes_buffer, 5);
624 /* god help us; something's really wrong */
625 msg_Err(p_demux, "can't find audio PES header in packet");
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;
633 p_sys->i_pes_buf_cnt = 0;
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;
642 block_Release(p_block_in);
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 >
656 p_block_in->i_buffer -= 2;
657 p_sys->l_ac3_pkt_size = 0;
659 p_sys->l_ac3_pkt_size += p_block_in->i_buffer;
662 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
665 /* MPEG Audio with PES Header, either SA or DTiVo */
666 /* ================================================ */
667 if ( subrec_type == 0x03 )
669 esOffset1 = find_es_header( ty_MPEGAudioPacket,
670 p_block_in->p_buffer, 5 );
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);*/
677 /* SA PES Header, No Audio Data */
678 /* ================================================ */
679 if ( ( esOffset1 == 0 ) && ( l_rec_size == 16 ) )
681 p_sys->lastAudioPTS = get_pts( &p_block_in->p_buffer[
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 );*/
690 /* DTiVo Audio with PES Header */
691 /* ================================================ */
693 /* Check for complete PES */
694 if (check_sync_pes(p_demux, p_block_in, esOffset1,
697 /* partial PES header found, nothing else.
700 block_Release(p_block_in);
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]);
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,
720 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
722 } /* if subrec == 0x03 */
724 /* SA Audio with no PES Header */
725 /* ================================================ */
726 if ( subrec_type == 0x04 )
729 "Adding SA Audio Packet Size %ld", l_rec_size ); */
731 /* set PCR before we send */
732 if (p_sys->lastAudioPTS > 0)
734 p_block_in->i_pts = p_sys->lastAudioPTS;
735 es_out_Control( p_demux->out, ES_OUT_SET_PCR,
738 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
741 /* DTiVo AC3 Audio Data with PES Header */
742 /* ================================================ */
743 if ( subrec_type == 0x09 )
745 esOffset1 = find_es_header( ty_AC3AudioPacket,
746 p_block_in->p_buffer, 5 );
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);
763 /* Check for complete PES */
764 if (check_sync_pes(p_demux, p_block_in, esOffset1,
767 /* partial PES header found, nothing else. we're done. */
771 /* set PCR before we send (if PTS found) */
772 if( p_block_in->i_pts > 0 )
774 es_out_Control( p_demux->out, ES_OUT_SET_PCR,
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;
783 p_sys->l_ac3_pkt_size = p_block_in->i_buffer;
786 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
788 } /* end "if audio" */
789 /* ================================================================ */
791 /* ================================================================ */
792 else if ( rec_type == 0x01 )
794 /*msg_Dbg(p_demux, "CC1 %02x %02x [%c%c]", rec_hdr->ex1,
795 rec_hdr->ex2, rec_hdr->ex1, rec_hdr->ex2 );*/
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 );*/
812 else if ( rec_type == 0x02 )
814 /*msg_Dbg(p_demux, "CC2 %02x %02x", rec_hdr->ex1, rec_hdr->ex2 );*/
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 );*/
830 /* ================================================================ */
831 /* Tivo data services (e.g. "thumbs-up to record!") useless for us */
832 /* ================================================================ */
833 else if ( rec_type == 0x03 )
836 /* ================================================================ */
837 /* Unknown, but seen regularly */
838 /* ================================================================ */
839 else if ( rec_type == 0x05 )
844 msg_Dbg(p_demux, "Invalid record type 0x%02x", rec_type );
845 if (p_block_in) block_Release(p_block_in);
853 /* seek to a position within the stream, if possible */
854 static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct)
856 demux_sys_t *p_sys = p_demux->p_sys;
857 int64_t seek_pos = p_sys->i_stream_size * seek_pct;
861 /* if we're not seekable, there's nothing to do */
862 if (!p_sys->b_seekable)
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;
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 ))
872 /* can't seek stream */
875 parse_master(p_demux);
877 /* now for the actual chunk */
878 if ( stream_Seek( p_demux->s, p_sys->i_cur_chunk * CHUNK_SIZE))
880 /* can't seek stream */
884 p_sys->i_stuff_cnt = 0;
885 get_chunk_header(p_demux);
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);
894 /* seek to the start of this record's data.
895 * to do that, we have to skip past all prior records */
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);
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 );
909 /* seek to an exact time position within the stream, if possible.
910 * l_seek_time is in nanoseconds, the TIVO time standard.
912 static int ty_stream_seek_time(demux_t *p_demux, uint64_t l_seek_time)
914 demux_sys_t *p_sys = p_demux->p_sys;
915 int i, i_seq_entry = 0;
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;
922 /* if we're not seekable, there's nothing to do */
923 if (!p_sys->b_seekable || !p_sys->b_have_master)
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);
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");
939 stream_Seek(p_demux->s, (i_cur_part - 1) * TIVO_PART_LENGTH);
941 parse_master(p_demux);
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.");
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");
953 stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
955 parse_master(p_demux);
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;
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");
983 stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
985 parse_master(p_demux);
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) +
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;
1015 l_seek_secs = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts /
1017 msg_Dbg(p_demux, "found SEQ hdr for timestamp %02ld:%02ld:%02ld",
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.");
1027 msg_Dbg(p_demux, "timestamp too early. still scanning.");
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);
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
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;
1052 /* parse a master chunk, filling the SEQ table and other variables.
1053 * We assume the stream is currently pointing to it.
1055 static void parse_master(demux_t *p_demux)
1057 demux_sys_t *p_sys = p_demux->p_sys;
1058 uint8_t mst_buf[32];
1060 int64_t i_save_pos = stream_Tell(p_demux->s);
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. */
1069 /* clear the SEQ table */
1070 if (p_sys->seq_table != NULL)
1071 free(p_sys->seq_table);
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);
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);
1089 memcpy(p_sys->seq_table[i].chunk_bitmask, &mst_buf[8], i_map_size);
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;
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) );
1106 /* seek past this chunk */
1107 stream_Seek(p_demux->s, i_save_pos + CHUNK_SIZE);
1111 static int Control(demux_t *p_demux, int i_query, va_list args)
1113 demux_sys_t *p_sys = p_demux->p_sys;
1115 int64_t i64, *p_i64;
1117 /*msg_Info(p_demux, "control cmd %d", i_query);*/
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 )
1124 pf = (double*) va_arg( args, double* );
1125 *pf = (double)stream_Tell( p_demux->s ) / (double) i64;
1128 return VLC_EGENERIC;
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);
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 *);
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);
1155 return VLC_EGENERIC;
1160 /* ======================================================================== */
1161 static void Close( vlc_object_t *p_this )
1163 demux_sys_t *p_sys = ((demux_t *) p_this)->p_sys;
1165 free(p_sys->rec_hdrs);
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)
1178 demux_sys_t *p_sys = p_demux->p_sys;
1179 const uint8_t *p_buf;
1181 vlc_bool_t b_probe_error = VLC_FALSE;
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;
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)
1198 p_buf += CHUNK_SIZE;
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;
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;
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;
1214 return b_probe_error?VLC_EGENERIC:VLC_SUCCESS;
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)
1222 demux_sys_t *p_sys = p_demux->p_sys;
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;
1228 /* skip if it's a Part header */
1229 if( U32_AT( &p_chunk[ 0 ] ) == TIVO_PES_FILEID )
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 */
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);
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.
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) {
1270 msg_Dbg(p_demux, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.",
1271 i_num_6e0, i_num_be0);
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;
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" );
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",
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;
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;
1323 i_data_offset += p_hdrs[i].l_rec_size;
1330 /* =========================================================================== */
1331 static int get_chunk_header(demux_t *p_demux)
1333 int i_readSize, i_num_recs;
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 */
1339 msg_Dbg(p_demux, "parsing ty chunk #%d", p_sys->i_cur_chunk );
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;
1347 /* read the TY packet header */
1348 i_readSize = stream_Peek( p_demux->s, &p_peek, 4 );
1349 p_sys->i_cur_chunk++;
1351 if ( (i_readSize < 4) || ( U32_AT(&p_peek[ 0 ] ) == 0 ))
1358 /* check if it's a PART Header */
1359 if( U32_AT( &p_peek[ 0 ] ) == TIVO_PES_FILEID )
1361 /* parse master chunk */
1362 parse_master(p_demux);
1363 return get_chunk_header(p_demux);
1366 /* number of records in chunk (8- or 16-bit number) */
1367 if (p_peek[3] & 0x80)
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)
1374 p_sys->i_seq_rec &= ~0x8000;
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];
1383 p_sys->i_cur_rec = 0;
1384 p_sys->b_first_chunk = VLC_FALSE;
1386 /*msg_Dbg( p_demux, "chunk has %d records", i_num_recs );*/
1388 if (p_sys->rec_hdrs)
1389 free(p_sys->rec_hdrs);
1391 /* skip past the 4 bytes we "peeked" earlier */
1392 stream_Read( p_demux->s, NULL, 4 );
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;
1401 p_sys->rec_hdrs = parse_chunk_headers(p_demux, p_hdr_buf, i_num_recs,
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 );
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)
1418 ty_rec_hdr_t *p_hdrs, *p_rec_hdr;
1420 *pi_payload_size = 0;
1421 p_hdrs = malloc(i_num_recs * sizeof(ty_rec_hdr_t));
1423 for (i = 0; i < i_num_recs; i++)
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)
1432 /* marker bit 2 set, so read extended data */
1433 b1 = ( ( ( record_header[ 0 ] & 0x0f ) << 4 ) |
1434 ( ( record_header[ 1 ] & 0xf0 ) >> 4 ) );
1436 b2 = ( ( ( record_header[ 1 ] & 0x0f ) << 4 ) |
1437 ( ( record_header[ 2 ] & 0xf0 ) >> 4 ) );
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;
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 ] );
1454 } /* end of record-header loop */