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"
41 #include "../codec/cc.h"
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Open ( vlc_object_t * );
47 static void Close( vlc_object_t * );
50 set_shortname( _("TY") );
51 set_description(_("TY Stream audio/video demux"));
52 set_category( CAT_INPUT );
53 set_subcategory( SUBCAT_INPUT_DEMUX );
54 set_capability("demux2", 6);
55 /* FIXME: there seems to be a segfault when using PVR access
56 * and TY demux has a bigger priority than PS
57 * Something must be wrong.
59 set_callbacks( Open, Close );
64 /*****************************************************************************
66 *****************************************************************************/
67 static int Demux ( demux_t * );
68 static int Control( demux_t *, int, va_list );
70 #define SERIES1_PES_LENGTH (11) /* length of audio PES hdr on S1 */
71 #define SERIES2_PES_LENGTH (16) /* length of audio PES hdr on S2 */
72 #define AC3_PES_LENGTH (14) /* length of audio PES hdr for AC3 */
73 #define VIDEO_PES_LENGTH (16) /* length of video PES header */
74 #define DTIVO_PTS_OFFSET (6) /* offs into PES for MPEG PTS on DTivo */
75 #define SA_PTS_OFFSET (9) /* offset into PES for MPEG PTS on SA */
76 #define AC3_PTS_OFFSET (9) /* offset into PES for AC3 PTS on DTivo */
77 #define VIDEO_PTS_OFFSET (9) /* offset into PES for video PTS on all */
78 #define AC3_PKT_LENGTH (1536) /* size of TiVo AC3 pkts (w/o PES hdr) */
79 static const uint8_t ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 };
80 static const uint8_t ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 };
81 static const uint8_t ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd };
83 #define CHUNK_PEEK_COUNT (3) /* number of chunks to probe */
85 /* packet types for reference:
86 2/c0: audio data continued
87 3/c0: audio packet header (PES header)
88 4/c0: audio data (S/A only?)
89 9/c0: audio packet header, AC-3 audio
90 2/e0: video data continued
91 6/e0: video packet header (PES header)
92 7/e0: video sequence header start
93 8/e0: video I-frame header start
94 a/e0: video P-frame header start
95 b/e0: video B-frame header start
96 c/e0: video GOP header start
97 e/01: closed-caption data
98 e/02: Extended data services data
99 e/03: ipreview data ("thumbs up to record" signal)
103 #define TIVO_PES_FILEID ( 0xf5467abd )
104 #define TIVO_PART_LENGTH ( 0x20000000 ) /* 536,870,912 bytes */
105 #define CHUNK_SIZE ( 128 * 1024 )
114 uint64_t l_ty_pts; /* TY PTS in the record header */
119 uint64_t l_timestamp;
120 uint8_t chunk_bitmask[8];
146 es_out_id_t *p_video; /* ptr to video codec */
147 es_out_id_t *p_audio; /* holds either ac3 or mpeg codec ptr */
150 es_out_id_t *p_cc[4];
154 size_t i_stream_size; /* size of input stream (if known) */
155 //uint64_t l_program_len; /* length of this stream in msec */
156 vlc_bool_t b_seekable; /* is this stream seekable? */
157 vlc_bool_t b_have_master; /* are master chunks present? */
158 tivo_type_t tivo_type; /* tivo type (SA / DTiVo) */
159 tivo_series_t tivo_series; /* Series1 or Series2 */
160 tivo_audio_t audio_type; /* AC3 or MPEG */
161 int i_Pes_Length; /* Length of Audio PES header */
162 int i_Pts_Offset; /* offset into audio PES of PTS */
163 uint8_t pes_buffer[20]; /* holds incomplete pes headers */
164 int i_pes_buf_cnt; /* how many bytes in our buffer */
165 size_t l_ac3_pkt_size; /* len of ac3 pkt we've seen so far */
166 uint64_t l_last_ty_pts; /* last TY timestamp we've seen */
167 //mtime_t l_last_ty_pts_sync; /* audio PTS at time of last TY PTS */
168 uint64_t l_first_ty_pts; /* first TY PTS in this master chunk */
169 uint64_t l_final_ty_pts; /* final TY PTS in this master chunk */
170 int i_seq_table_size; /* number of entries in SEQ table */
171 int i_bits_per_seq_entry; /* # of bits in SEQ table bitmask */
173 mtime_t firstAudioPTS;
174 mtime_t lastAudioPTS;
175 mtime_t lastVideoPTS;
177 ty_rec_hdr_t *rec_hdrs; /* record headers array */
178 int i_cur_rec; /* current record in this chunk */
179 int i_num_recs; /* number of recs in this chunk */
180 int i_seq_rec; /* record number where seq start is */
181 ty_seq_table_t *seq_table; /* table of SEQ entries from mstr chk */
183 vlc_bool_t b_first_chunk;
186 static int get_chunk_header(demux_t *);
187 static mtime_t get_pts( const uint8_t *buf );
188 static int find_es_header( const uint8_t *header,
189 const uint8_t *buffer, int i_search_len );
190 static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct);
191 static int ty_stream_seek_time(demux_t *, uint64_t);
193 static ty_rec_hdr_t *parse_chunk_headers( demux_t *p_demux, const uint8_t *p_buf,
194 int i_num_recs, int *pi_payload_size);
195 static int probe_stream(demux_t *p_demux);
196 static void analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk);
197 static void parse_master(demux_t *p_demux);
199 static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
200 static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
201 static int DemuxRecCc( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in );
203 static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 );
206 * Open: check file and initialize demux structures
209 * 1. peek at the first 12 bytes of the stream for the
210 * magic TiVo PART header & stream type & chunk size
211 * 2. if it's not there, error with VLC_EGENERIC
212 * 3. set up video (mpgv) codec
213 * 4. return VLC_SUCCESS
215 static int Open(vlc_object_t *p_this)
217 demux_t *p_demux = (demux_t *)p_this;
220 const uint8_t *p_peek;
223 /* peek at the first 12 bytes. */
224 /* for TY streams, they're always the same */
225 if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
228 if ( U32_AT(p_peek) != TIVO_PES_FILEID ||
229 U32_AT(&p_peek[4]) != 0x02 ||
230 U32_AT(&p_peek[8]) != CHUNK_SIZE )
232 if( !p_demux->b_force &&
233 !demux2_IsPathExtension( p_demux, ".ty" ) &&
234 !demux2_IsPathExtension( p_demux, ".ty+" ) )
236 msg_Warn( p_demux, "this does not look like a TY file, "
237 "continuing anyway..." );
240 /* at this point, we assume we have a valid TY stream */
241 msg_Dbg( p_demux, "valid TY stream detected" );
243 /* Set exported functions */
244 p_demux->pf_demux = Demux;
245 p_demux->pf_control = Control;
247 /* create our structure that will hold all data */
248 p_demux->p_sys = p_sys = malloc(sizeof(demux_sys_t));
249 memset(p_sys, 0, sizeof(demux_sys_t));
251 /* set up our struct (most were zero'd out with the memset above) */
252 p_sys->b_first_chunk = VLC_TRUE;
253 p_sys->b_have_master = (U32_AT(p_peek) == TIVO_PES_FILEID);
254 p_sys->firstAudioPTS = -1;
255 p_sys->i_stream_size = stream_Size(p_demux->s);
256 p_sys->tivo_type = TIVO_TYPE_UNKNOWN;
257 p_sys->audio_type = TIVO_AUDIO_UNKNOWN;
258 p_sys->tivo_series = TIVO_SERIES_UNKNOWN;
259 p_sys->i_Pes_Length = 0;
260 p_sys->i_Pts_Offset = 0;
261 p_sys->l_ac3_pkt_size = 0;
263 /* see if this stream is seekable */
264 stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
266 if (probe_stream(p_demux) != VLC_SUCCESS) {
271 if (!p_sys->b_have_master)
272 msg_Warn(p_demux, "No master chunk found; seeking will be limited.");
274 /* register the proper audio codec */
275 if (p_sys->audio_type == TIVO_AUDIO_MPEG) {
276 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
278 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', ' ' ) );
280 p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
282 /* register the video stream */
283 es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', 'g', 'v' ) );
284 p_sys->p_video = es_out_Add( p_demux->out, &fmt );
287 for( i = 0; i < 4; i++ )
288 p_sys->p_cc[i] = NULL;
289 cc_Init( &p_sys->cc );
294 /* =========================================================================== */
295 /* Demux: Read & Demux one record from the chunk
297 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
299 * NOTE: I think we can return the number of packets sent instead of just 1.
300 * that means we can demux an entire chunk and shoot it back (may be more efficient)
301 * -- should try that some day :) --
303 static int Demux( demux_t *p_demux )
305 demux_sys_t *p_sys = p_demux->p_sys;
307 block_t *p_block_in = NULL;
309 /*msg_Dbg(p_demux, "ty demux processing" );*/
311 /* did we hit EOF earlier? */
316 * what we do (1 record now.. maybe more later):
317 * - use stream_Read() to read the chunk header & record headers
318 * - discard entire chunk if it is a PART header chunk
319 * - parse all the headers into record header array
320 * - keep a pointer of which record we're on
321 * - use stream_Block() to fetch each record
322 * - parse out PTS from PES headers
323 * - set PTS for data packets
324 * - pass the data on to the proper codec via es_out_Send()
326 * if this is the first time or
327 * if we're at the end of this chunk, start a new one
329 /* parse the next chunk's record headers */
330 if( p_sys->b_first_chunk || p_sys->i_cur_rec >= p_sys->i_num_recs )
332 if( get_chunk_header(p_demux) == 0 )
336 /*======================================================================
337 * parse & send one record of the chunk
338 *====================================================================== */
339 p_rec = &p_sys->rec_hdrs[p_sys->i_cur_rec];
343 const long l_rec_size = p_rec->l_rec_size;
344 /*msg_Dbg(p_demux, "Record Type 0x%x/%02x %ld bytes",
345 subrec_type, p_rec->rec_type, l_rec_size );*/
347 /* some normal records are 0 length, so check for that... */
348 if( l_rec_size <= 0 )
350 /* no data in payload; we're done */
355 /* read in this record's payload */
356 if( !( p_block_in = stream_Block( p_demux->s, l_rec_size ) ) )
359 /* set these as 'unknown' for now */
361 p_block_in->i_dts = 0;
365 -- don't read any data from the stream, data was in the record header --
367 "Record Type 0x%02x/%02x, ext data = %02x, %02x", subrec_type,
368 p_rec->rec_type, p_rec->ex1, p_rec->ex2);
371 if( p_rec->rec_type == 0xe0 )
374 DemuxRecVideo( p_demux, p_rec, p_block_in );
376 else if ( p_rec->rec_type == 0xc0 )
379 DemuxRecAudio( p_demux, p_rec, p_block_in );
381 else if( p_rec->rec_type == 0x01 || p_rec->rec_type == 0x02 )
383 /* Closed Captions/XDS */
384 DemuxRecCc( p_demux, p_rec, p_block_in );
386 else if ( p_rec->rec_type == 0x03 )
388 /* Tivo data services (e.g. "thumbs-up to record!") useless for us */
390 block_Release(p_block_in);
392 else if ( p_rec->rec_type == 0x05 )
394 /* Unknown, but seen regularly */
396 block_Release(p_block_in);
400 msg_Dbg(p_demux, "Invalid record type 0x%02x", p_rec->rec_type );
402 block_Release(p_block_in);
411 static int Control(demux_t *p_demux, int i_query, va_list args)
413 demux_sys_t *p_sys = p_demux->p_sys;
417 /*msg_Info(p_demux, "control cmd %d", i_query);*/
420 case DEMUX_GET_POSITION:
421 /* arg is 0.0 - 1.0 percent of overall file position */
422 if( ( i64 = p_sys->i_stream_size ) > 0 )
424 pf = (double*) va_arg( args, double* );
425 *pf = (double)stream_Tell( p_demux->s ) / (double) i64;
430 case DEMUX_SET_POSITION:
431 /* arg is 0.0 - 1.0 percent of overall file position */
432 f = (double) va_arg( args, double );
433 /* msg_Dbg(p_demux, "Control - set position to %2.3f", f); */
434 if ((i64 = p_sys->i_stream_size) > 0)
435 return ty_stream_seek_pct(p_demux, f);
438 /* return TiVo timestamp */
439 p_i64 = (int64_t *) va_arg(args, int64_t *);
440 //*p_i64 = p_sys->lastAudioPTS - p_sys->firstAudioPTS;
441 //*p_i64 = (p_sys->l_last_ty_pts / 1000) + (p_sys->lastAudioPTS -
442 // p_sys->l_last_ty_pts_sync);
443 *p_i64 = (p_sys->l_last_ty_pts / 1000);
445 case DEMUX_GET_LENGTH: /* length of program in microseconds, 0 if unk */
447 p_i64 = (int64_t *) va_arg(args, int64_t *);
450 case DEMUX_SET_TIME: /* arg is time in microsecs */
451 i64 = (int64_t) va_arg( args, int64_t );
452 return ty_stream_seek_time(p_demux, i64 * 1000);
460 static void Close( vlc_object_t *p_this )
462 demux_t *p_demux = (demux_t*)p_this;
463 demux_sys_t *p_sys = p_demux->p_sys;
465 cc_Exit( &p_sys->cc );
466 free( p_sys->rec_hdrs );
467 if( p_sys->seq_table )
468 free( p_sys->seq_table );
473 /* =========================================================================== */
474 /* Compute Presentation Time Stamp (PTS)
475 * Assume buf points to beginning of PTS */
476 static mtime_t get_pts( const uint8_t *buf )
480 i_pts = ((mtime_t)(buf[0]&0x0e ) << 29)|
481 (mtime_t)(buf[1] << 22)|
482 ((mtime_t)(buf[2]&0xfe) << 14)|
483 (mtime_t)(buf[3] << 7)|
484 (mtime_t)(buf[4] >> 1);
485 i_pts *= 100 / 9; /* convert PTS (90Khz clock) to microseconds */
490 /* =========================================================================== */
491 static int find_es_header( const uint8_t *header,
492 const uint8_t *buffer, int i_search_len )
496 for( count = 0; count < i_search_len; count++ )
498 if( !memcmp( &buffer[count], header, 4 ) )
505 /* =========================================================================== */
506 /* check if we have a full PES header, if not, then save what we have.
507 * this is called when audio-start packets are encountered.
509 * 1 partial PES hdr found, some audio data found (buffer adjusted),
510 * -1 partial PES hdr found, no audio data found
511 * 0 otherwise (complete PES found, pts extracted, pts set, buffer adjusted) */
512 /* TODO: HD support -- nothing known about those streams */
513 static int check_sync_pes( demux_t *p_demux, block_t *p_block,
514 int32_t offset, int32_t rec_len )
516 demux_sys_t *p_sys = p_demux->p_sys;
518 if ( offset < 0 || offset + p_sys->i_Pes_Length > rec_len )
520 /* entire PES header not present */
521 msg_Dbg( p_demux, "PES header at %d not complete in record. storing.",
523 /* save the partial pes header */
526 /* no header found, fake some 00's (this works, believe me) */
527 memset( p_sys->pes_buffer, 4, 0 );
528 p_sys->i_pes_buf_cnt = 4;
530 msg_Err( p_demux, "PES header not found in record of %d bytes!",
534 /* copy the partial pes header we found */
535 memcpy( p_sys->pes_buffer, p_block->p_buffer + offset,
537 p_sys->i_pes_buf_cnt = rec_len - offset;
541 /* PES Header was found, but not complete, so trim the end of this record */
542 p_block->i_buffer -= rec_len - offset;
545 return -1; /* partial PES, no audio data */
547 /* full PES header present, extract PTS */
548 p_sys->lastAudioPTS = get_pts( &p_block->p_buffer[ offset +
549 p_sys->i_Pts_Offset ] );
550 if (p_sys->firstAudioPTS < 0)
551 p_sys->firstAudioPTS = p_sys->lastAudioPTS;
552 p_block->i_pts = p_sys->lastAudioPTS;
553 /*msg_Dbg(p_demux, "Audio PTS %lld", p_sys->lastAudioPTS );*/
554 /* adjust audio record to remove PES header */
555 memmove(p_block->p_buffer + offset, p_block->p_buffer + offset +
556 p_sys->i_Pes_Length, rec_len - p_sys->i_Pes_Length);
557 p_block->i_buffer -= p_sys->i_Pes_Length;
559 msg_Dbg(p_demux, "pes hdr removed; buffer len=%d and has "
560 "%02x %02x %02x %02x %02x %02x %02x %02x "
561 "%02x %02x %02x %02x %02x %02x %02x %02x", p_block->i_buffer,
562 p_block->p_buffer[0], p_block->p_buffer[1],
563 p_block->p_buffer[2], p_block->p_buffer[3],
564 p_block->p_buffer[4], p_block->p_buffer[5],
565 p_block->p_buffer[6], p_block->p_buffer[7],
566 p_block->p_buffer[8], p_block->p_buffer[9],
567 p_block->p_buffer[10], p_block->p_buffer[11],
568 p_block->p_buffer[12], p_block->p_buffer[13],
569 p_block->p_buffer[14], p_block->p_buffer[15]);
574 static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
576 demux_sys_t *p_sys = p_demux->p_sys;
577 const int subrec_type = rec_hdr->subrec_type;
578 const long l_rec_size = rec_hdr->l_rec_size; // p_block_in->i_buffer might be better
582 assert( rec_hdr->rec_type == 0xe0 );
587 msg_Dbg(p_demux, "packet buffer has "
588 "%02x %02x %02x %02x %02x %02x %02x %02x "
589 "%02x %02x %02x %02x %02x %02x %02x %02x",
590 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
591 p_block_in->p_buffer[2], p_block_in->p_buffer[3],
592 p_block_in->p_buffer[4], p_block_in->p_buffer[5],
593 p_block_in->p_buffer[6], p_block_in->p_buffer[7],
594 p_block_in->p_buffer[8], p_block_in->p_buffer[9],
595 p_block_in->p_buffer[10], p_block_in->p_buffer[11],
596 p_block_in->p_buffer[12], p_block_in->p_buffer[13],
597 p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
599 //if( subrec_type == 0x06 || subrec_type == 0x07 )
600 if( subrec_type != 0x02 && subrec_type != 0x0c &&
601 subrec_type != 0x08 && l_rec_size > 4 )
603 /* get the PTS from this packet if it has one.
604 * on S1, only 0x06 has PES. On S2, however, most all do.
605 * Do NOT Pass the PES Header to the MPEG2 codec */
606 esOffset1 = find_es_header( ty_VideoPacket, p_block_in->p_buffer, 5 );
607 if( esOffset1 != -1 )
609 //msg_Dbg(p_demux, "Video PES hdr in pkt type 0x%02x at offset %d",
610 //subrec_type, esOffset1);
611 p_sys->lastVideoPTS = get_pts(
612 &p_block_in->p_buffer[ esOffset1 + VIDEO_PTS_OFFSET ] );
613 /*msg_Dbg(p_demux, "Video rec %d PTS "I64Fd, p_sys->i_cur_rec,
614 p_sys->lastVideoPTS );*/
615 if (subrec_type != 0x06) {
616 /* if we found a PES, and it's not type 6, then we're S2 */
617 /* The packet will have video data (& other headers) so we
618 * chop out the PES header and send the rest */
619 if (l_rec_size >= VIDEO_PES_LENGTH) {
620 p_block_in->p_buffer += VIDEO_PES_LENGTH + esOffset1;
621 p_block_in->i_buffer -= VIDEO_PES_LENGTH + esOffset1;
623 msg_Dbg(p_demux, "video rec type 0x%02x has short PES"
624 " (%ld bytes)", subrec_type, l_rec_size);
625 /* nuke this block; it's too short, but has PES marker */
626 p_block_in->i_buffer = 0;
630 msg_Dbg(p_demux, "No Video PES hdr in pkt type 0x%02x",
634 if(subrec_type == 0x06 )
636 /* type 6 (S1 DTivo) has no data, so we're done */
637 block_Release(p_block_in);
641 /* if it's not a continue blk, then set PTS */
642 if( subrec_type != 0x02 )
644 /*msg_Dbg(p_demux, "Video rec %d type 0x%02X", p_sys->i_cur_rec,
646 /* if it's a GOP header, make sure it's legal
647 * (if we have enough data) */
648 /* Some ty files don't have this bit set
649 * and it causes problems */
650 if (subrec_type == 0x0c && l_rec_size >= 6)
651 p_block_in->p_buffer[5] |= 0x08;
652 /* store the TY PTS if there is one */
653 if (subrec_type == 0x07) {
654 p_sys->l_last_ty_pts = rec_hdr->l_ty_pts;
655 /* should we use audio or video PTS? */
656 //p_sys->l_last_ty_pts_sync = p_sys->lastAudioPTS;
658 /* yes I know this is a cheap hack. It's the timestamp
659 used for display and skipping fwd/back, so it
660 doesn't have to be accurate to the millisecond.
661 I adjust it here by roughly one 1/30 sec. Yes it
662 will be slightly off for UK streams, but it's OK.
664 p_sys->l_last_ty_pts += 35000000;
665 //p_sys->l_last_ty_pts += 33366667;
667 /* set PTS for this block before we send */
668 if (p_sys->lastVideoPTS > 0)
670 p_block_in->i_pts = p_sys->lastVideoPTS;
671 /* PTS gets used ONCE.
672 * Any subsequent frames we get BEFORE next PES
673 * header will have their PTS computed in the codec */
674 p_sys->lastVideoPTS = 0;
678 /* Register the CC decoders when needed */
679 for( i = 0; i < 4; i++ )
681 static const vlc_fourcc_t fcc[4] = {
682 VLC_FOURCC('c', 'c', '1', ' '),
683 VLC_FOURCC('c', 'c', '2', ' '),
684 VLC_FOURCC('c', 'c', '3', ' '),
685 VLC_FOURCC('c', 'c', '4', ' ')
687 static const char *ppsz_description[4] = {
688 N_("Closed captions 1"),
689 N_("Closed captions 2"),
690 N_("Closed captions 3"),
691 N_("Closed captions 4"),
696 if( !p_sys->cc.pb_present[i] || p_sys->p_cc[i] )
699 es_format_Init( &fmt, SPU_ES, fcc[i] );
700 fmt.psz_description = strdup( _(ppsz_description[i]) );
701 p_sys->p_cc[i] = es_out_Add( p_demux->out, &fmt );
702 es_format_Clean( &fmt );
705 /* Send the CC data */
706 if( p_block_in->i_pts > 0 && p_sys->cc.i_data > 0 )
710 block_t *p_cc = block_New( p_demux, p_sys->cc.i_data );
711 p_cc->i_flags |= BLOCK_FLAG_TYPE_I;
712 p_cc->i_pts = p_block_in->i_pts;
713 memcpy( p_cc->p_buffer, p_sys->cc.p_data, p_sys->cc.i_data );
715 for( i = 0, i_cc_count = 0; i < 4; i++ )
716 i_cc_count += p_sys->p_cc[i] ? 1 : 0;
718 for( i = 0; i < 4; i++ )
720 if( !p_sys->p_cc[i] )
723 es_out_Send( p_demux->out, p_sys->p_cc[i], block_Duplicate( p_cc ) );
725 es_out_Send( p_demux->out, p_sys->p_cc[i], p_cc );
727 cc_Flush( &p_sys->cc );
730 //msg_Dbg(p_demux, "sending rec %d as video type 0x%02x",
731 //p_sys->i_cur_rec, subrec_type);
732 es_out_Send(p_demux->out, p_sys->p_video, p_block_in);
735 static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
737 demux_sys_t *p_sys = p_demux->p_sys;
738 const int subrec_type = rec_hdr->subrec_type;
739 const long l_rec_size = rec_hdr->l_rec_size;
742 assert( rec_hdr->rec_type == 0xc0 );
747 printf( "Audio Packet Header " );
748 for( i = 0 ; i < 24 ; i++ )
749 printf( "%2.2x ", p_block_in->p_buffer[i] );
753 if( subrec_type == 2 )
755 /* SA or DTiVo Audio Data, no PES (continued block)
756 * ================================================
759 /* continue PES if previous was incomplete */
760 if (p_sys->i_pes_buf_cnt > 0)
762 const int i_need = p_sys->i_Pes_Length - p_sys->i_pes_buf_cnt;
764 msg_Dbg(p_demux, "continuing PES header");
765 /* do we have enough data to complete? */
766 if (i_need >= l_rec_size)
768 /* don't have complete PES hdr; save what we have and return */
769 memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
770 p_block_in->p_buffer, l_rec_size);
771 p_sys->i_pes_buf_cnt += l_rec_size;
773 block_Release(p_block_in);
777 /* we have enough; reconstruct this p_frame with the new hdr */
778 memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
779 p_block_in->p_buffer, i_need);
780 /* advance the block past the PES header (don't want to send it) */
781 p_block_in->p_buffer += i_need;
782 p_block_in->i_buffer -= i_need;
783 /* get the PTS out of this PES header (MPEG or AC3) */
784 if (p_sys->audio_type == TIVO_AUDIO_MPEG)
785 esOffset1 = find_es_header(ty_MPEGAudioPacket,
786 p_sys->pes_buffer, 5);
788 esOffset1 = find_es_header(ty_AC3AudioPacket,
789 p_sys->pes_buffer, 5);
792 /* god help us; something's really wrong */
793 msg_Err(p_demux, "can't find audio PES header in packet");
797 p_sys->lastAudioPTS = get_pts(
798 &p_sys->pes_buffer[ esOffset1 + p_sys->i_Pts_Offset ] );
799 p_block_in->i_pts = p_sys->lastAudioPTS;
801 p_sys->i_pes_buf_cnt = 0;
803 /* S2 DTivo has AC3 packets with 2 padding bytes at end. This is
804 * not allowed in the AC3 spec and will cause problems. So here
805 * we try to trim things. */
806 /* Also, S1 DTivo has alternating short / long AC3 packets. That
807 * is, one packet is short (incomplete) and the next packet has
808 * the first one's missing data, plus all of its own. Strange. */
809 if (p_sys->audio_type == TIVO_AUDIO_AC3 &&
810 p_sys->tivo_series == TIVO_SERIES2) {
811 if (p_sys->l_ac3_pkt_size + p_block_in->i_buffer >
813 p_block_in->i_buffer -= 2;
814 p_sys->l_ac3_pkt_size = 0;
816 p_sys->l_ac3_pkt_size += p_block_in->i_buffer;
820 else if( subrec_type == 0x03 )
822 /* MPEG Audio with PES Header, either SA or DTiVo */
823 /* ================================================ */
824 esOffset1 = find_es_header( ty_MPEGAudioPacket,
825 p_block_in->p_buffer, 5 );
827 /*msg_Dbg(p_demux, "buffer has %#02x %#02x %#02x %#02x",
828 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
829 p_block_in->p_buffer[2], p_block_in->p_buffer[3]);
830 msg_Dbg(p_demux, "audio ES hdr at offset %d", esOffset1);*/
832 /* SA PES Header, No Audio Data */
833 /* ================================================ */
834 if ( ( esOffset1 == 0 ) && ( l_rec_size == 16 ) )
836 p_sys->lastAudioPTS = get_pts( &p_block_in->p_buffer[
838 if (p_sys->firstAudioPTS < 0)
839 p_sys->firstAudioPTS = p_sys->lastAudioPTS;
841 block_Release(p_block_in);
843 /*msg_Dbg(p_demux, "SA Audio PTS %lld",
844 p_sys->lastAudioPTS );*/
846 /* DTiVo Audio with PES Header */
847 /* ================================================ */
849 /* Check for complete PES */
850 if (check_sync_pes(p_demux, p_block_in, esOffset1,
853 /* partial PES header found, nothing else.
855 block_Release(p_block_in);
859 msg_Dbg(p_demux, "packet buffer has "
860 "%02x %02x %02x %02x %02x %02x %02x %02x "
861 "%02x %02x %02x %02x %02x %02x %02x %02x",
862 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
863 p_block_in->p_buffer[2], p_block_in->p_buffer[3],
864 p_block_in->p_buffer[4], p_block_in->p_buffer[5],
865 p_block_in->p_buffer[6], p_block_in->p_buffer[7],
866 p_block_in->p_buffer[8], p_block_in->p_buffer[9],
867 p_block_in->p_buffer[10], p_block_in->p_buffer[11],
868 p_block_in->p_buffer[12], p_block_in->p_buffer[13],
869 p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
872 else if( subrec_type == 0x04 )
874 /* SA Audio with no PES Header */
875 /* ================================================ */
877 "Adding SA Audio Packet Size %ld", l_rec_size ); */
879 if (p_sys->lastAudioPTS > 0)
880 p_block_in->i_pts = p_sys->lastAudioPTS;
882 else if( subrec_type == 0x09 )
884 /* DTiVo AC3 Audio Data with PES Header */
885 /* ================================================ */
886 esOffset1 = find_es_header( ty_AC3AudioPacket,
887 p_block_in->p_buffer, 5 );
890 msg_Dbg(p_demux, "buffer has "
891 "%02x %02x %02x %02x %02x %02x %02x %02x "
892 "%02x %02x %02x %02x %02x %02x %02x %02x",
893 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
894 p_block_in->p_buffer[2], p_block_in->p_buffer[3],
895 p_block_in->p_buffer[4], p_block_in->p_buffer[5],
896 p_block_in->p_buffer[6], p_block_in->p_buffer[7],
897 p_block_in->p_buffer[8], p_block_in->p_buffer[9],
898 p_block_in->p_buffer[10], p_block_in->p_buffer[11],
899 p_block_in->p_buffer[12], p_block_in->p_buffer[13],
900 p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
901 msg_Dbg(p_demux, "audio ES AC3 hdr at offset %d", esOffset1);
904 /* Check for complete PES */
905 if (check_sync_pes(p_demux, p_block_in, esOffset1,
908 /* partial PES header found, nothing else. we're done. */
909 block_Release(p_block_in);
912 /* S2 DTivo has invalid long AC3 packets */
913 if (p_sys->tivo_series == TIVO_SERIES2) {
914 if (p_block_in->i_buffer > AC3_PKT_LENGTH) {
915 p_block_in->i_buffer -= 2;
916 p_sys->l_ac3_pkt_size = 0;
918 p_sys->l_ac3_pkt_size = p_block_in->i_buffer;
924 /* Unsupported/Unknown */
925 block_Release(p_block_in);
929 /* set PCR before we send (if PTS found) */
930 if( p_block_in->i_pts > 0 )
931 es_out_Control( p_demux->out, ES_OUT_SET_PCR,
934 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
938 static int DemuxRecCc( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in )
940 demux_sys_t *p_sys = p_demux->p_sys;
945 block_Release(p_block_in);
947 if( rec_hdr->rec_type == 0x01 )
949 else if( rec_hdr->rec_type == 0x02 )
954 /* XDS data (extract programs infos) transmitted on field 2 only */
956 DemuxDecodeXds( p_demux, rec_hdr->ex1, rec_hdr->ex2 );
958 if( p_sys->cc.i_data + 3 > CC_MAX_DATA_SIZE )
961 p_sys->cc.p_data[p_sys->cc.i_data+0] = i_field;
962 p_sys->cc.p_data[p_sys->cc.i_data+1] = rec_hdr->ex1;
963 p_sys->cc.p_data[p_sys->cc.i_data+2] = rec_hdr->ex2;
964 p_sys->cc.i_data += 3;
966 i_channel = cc_Channel( i_field, &p_sys->cc.p_data[p_sys->cc.i_data+1] );
967 if( i_channel >= 0 && i_channel < 4 )
968 p_sys->cc.pb_present[i_channel] = VLC_TRUE;
972 /* seek to a position within the stream, if possible */
973 static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct)
975 demux_sys_t *p_sys = p_demux->p_sys;
976 int64_t seek_pos = p_sys->i_stream_size * seek_pct;
980 /* if we're not seekable, there's nothing to do */
981 if (!p_sys->b_seekable)
984 /* figure out which part & chunk we want & go there */
985 i_cur_part = seek_pos / TIVO_PART_LENGTH;
986 p_sys->i_cur_chunk = seek_pos / CHUNK_SIZE;
988 /* try to read the part header (master chunk) if it's there */
989 if ( stream_Seek( p_demux->s, i_cur_part * TIVO_PART_LENGTH ))
991 /* can't seek stream */
994 parse_master(p_demux);
996 /* now for the actual chunk */
997 if ( stream_Seek( p_demux->s, p_sys->i_cur_chunk * CHUNK_SIZE))
999 /* can't seek stream */
1000 return VLC_EGENERIC;
1002 /* load the chunk */
1003 p_sys->i_stuff_cnt = 0;
1004 get_chunk_header(p_demux);
1006 /* seek within the chunk to get roughly to where we want */
1007 p_sys->i_cur_rec = (int)
1008 ((double) ((seek_pos % CHUNK_SIZE) / (double) (CHUNK_SIZE)) * p_sys->i_num_recs);
1009 msg_Dbg(p_demux, "Seeked to file pos " I64Fd, seek_pos);
1010 msg_Dbg(p_demux, " (chunk %d, record %d)",
1011 p_sys->i_cur_chunk - 1, p_sys->i_cur_rec);
1013 /* seek to the start of this record's data.
1014 * to do that, we have to skip past all prior records */
1016 for (i=0; i<p_sys->i_cur_rec; i++)
1017 l_skip_amt += p_sys->rec_hdrs[i].l_rec_size;
1018 stream_Seek(p_demux->s, ((p_sys->i_cur_chunk-1) * CHUNK_SIZE) +
1019 (p_sys->i_num_recs * 16) + l_skip_amt + 4);
1021 /* to hell with syncing any audio or video, just start reading records... :) */
1022 /*p_sys->lastAudioPTS = p_sys->lastVideoPTS = 0;*/
1023 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
1027 static void DemuxDecodeXds( demux_t *p_demux, uint8_t d1, uint8_t d2 )
1032 /* seek to an exact time position within the stream, if possible.
1033 * l_seek_time is in nanoseconds, the TIVO time standard.
1035 static int ty_stream_seek_time(demux_t *p_demux, uint64_t l_seek_time)
1037 demux_sys_t *p_sys = p_demux->p_sys;
1038 int i, i_seq_entry = 0;
1040 long l_cur_pos = stream_Tell(p_demux->s);
1041 int i_cur_part = l_cur_pos / TIVO_PART_LENGTH;
1042 long l_seek_secs = l_seek_time / 1000000000;
1043 uint64_t l_fwd_stamp = 1;
1045 /* if we're not seekable, there's nothing to do */
1046 if (!p_sys->b_seekable || !p_sys->b_have_master)
1047 return VLC_EGENERIC;
1049 msg_Dbg(p_demux, "Skipping to time %02ld:%02ld:%02ld",
1050 l_seek_secs / 3600, (l_seek_secs / 60) % 60, l_seek_secs % 60);
1052 /* seek to the proper segment if necessary */
1053 /* first see if we need to go back */
1054 while (l_seek_time < p_sys->l_first_ty_pts) {
1055 msg_Dbg(p_demux, "skipping to prior segment.");
1056 /* load previous part */
1057 if (i_cur_part == 0) {
1058 stream_Seek(p_demux->s, l_cur_pos);
1059 msg_Err(p_demux, "Attempt to seek past BOF");
1060 return VLC_EGENERIC;
1062 stream_Seek(p_demux->s, (i_cur_part - 1) * TIVO_PART_LENGTH);
1064 parse_master(p_demux);
1066 /* maybe we need to go forward */
1067 while (l_seek_time > p_sys->l_final_ty_pts) {
1068 msg_Dbg(p_demux, "skipping to next segment.");
1069 /* load next part */
1070 if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1071 /* error; restore previous file position */
1072 stream_Seek(p_demux->s, l_cur_pos);
1073 msg_Err(p_demux, "seek error");
1074 return VLC_EGENERIC;
1076 stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
1078 parse_master(p_demux);
1081 /* our target is somewhere within this part;
1082 find the proper chunk using seq_table */
1083 for (i=1; i<p_sys->i_seq_table_size; i++) {
1084 if (p_sys->seq_table[i].l_timestamp > l_seek_time) {
1085 /* i-1 is the section we want; remember the next timestamp in case
1086 we have to use it (this section may not have a proper SEQ hdr
1087 for the time we're seeking) */
1088 msg_Dbg(p_demux, "stopping at seq entry %d.", i);
1089 l_fwd_stamp = p_sys->seq_table[i].l_timestamp;
1095 /* if we went through the entire last loop and didn't find our target,
1096 then we skip to the next part. What has happened is that the actual
1097 time we're seeking is within this part, but there isn't a SEQ hdr
1098 for it here. So we skip to the next part */
1099 if (i == p_sys->i_seq_table_size) {
1100 if ((i_cur_part + 1) * TIVO_PART_LENGTH > p_sys->i_stream_size) {
1101 /* error; restore previous file position */
1102 stream_Seek(p_demux->s, l_cur_pos);
1103 msg_Err(p_demux, "seek error");
1104 return VLC_EGENERIC;
1106 stream_Seek(p_demux->s, (i_cur_part + 1) * TIVO_PART_LENGTH);
1108 parse_master(p_demux);
1112 /* determine which chunk has our seek_time */
1113 for (i=0; i<p_sys->i_bits_per_seq_entry; i++) {
1114 long l_chunk_nr = i_seq_entry * p_sys->i_bits_per_seq_entry + i;
1115 long l_chunk_offset = (l_chunk_nr + 1) * CHUNK_SIZE;
1116 msg_Dbg(p_demux, "testing part %d chunk %ld mask 0x%02X bit %d",
1117 i_cur_part, l_chunk_nr,
1118 p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8], i%8);
1119 if (p_sys->seq_table[i_seq_entry].chunk_bitmask[i/8] & (1 << (i%8))) {
1120 /* check this chunk's SEQ header timestamp */
1121 msg_Dbg(p_demux, "has SEQ. seeking to chunk at 0x%lX",
1122 (i_cur_part * TIVO_PART_LENGTH) + l_chunk_offset);
1123 stream_Seek(p_demux->s, (i_cur_part * TIVO_PART_LENGTH) +
1125 // TODO: we don't have to parse the full header set;
1126 // just test the seq_rec entry for its timestamp
1127 p_sys->i_stuff_cnt = 0;
1128 get_chunk_header(p_demux);
1129 // check ty PTS for the SEQ entry in this chunk
1130 if (p_sys->i_seq_rec < 0 || p_sys->i_seq_rec > p_sys->i_num_recs) {
1131 msg_Err(p_demux, "no SEQ hdr in chunk; table had one.");
1132 /* Seek to beginning of original chunk & reload it */
1133 stream_Seek(p_demux->s, (l_cur_pos / CHUNK_SIZE) * CHUNK_SIZE);
1134 p_sys->i_stuff_cnt = 0;
1135 get_chunk_header(p_demux);
1136 return VLC_EGENERIC;
1138 l_seek_secs = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts /
1140 msg_Dbg(p_demux, "found SEQ hdr for timestamp %02ld:%02ld:%02ld",
1142 (l_seek_secs / 60) % 60, l_seek_secs % 60);
1143 if (p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts >= l_seek_time) {
1144 // keep this one? go back?
1145 /* for now, we take this one. it's the first SEQ hdr AFTER
1146 the time we were searching for. */
1147 msg_Dbg(p_demux, "seek target found.");
1150 msg_Dbg(p_demux, "timestamp too early. still scanning.");
1153 /* if we made it through this entire loop without finding our target,
1154 then we skip to the next section. What has happened is that the actual
1155 time we're seeking is within this section, but there isn't a SEQ hdr
1156 for it here. So we skip to the next closest one (l_fwd_stamp) */
1157 if (i == p_sys->i_bits_per_seq_entry)
1158 return ty_stream_seek_time(p_demux, l_fwd_stamp);
1160 /* current stream ptr is at beginning of data for this chunk,
1161 so we need to skip past any stream data prior to the seq_rec
1164 for (i=0; i<p_sys->i_seq_rec; i++)
1165 i_skip_cnt += p_sys->rec_hdrs[i].l_rec_size;
1166 stream_Read(p_demux->s, NULL, i_skip_cnt);
1167 p_sys->i_cur_rec = p_sys->i_seq_rec;
1168 //p_sys->l_last_ty_pts = p_sys->rec_hdrs[p_sys->i_seq_rec].l_ty_pts;
1169 //p_sys->l_last_ty_pts_sync = p_sys->lastAudioPTS;
1175 /* parse a master chunk, filling the SEQ table and other variables.
1176 * We assume the stream is currently pointing to it.
1178 static void parse_master(demux_t *p_demux)
1180 demux_sys_t *p_sys = p_demux->p_sys;
1181 uint8_t mst_buf[32];
1183 int64_t i_save_pos = stream_Tell(p_demux->s);
1186 /* Note that the entries in the SEQ table in the stream may have
1187 different sizes depending on the bits per entry. We store them
1188 all in the same size structure, so we have to parse them out one
1189 by one. If we had a dynamic structure, we could simply read the
1190 entire table directly from the stream into memory in place. */
1192 /* clear the SEQ table */
1193 if (p_sys->seq_table != NULL)
1194 free(p_sys->seq_table);
1196 /* parse header info */
1197 stream_Read(p_demux->s, mst_buf, 32);
1198 i_map_size = U32_AT(&mst_buf[20]); /* size of bitmask, in bytes */
1199 p_sys->i_bits_per_seq_entry = i_map_size * 8;
1200 i = U32_AT(&mst_buf[28]); /* size of SEQ table, in bytes */
1201 p_sys->i_seq_table_size = i / (8 + i_map_size);
1203 /* parse all the entries */
1204 p_sys->seq_table = malloc(p_sys->i_seq_table_size * sizeof(ty_seq_table_t));
1205 for (i=0; i<p_sys->i_seq_table_size; i++) {
1206 stream_Read(p_demux->s, mst_buf, 8 + i_map_size);
1207 p_sys->seq_table[i].l_timestamp = U64_AT(&mst_buf[0]);
1208 if (i_map_size > 8) {
1209 msg_Err(p_demux, "Unsupported SEQ bitmap size in master chunk");
1210 memset(p_sys->seq_table[i].chunk_bitmask, i_map_size, 0);
1212 memcpy(p_sys->seq_table[i].chunk_bitmask, &mst_buf[8], i_map_size);
1216 /* set up a few of our variables */
1217 p_sys->l_first_ty_pts = p_sys->seq_table[0].l_timestamp;
1218 p_sys->l_final_ty_pts =
1219 p_sys->seq_table[p_sys->i_seq_table_size - 1].l_timestamp;
1220 p_sys->b_have_master = VLC_TRUE;
1222 i_pts_secs = p_sys->l_first_ty_pts / 1000000000;
1223 msg_Dbg( p_demux, "first TY pts in master is %02d:%02d:%02d",
1224 (int)(i_pts_secs / 3600), (int)((i_pts_secs / 60) % 60), (int)(i_pts_secs % 60) );
1225 i_pts_secs = p_sys->l_final_ty_pts / 1000000000;
1226 msg_Dbg( p_demux, "final TY pts in master is %02d:%02d:%02d",
1227 (int)(i_pts_secs / 3600), (int)((i_pts_secs / 60) % 60), (int)(i_pts_secs % 60) );
1229 /* seek past this chunk */
1230 stream_Seek(p_demux->s, i_save_pos + CHUNK_SIZE);
1234 /* ======================================================================== */
1235 /* "Peek" at some chunks. Skip over the Part header if we find it.
1236 * We parse the peeked data and determine audio type,
1237 * SA vs. DTivo, & Tivo Series.
1238 * Set global vars i_Pes_Length, i_Pts_Offset,
1239 * p_sys->tivo_series, p_sys->tivo_type, p_sys->audio_type */
1240 static int probe_stream(demux_t *p_demux)
1242 demux_sys_t *p_sys = p_demux->p_sys;
1243 const uint8_t *p_buf;
1245 vlc_bool_t b_probe_error = VLC_FALSE;
1247 /* we need CHUNK_PEEK_COUNT chunks of data, first one might be a Part header, so ... */
1248 if (stream_Peek( p_demux->s, &p_buf, CHUNK_PEEK_COUNT * CHUNK_SIZE ) <
1249 CHUNK_PEEK_COUNT * CHUNK_SIZE) {
1250 msg_Err(p_demux, "Can't peek %d chunks", CHUNK_PEEK_COUNT);
1251 /* TODO: if seekable, then loop reading chunks into a temp buffer */
1252 return VLC_EGENERIC;
1255 /* the real work: analyze this chunk */
1256 for (i = 0; i < CHUNK_PEEK_COUNT; i++) {
1257 analyze_chunk(p_demux, p_buf);
1258 if (p_sys->tivo_series != TIVO_SERIES_UNKNOWN &&
1259 p_sys->audio_type != TIVO_AUDIO_UNKNOWN &&
1260 p_sys->tivo_type != TIVO_TYPE_UNKNOWN)
1262 p_buf += CHUNK_SIZE;
1265 /* the final tally */
1266 if (p_sys->tivo_series == TIVO_SERIES_UNKNOWN) {
1267 msg_Err(p_demux, "Can't determine Tivo Series.");
1268 b_probe_error = VLC_TRUE;
1270 if (p_sys->audio_type == TIVO_AUDIO_UNKNOWN) {
1271 msg_Err(p_demux, "Can't determine Tivo Audio Type.");
1272 b_probe_error = VLC_TRUE;
1274 if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1275 msg_Err(p_demux, "Can't determine Tivo Type (SA/DTivo).");
1276 b_probe_error = VLC_TRUE;
1278 return b_probe_error?VLC_EGENERIC:VLC_SUCCESS;
1282 /* ======================================================================== */
1283 /* gather statistics for this chunk & set our tivo-type vars accordingly */
1284 static void analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
1286 demux_sys_t *p_sys = p_demux->p_sys;
1288 ty_rec_hdr_t *p_hdrs;
1289 int i_num_6e0, i_num_be0, i_num_9c0, i_num_3c0;
1290 uint32_t i_payload_size;
1292 /* skip if it's a Part header */
1293 if( U32_AT( &p_chunk[ 0 ] ) == TIVO_PES_FILEID )
1296 /* number of records in chunk (we ignore high order byte;
1297 * rarely are there > 256 chunks & we don't need that many anyway) */
1298 i_num_recs = p_chunk[0];
1299 if (i_num_recs < 5) {
1300 /* try again with the next chunk. Sometimes there are dead ones */
1304 p_chunk += 4; /* skip past rec count & SEQ bytes */
1305 //msg_Dbg(p_demux, "probe: chunk has %d recs", i_num_recs);
1306 p_hdrs = parse_chunk_headers(p_demux, p_chunk, i_num_recs, &i_payload_size);
1308 * 1. check video packets. Presence of 0x6e0 means S1.
1309 * No 6e0 but have be0 means S2.
1310 * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg)
1311 * If AC-3, then we have DTivo.
1312 * If MPEG, search for PTS offset. This will determine SA vs. DTivo.
1314 i_num_6e0 = i_num_be0 = i_num_9c0 = i_num_3c0 = 0;
1315 for (i=0; i<i_num_recs; i++) {
1316 //msg_Dbg(p_demux, "probe: rec is %d/%d = 0x%04x", p_hdrs[i].subrec_type,
1317 //p_hdrs[i].rec_type,
1318 //p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type);
1319 switch (p_hdrs[i].subrec_type << 8 | p_hdrs[i].rec_type) {
1334 msg_Dbg(p_demux, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.",
1335 i_num_6e0, i_num_be0);
1337 /* set up our variables */
1338 if (i_num_6e0 > 0) {
1339 msg_Dbg(p_demux, "detected Series 1 Tivo");
1340 p_sys->tivo_series = TIVO_SERIES1;
1341 p_sys->i_Pes_Length = SERIES1_PES_LENGTH;
1342 } else if (i_num_be0 > 0) {
1343 msg_Dbg(p_demux, "detected Series 2 Tivo");
1344 p_sys->tivo_series = TIVO_SERIES2;
1345 p_sys->i_Pes_Length = SERIES2_PES_LENGTH;
1347 if (i_num_9c0 > 0) {
1348 msg_Dbg(p_demux, "detected AC-3 Audio (DTivo)" );
1349 p_sys->audio_type = TIVO_AUDIO_AC3;
1350 p_sys->tivo_type = TIVO_TYPE_DTIVO;
1351 p_sys->i_Pts_Offset = AC3_PTS_OFFSET;
1352 p_sys->i_Pes_Length = AC3_PES_LENGTH;
1353 } else if (i_num_3c0 > 0) {
1354 p_sys->audio_type = TIVO_AUDIO_MPEG;
1355 msg_Dbg(p_demux, "detected MPEG Audio" );
1358 /* if tivo_type still unknown, we can check PTS location
1359 * in MPEG packets to determine tivo_type */
1360 if (p_sys->tivo_type == TIVO_TYPE_UNKNOWN) {
1361 uint32_t i_data_offset = (16 * i_num_recs);
1362 for (i=0; i<i_num_recs; i++) {
1363 if ((p_hdrs[i].subrec_type << 0x08 | p_hdrs[i].rec_type) == 0x3c0 &&
1364 p_hdrs[i].l_rec_size > 15) {
1365 /* first make sure we're aligned */
1366 int i_pes_offset = find_es_header(ty_MPEGAudioPacket,
1367 &p_chunk[i_data_offset], 5);
1368 if (i_pes_offset >= 0) {
1369 /* pes found. on SA, PES has hdr data at offset 6, not PTS. */
1370 //msg_Dbg(p_demux, "probe: mpeg es header found in rec %d at offset %d",
1372 if ((p_chunk[i_data_offset + 6 + i_pes_offset] & 0x80) == 0x80) {
1373 /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */
1374 if (p_sys->tivo_series == TIVO_SERIES1)
1375 msg_Dbg(p_demux, "detected Stand-Alone Tivo" );
1376 p_sys->tivo_type = TIVO_TYPE_SA;
1377 p_sys->i_Pts_Offset = SA_PTS_OFFSET;
1379 if (p_sys->tivo_series == TIVO_SERIES1)
1380 msg_Dbg(p_demux, "detected DirecTV Tivo" );
1381 p_sys->tivo_type = TIVO_TYPE_DTIVO;
1382 p_sys->i_Pts_Offset = DTIVO_PTS_OFFSET;
1387 i_data_offset += p_hdrs[i].l_rec_size;
1394 /* =========================================================================== */
1395 static int get_chunk_header(demux_t *p_demux)
1397 int i_readSize, i_num_recs;
1399 const uint8_t *p_peek;
1400 demux_sys_t *p_sys = p_demux->p_sys;
1401 int i_payload_size; /* sum of all records' sizes */
1403 msg_Dbg(p_demux, "parsing ty chunk #%d", p_sys->i_cur_chunk );
1405 /* if we have left-over filler space from the last chunk, get that */
1406 if (p_sys->i_stuff_cnt > 0) {
1407 stream_Read( p_demux->s, NULL, p_sys->i_stuff_cnt);
1408 p_sys->i_stuff_cnt = 0;
1411 /* read the TY packet header */
1412 i_readSize = stream_Peek( p_demux->s, &p_peek, 4 );
1413 p_sys->i_cur_chunk++;
1415 if ( (i_readSize < 4) || ( U32_AT(&p_peek[ 0 ] ) == 0 ))
1422 /* check if it's a PART Header */
1423 if( U32_AT( &p_peek[ 0 ] ) == TIVO_PES_FILEID )
1425 /* parse master chunk */
1426 parse_master(p_demux);
1427 return get_chunk_header(p_demux);
1430 /* number of records in chunk (8- or 16-bit number) */
1431 if (p_peek[3] & 0x80)
1433 /* 16 bit rec cnt */
1434 p_sys->i_num_recs = i_num_recs = (p_peek[1] << 8) + p_peek[0];
1435 p_sys->i_seq_rec = (p_peek[3] << 8) + p_peek[2];
1436 if (p_sys->i_seq_rec != 0xffff)
1438 p_sys->i_seq_rec &= ~0x8000;
1443 /* 8 bit reclen - tivo 1.3 format */
1444 p_sys->i_num_recs = i_num_recs = p_peek[0];
1445 p_sys->i_seq_rec = p_peek[1];
1447 p_sys->i_cur_rec = 0;
1448 p_sys->b_first_chunk = VLC_FALSE;
1450 /*msg_Dbg( p_demux, "chunk has %d records", i_num_recs );*/
1452 if (p_sys->rec_hdrs)
1453 free(p_sys->rec_hdrs);
1455 /* skip past the 4 bytes we "peeked" earlier */
1456 stream_Read( p_demux->s, NULL, 4 );
1458 /* read the record headers into a temp buffer */
1459 p_hdr_buf = malloc(i_num_recs * 16);
1460 if (stream_Read(p_demux->s, p_hdr_buf, i_num_recs * 16) < i_num_recs * 16) {
1462 p_sys->eof = VLC_TRUE;
1466 p_sys->rec_hdrs = parse_chunk_headers(p_demux, p_hdr_buf, i_num_recs,
1470 p_sys->i_stuff_cnt = CHUNK_SIZE - 4 -
1471 (p_sys->i_num_recs * 16) - i_payload_size;
1472 if (p_sys->i_stuff_cnt > 0)
1473 msg_Dbg( p_demux, "chunk has %d stuff bytes at end",
1474 p_sys->i_stuff_cnt );
1479 static ty_rec_hdr_t *parse_chunk_headers( demux_t *p_demux, const uint8_t *p_buf,
1480 int i_num_recs, int *pi_payload_size)
1483 ty_rec_hdr_t *p_hdrs, *p_rec_hdr;
1485 *pi_payload_size = 0;
1486 p_hdrs = malloc(i_num_recs * sizeof(ty_rec_hdr_t));
1488 for (i = 0; i < i_num_recs; i++)
1490 const uint8_t *record_header = p_buf + (i * 16);
1491 p_rec_hdr = &p_hdrs[i]; /* for brevity */
1492 p_rec_hdr->rec_type = record_header[3];
1493 p_rec_hdr->subrec_type = record_header[2] & 0x0f;
1494 if ((record_header[ 0 ] & 0x80) == 0x80)
1497 /* marker bit 2 set, so read extended data */
1498 b1 = ( ( ( record_header[ 0 ] & 0x0f ) << 4 ) |
1499 ( ( record_header[ 1 ] & 0xf0 ) >> 4 ) );
1501 b2 = ( ( ( record_header[ 1 ] & 0x0f ) << 4 ) |
1502 ( ( record_header[ 2 ] & 0xf0 ) >> 4 ) );
1505 p_rec_hdr->ex1 = b1;
1506 p_rec_hdr->ex2 = b2;
1507 p_rec_hdr->l_rec_size = 0;
1508 p_rec_hdr->l_ty_pts = 0;
1509 p_rec_hdr->b_ext = VLC_TRUE;
1513 p_rec_hdr->l_rec_size = ( record_header[ 0 ] << 8 |
1514 record_header[ 1 ] ) << 4 | ( record_header[ 2 ] >> 4 );
1515 *pi_payload_size += p_rec_hdr->l_rec_size;
1516 p_rec_hdr->b_ext = VLC_FALSE;
1517 p_rec_hdr->l_ty_pts = U64_AT( &record_header[ 8 ] );
1519 //fprintf( stderr, "parse_chunk_headers[%d] t=0x%x s=%d\n", i, p_rec_hdr->rec_type, p_rec_hdr->subrec_type );
1520 } /* end of record-header loop */