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