2 * tivo@wingert.org, February 2003
4 * Copyright (C) 2003 Christopher R. Wingert
6 * The license covers the portions of this file regarding TiVo additions.
8 * Olaf Beck and Tridge (indirectly) were essential at providing
9 * information regarding the format of the TiVo streams.
11 * However, no code in the following subsection is directly copied from
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
42 #include "stream/stream.h"
48 extern void skip_audio_frame( sh_audio_t
*sh_audio
);
49 extern int sub_justify
;
52 // 3/c0: audio packet header (PES header)
53 // 4/c0: audio data (S/A only?)
54 // 9/c0: audio packet header, AC-3 audio
56 // 6/e0: video packet header (PES header)
57 // 7/e0: video sequence header start
58 // 8/e0: video I-frame header start
59 // a/e0: video P-frame header start
60 // b/e0: video B-frame header start
61 // c/e0: video GOP header start
62 // e/01: closed-caption data
63 // e/02: Extended data services data
66 #define TIVO_PES_FILEID ( 0xf5467abd )
67 #define TIVO_PART_LENGTH ( 0x20000000 )
69 #define CHUNKSIZE ( 128 * 1024 )
70 #define MAX_AUDIO_BUFFER ( 16 * 1024 )
72 #define PTS_MHZ ( 90 )
73 #define PTS_KHZ ( PTS_MHZ * 1000 )
78 typedef struct stmf_fileParts
86 #define MAX_TMF_PARTS ( 16 )
88 typedef struct sTivoInfo
92 unsigned char lastAudio
[ MAX_AUDIO_BUFFER
];
95 int tivoType
; // 1 = SA, 2 = DTiVo
104 unsigned int pesFileId
; // Should be 0xf5467abd
105 int streamType
; // Should be 0x02
106 int chunkSize
; // Should always be 128k
111 tmf_fileParts tmfparts
[ MAX_TMF_PARTS
];
114 off_t tmf_totalchunks
;
118 off_t
vstream_streamsize( );
119 void ty_ClearOSD( int start
);
121 // ===========================================================================
122 #define TMF_SIG "showing.xml"
124 int ty_octaltodecimal( char *num
)
134 for ( i
= ( len
- 1 ) ; i
>= 0 ; i
-- )
136 result
+= ( ( num
[ i
] - '0') * mult
);
144 // ===========================================================================
145 int ty_extensionis( char *name
, char *ext
)
149 if ( strlen( ext
) > strlen( name
) ) return( 0 );
151 ptr
+= ( strlen( name
) - strlen( ext
) );
152 if ( strcmp( ptr
, ext
) == 0 ) return( 1 );
157 // ===========================================================================
158 int ty_tmf_filetoparts( demuxer_t
*demux
, TiVoInfo
*tivo
)
177 totalsize
= demux
->stream
->end_pos
;
180 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Dumping tar contents\n" );
183 ok
= stream_seek( demux
->stream
, offset
);
184 if ( ( offset
+ 512 ) == totalsize
)
191 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Seek bad %"PRId64
"\n", (int64_t)offset
);
196 count
= stream_read( demux
->stream
, header
, 512 );
199 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Read bad\n" );
204 strlcpy( name
, &header
[ 0 ], 100 );
205 strlcpy( sizestr
, &header
[ 124 ], 12 );
206 size
= ty_octaltodecimal( sizestr
);
209 if ( ( size
% 512 ) > 0 ) blocks
++;
210 skip
= ( blocks
+ 1 ) * 512;
212 if ( ( offset
+ skip
) > totalsize
)
214 size
= totalsize
- offset
;
217 isty
= ty_extensionis( name
, ".ty" );
219 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "name %-20.20s size %-12.12s %d %d\n",
220 name
, sizestr
, size
, isty
);
224 tivo
->tmfparts
[ parts
].fileNo
= parts
;
225 // HACK - Ignore last chunk of a Part File
226 // Why? I have no idea.
227 tivo
->tmfparts
[ parts
].fileSize
= size
- 0x20000;
228 tivo
->tmfparts
[ parts
].startOffset
= offset
+ 512;
229 tivo
->tmfparts
[ parts
].chunks
=
230 ( tivo
->tmfparts
[ parts
].fileSize
/ CHUNKSIZE
);
233 MSGT_DEMUX
, MSGL_DBG3
,
234 "tmf_filetoparts(): index %d, file %d, chunks %d\n",
236 tivo
->tmfparts
[ parts
].fileNo
,
237 tivo
->tmfparts
[ parts
].chunks
241 MSGT_DEMUX
, MSGL_DBG3
,
242 "tmf_filetoparts(): size %"PRId64
"\n",
243 tivo
->tmfparts
[ parts
].fileSize
247 MSGT_DEMUX
, MSGL_DBG3
,
248 "tmf_filetoparts(): startOffset %"PRId64
"\n",
249 tivo
->tmfparts
[ parts
].startOffset
252 if ( parts
> MAX_TMF_PARTS
)
254 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "ty:tmf too big\n" );
258 if ( ( offset
+ skip
) > totalsize
)
270 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
271 "WARNING : tmf parse error, not intact\n" );
273 tivo
->tmf_totalparts
= parts
;
274 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
275 "tmf_filetoparts(): No More Part Files %d\n", parts
);
277 tivo
->tmf_totalsize
= 0;
278 tivo
->tmf_totalchunks
= 0;
279 for( index
= 0 ; index
< tivo
->tmf_totalparts
; index
++ )
281 tivo
->tmf_totalsize
+= tivo
->tmfparts
[ index
].fileSize
;
282 tivo
->tmf_totalchunks
+= ( tivo
->tmfparts
[ index
].fileSize
/ CHUNKSIZE
);
284 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
285 "tmf_filetoparts():total size %"PRId64
"\n", (int64_t)tivo
->tmf_totalsize
);
286 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
287 "tmf_filetoparts():total chunks %"PRId64
"\n", (int64_t)tivo
->tmf_totalchunks
);
293 // ===========================================================================
294 void tmf_filetooffset( TiVoInfo
*tivo
, int chunk
, off_t
*offset
)
300 for( index
= 0 ; index
< tivo
->tmf_totalparts
; index
++ )
302 if ( chunk
>= tivo
->tmfparts
[ index
].chunks
)
304 chunk
-= tivo
->tmfparts
[ index
].chunks
;
311 if ( chunk
< tivo
->tmfparts
[ index
].chunks
)
313 *offset
= tivo
->tmfparts
[ index
].startOffset
+
314 ( chunk
* CHUNKSIZE
);
318 MSGT_DEMUX
, MSGL_DBG3
,
319 "tmf_filetooffset() offset %"PRIx64
"\n", *offset
324 // ===========================================================================
325 int tmf_load_chunk( demuxer_t
*demux
, TiVoInfo
*tivo
,
326 unsigned char *buff
, int size
, int readChunk
)
331 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "\ntmf_load_chunk() begin %d\n",
334 if ( tivo
->tmf_totalparts
<= 0 )
339 if ( readChunk
>= tivo
->tmf_totalchunks
)
341 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "Read past EOF()\n" );
345 tmf_filetooffset( tivo
, readChunk
, &fileoffset
);
347 if ( stream_seek( demux
->stream
, fileoffset
) != 1 )
349 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "Read past EOF()\n" );
352 count
= stream_read( demux
->stream
, buff
, size
);
353 demux
->filepos
= stream_tell( demux
->stream
);
355 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() count %x\n",
358 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
359 "tmf_load_chunk() bytes %x %x %x %x %x %x %x %x\n",
360 buff
[ 0 ], buff
[ 1 ], buff
[ 2 ], buff
[ 3 ],
361 buff
[ 4 ], buff
[ 5 ], buff
[ 6 ], buff
[ 7 ] );
363 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() end\n" );
368 // ===========================================================================
370 // DTiVo MPEG 336, 480, 576, 768
374 #define SERIES1_PTS_LENGTH ( 11 )
375 #define SERIES1_PTS_OFFSET ( 6 )
376 #define SERIES2_PTS_LENGTH ( 16 )
377 #define SERIES2_PTS_OFFSET ( 9 )
378 #define AC3_PTS_LENGTH ( 16 )
379 #define AC3_PTS_OFFSET ( 9 )
381 #define NUMBER_DIFFERENT_AUDIO_SIZES ( 7 )
382 static int Series1AudioWithPTS
[ NUMBER_DIFFERENT_AUDIO_SIZES
] =
384 336 + SERIES1_PTS_LENGTH
,
385 384 + SERIES1_PTS_LENGTH
,
386 480 + SERIES1_PTS_LENGTH
,
387 576 + SERIES1_PTS_LENGTH
,
388 768 + SERIES1_PTS_LENGTH
,
389 864 + SERIES1_PTS_LENGTH
391 static int Series2AudioWithPTS
[ NUMBER_DIFFERENT_AUDIO_SIZES
] =
393 336 + SERIES2_PTS_LENGTH
,
394 384 + SERIES2_PTS_LENGTH
,
395 480 + SERIES2_PTS_LENGTH
,
396 576 + SERIES2_PTS_LENGTH
,
397 768 + SERIES2_PTS_LENGTH
,
398 864 + SERIES2_PTS_LENGTH
401 static int IsValidAudioPacket( int size
, int *ptsOffset
, int *ptsLen
)
409 if ( ( size
== 1550 ) || ( size
== 1552 ) )
411 *ptsOffset
= AC3_PTS_OFFSET
;
412 *ptsLen
= AC3_PTS_LENGTH
;
417 for( count
= 0 ; count
< NUMBER_DIFFERENT_AUDIO_SIZES
; count
++ )
419 if ( size
== Series1AudioWithPTS
[ count
] )
421 *ptsOffset
= SERIES1_PTS_OFFSET
;
422 *ptsLen
= SERIES1_PTS_LENGTH
;
426 if ( *ptsOffset
== 0 )
428 for( count
= 0 ; count
< NUMBER_DIFFERENT_AUDIO_SIZES
; count
++ )
430 if ( size
== Series2AudioWithPTS
[ count
] )
432 *ptsOffset
= SERIES2_PTS_OFFSET
;
433 *ptsLen
= SERIES2_PTS_LENGTH
;
438 if ( *ptsOffset
== 0 )
440 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Tossing Audio Packet Size %d\n",
451 static float get_ty_pts( unsigned char *buf
)
456 temp
= ( buf
[ 0 ] & 0xE ) >> 1;
457 result
= ( (float) temp
) * ( (float) ( 1L << 30 ) ) / ( (float)PTS_KHZ
);
459 result
+= ( (float) temp
) * ( (float) ( 1L << 22 ) ) / ( (float)PTS_KHZ
);
460 temp
= ( buf
[ 2 ] & 0xFE ) >> 1;
461 result
+= ( (float) temp
) * ( (float) ( 1L << 15 ) ) / ( (float)PTS_KHZ
);
463 result
+= ( (float) temp
) * ( (float) ( 1L << 7 ) ) / ( (float)PTS_KHZ
);
464 temp
= ( buf
[ 4 ] & 0xFE ) >> 1;
465 result
+= ( (float) temp
) / ( (float)PTS_MHZ
);
470 static void demux_ty_AddToAudioBuffer( TiVoInfo
*tivo
, unsigned char *buffer
,
473 if ( ( tivo
->lastAudioEnd
+ size
) < MAX_AUDIO_BUFFER
)
475 memcpy( &( tivo
->lastAudio
[ tivo
->lastAudioEnd
] ),
477 tivo
->lastAudioEnd
+= size
;
481 mp_msg( MSGT_DEMUX
, MSGL_ERR
,
482 "ty:WARNING - Would have blown my audio buffer\n" );
486 static void demux_ty_CopyToDemuxPacket( int type
, TiVoInfo
*tivo
, demux_stream_t
*ds
,
487 unsigned char *buffer
, int size
, off_t pos
, float pts
)
491 // mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Calling ds_add_packet() %7.1f\n", pts );
492 // printf( "%x %x %x %x\n",
493 // buffer[ 0 ], buffer[ 1 ], buffer[ 2 ], buffer[ 3 ] );
495 dp
= new_demux_packet( size
);
496 memcpy( dp
->buffer
, buffer
, size
);
500 ds_add_packet( ds
, dp
);
504 if ( tivo
->firstVideoPTS
== -1 )
506 tivo
->firstVideoPTS
= pts
;
511 if ( tivo
->firstAudioPTS
== -1 )
513 tivo
->firstAudioPTS
= pts
;
518 static int demux_ty_FindESHeader( unsigned char *header
, int headerSize
,
519 unsigned char *buffer
, int bufferSize
, int *esOffset1
)
524 for( count
= 0 ; count
< bufferSize
; count
++ )
526 if ( ( buffer
[ count
+ 0 ] == header
[ 0 ] ) &&
527 ( buffer
[ count
+ 1 ] == header
[ 1 ] ) &&
528 ( buffer
[ count
+ 2 ] == header
[ 2 ] ) &&
529 ( buffer
[ count
+ 3 ] == header
[ 3 ] ) )
538 static void demux_ty_FindESPacket( unsigned char *header
, int headerSize
,
539 unsigned char *buffer
, int bufferSize
, int *esOffset1
, int *esOffset2
)
546 for( count
= 0 ; count
< bufferSize
; count
++ )
548 if ( ( buffer
[ count
+ 0 ] == header
[ 0 ] ) &&
549 ( buffer
[ count
+ 1 ] == header
[ 1 ] ) &&
550 ( buffer
[ count
+ 2 ] == header
[ 2 ] ) &&
551 ( buffer
[ count
+ 3 ] == header
[ 3 ] ) )
558 if ( *esOffset1
!= -1 )
560 for( count
= *esOffset1
+ 1 ;
561 count
< bufferSize
; count
++ )
563 if ( ( buffer
[ count
+ 0 ] == header
[ 0 ] ) &&
564 ( buffer
[ count
+ 1 ] == header
[ 1 ] ) &&
565 ( buffer
[ count
+ 2 ] == header
[ 2 ] ) &&
566 ( buffer
[ count
+ 3 ] == header
[ 3 ] ) )
575 static int tivobuffer2hostlong( unsigned char *buffer
)
579 buffer
[ 0 ] << 24 | buffer
[ 1 ] << 16 | buffer
[ 2 ] << 8 | buffer
[ 3 ]
583 static unsigned char ty_VideoPacket
[] = { 0x00, 0x00, 0x01, 0xe0 };
584 static unsigned char ty_MPEGAudioPacket
[] = { 0x00, 0x00, 0x01, 0xc0 };
585 static unsigned char ty_AC3AudioPacket
[] = { 0x00, 0x00, 0x01, 0xbd };
587 static int demux_ty_fill_buffer( demuxer_t
*demux
, demux_stream_t
*dsds
)
591 int recordsDecoded
= 0;
594 unsigned char chunk
[ CHUNKSIZE
];
597 unsigned int pesFileId
= 0;
600 unsigned char *recPtr
;
610 demux_stream_t
*ds
= NULL
;
615 unsigned char lastCC
[ 16 ];
616 unsigned char lastXDS
[ 16 ];
620 if ( demux
->stream
->type
== STREAMTYPE_DVD
)
625 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty processing\n" );
626 if ( ( demux
->a_streams
[ MAX_A_STREAMS
- 1 ] ) == 0 )
628 demux
->a_streams
[ MAX_A_STREAMS
- 1 ] = malloc( sizeof( TiVoInfo
) );
629 tivo
= demux
->a_streams
[ MAX_A_STREAMS
- 1 ];
630 memset( tivo
, 0, sizeof( TiVoInfo
) );
631 tivo
->firstAudioPTS
= -1;
632 tivo
->firstVideoPTS
= -1;
636 tivo
= demux
->a_streams
[ MAX_A_STREAMS
- 1 ];
639 if( demux
->stream
->eof
) return 0;
641 // ======================================================================
642 // If we haven't figured out the size of the stream, let's do so
643 // ======================================================================
644 #ifdef STREAMTYPE_STREAM_TY
645 if ( demux
->stream
->type
== STREAMTYPE_STREAM_TY
)
647 // The vstream code figures out the exact size of the stream
648 demux
->movi_start
= 0;
649 demux
->movi_end
= vstream_streamsize();
650 tivo
->size
= vstream_streamsize();
655 // If its a local file, try to find the Part Headers, so we can
656 // calculate the ACTUAL stream size
657 // If we can't find it, go off with the file size and hope the
658 // extract program did the "right thing"
659 if ( tivo
->readHeader
== 0 )
661 tivo
->readHeader
= 1;
662 tivo
->size
= demux
->stream
->end_pos
;
664 filePos
= demux
->filepos
;
665 stream_seek( demux
->stream
, 0 );
667 // mp_msg( MSGT_DEMUX, MSGL_DBG3,
668 // "ty:Reading a chunk %d\n", __LINE__ );
670 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
672 if ( memcmp( chunk
, TMF_SIG
, sizeof( TMF_SIG
) ) == 0 )
674 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Detected a tmf\n" );
676 ty_tmf_filetoparts( demux
, tivo
);
677 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, CHUNKSIZE
, 0 );
680 if ( readSize
== CHUNKSIZE
)
682 tivo
->pesFileId
= tivobuffer2hostlong( &chunk
[ 0x00 ] );
683 tivo
->streamType
= tivobuffer2hostlong( &chunk
[ 0x04 ] );
684 tivo
->chunkSize
= tivobuffer2hostlong( &chunk
[ 0x08 ] );
686 if ( tivo
->pesFileId
== TIVO_PES_FILEID
)
692 if ( tivo
->tmf
!= 1 )
697 numberParts
= demux
->stream
->end_pos
/ TIVO_PART_LENGTH
;
698 offset
= numberParts
* TIVO_PART_LENGTH
;
700 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty/ty+Number Parts %"PRId64
"\n",
701 (int64_t)numberParts
);
703 if ( ( offset
+ CHUNKSIZE
) < demux
->stream
->end_pos
)
705 stream_seek( demux
->stream
, offset
);
706 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
711 numberParts
= tivo
->tmf_totalparts
;
712 offset
= numberParts
* TIVO_PART_LENGTH
;
713 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, CHUNKSIZE
,
714 ( numberParts
* ( TIVO_PART_LENGTH
- 0x20000 ) /
718 if ( readSize
== CHUNKSIZE
)
720 pesFileId
= tivobuffer2hostlong( &chunk
[ 0x00 ] );
721 if ( pesFileId
== TIVO_PES_FILEID
)
723 size
= tivobuffer2hostlong( &chunk
[ 0x0c ] );
727 tivo
->size
= numberParts
* TIVO_PART_LENGTH
;
729 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
730 "ty:Header Calc Stream Size %"PRId64
"\n", tivo
->size
);
735 if ( tivo
->size
> demux
->stream
->end_pos
)
737 tivo
->size
= demux
->stream
->end_pos
;
740 if ( demux
->stream
->start_pos
> 0 )
742 filePos
= demux
->stream
->start_pos
;
744 stream_seek( demux
->stream
, filePos
);
745 demux
->filepos
= stream_tell( demux
->stream
);
746 tivo
->whichChunk
= ( filePos
/ CHUNKSIZE
);
748 demux
->movi_start
= 0;
749 demux
->movi_end
= tivo
->size
;
752 // ======================================================================
753 // Give a clue as to where we are in the stream
754 // ======================================================================
755 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
756 "ty:ty header size %"PRIx64
"\n", (int64_t)tivo
->size
);
757 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
758 "ty:ty which Chunk %d\n", tivo
->whichChunk
);
759 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
760 "ty:file end_pos %"PRIx64
"\n", (int64_t)demux
->stream
->end_pos
);
761 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
762 "\nty:wanted current offset %"PRIx64
"\n", (int64_t)stream_tell( demux
->stream
) );
764 if ( tivo
->size
> 0 )
766 if ( stream_tell( demux
->stream
) > tivo
->size
)
768 demux
->stream
->eof
= 1;
773 if ( tivo
->tmf
!= 1 )
775 // Make sure we are on a 128k boundary
776 if ( ( demux
->filepos
% CHUNKSIZE
) != 0 )
778 whichChunk
= demux
->filepos
/ CHUNKSIZE
;
779 if ( ( demux
->filepos
% CHUNKSIZE
) > ( CHUNKSIZE
/ 2 ) )
783 stream_seek( demux
->stream
, ( whichChunk
* CHUNKSIZE
) );
786 demux
->filepos
= stream_tell( demux
->stream
);
787 tivo
->whichChunk
= demux
->filepos
/ CHUNKSIZE
;
788 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
789 if ( readSize
!= CHUNKSIZE
)
796 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, CHUNKSIZE
,
798 if ( readSize
!= CHUNKSIZE
)
805 // We found a part header, skip it
806 pesFileId
= tivobuffer2hostlong( &chunk
[ 0x00 ] );
807 if( pesFileId
== TIVO_PES_FILEID
)
809 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Skipping PART Header\n" );
810 if ( tivo
->tmf
!= 1 )
812 demux
->filepos
= stream_tell( demux
->stream
);
813 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
817 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, CHUNKSIZE
,
822 if ( readSize
!= CHUNKSIZE
)
827 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
828 "\nty:actual current offset %"PRIx64
"\n", ( stream_tell( demux
->stream
) -
832 // Let's make a Video Demux Stream for MPlayer
834 if( !demux
->v_streams
[ aid
] ) new_sh_video( demux
, aid
);
835 if( demux
->video
->id
== -1 ) demux
->video
->id
= aid
;
836 if( demux
->video
->id
== aid
)
839 if( !ds
->sh
) ds
->sh
= demux
->v_streams
[ aid
];
842 // ======================================================================
843 // Finally, we get to actually parse the chunk
844 // ======================================================================
845 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty parsing a chunk\n" );
846 numberRecs
= chunk
[ 0 ];
847 recPtr
= &chunk
[ 4 ];
848 offset
= ( numberRecs
* 16 ) + 4;
849 for ( counter
= 0 ; counter
< numberRecs
; counter
++ )
851 size
= ( recPtr
[ 0 ] << 8 | recPtr
[ 1 ] ) << 4 | ( recPtr
[ 2 ] >> 4 );
853 nybbleType
= recPtr
[ 2 ] & 0x0f;
856 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
857 "ty:Record Type %x/%x %d\n", nybbleType
, type
, size
);
859 // ================================================================
861 // ================================================================
864 if ( ( size
> 0 ) && ( ( size
+ offset
) <= CHUNKSIZE
) )
867 printf( "Video Chunk Header " );
868 for( count
= 0 ; count
< 24 ; count
++ )
870 printf( "%2.2x ", chunk
[ offset
+ count
] );
874 demux_ty_FindESHeader( ty_VideoPacket
, 4, &chunk
[ offset
],
876 if ( esOffset1
!= -1 )
878 tivo
->lastVideoPTS
= get_ty_pts(
879 &chunk
[ offset
+ esOffset1
+ 9 ] );
880 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Video PTS %7.1f\n",
881 tivo
->lastVideoPTS
);
884 // Do NOT Pass the PES Header onto the MPEG2 Decode
885 if( nybbleType
!= 0x06 )
887 demux_ty_CopyToDemuxPacket( TY_V
, tivo
, demux
->video
,
888 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
889 tivo
->lastVideoPTS
);
898 // ================================================================
900 // ================================================================
901 else if ( type
== 0xc0 )
903 if ( ( size
> 0 ) && ( ( size
+ offset
) <= CHUNKSIZE
) )
906 printf( "Audio Chunk Header " );
907 for( count
= 0 ; count
< 24 ; count
++ )
909 printf( "%2.2x ", chunk
[ offset
+ count
] );
914 if( demux
->audio
->id
== -1 )
916 if ( nybbleType
== 0x02 )
918 continue; // DTiVo inconclusive, wait for more
920 else if ( nybbleType
== 0x09 )
922 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting AC-3 Audio\n" );
927 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting MPEG Audio\n" );
928 aid
= 0x0; // MPEG Audio
931 demux
->audio
->id
= aid
;
932 if( !demux
->a_streams
[ aid
] ) new_sh_audio( demux
, aid
);
933 if( demux
->audio
->id
== aid
)
938 ds
->sh
= demux
->a_streams
[ aid
];
939 sh_a
= (sh_audio_t
*)ds
->sh
;
940 switch(aid
& 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
941 case 0x00: sh_a
->format
=0x50;break; // mpeg
942 case 0xA0: sh_a
->format
=0x10001;break; // dvd pcm
943 case 0x80: if((aid
& 0xF8) == 0x88) sh_a
->format
=0x2001;//dts
944 else sh_a
->format
=0x2000;break; // ac3
950 aid
= demux
->audio
->id
;
953 // SA DTiVo Audio Data, no PES
954 // ================================================
955 if ( nybbleType
== 0x02 )
957 if ( tivo
->tivoType
== 2 )
959 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
964 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
965 "ty:Adding Audio Packet Size %d\n", size
);
966 demux_ty_CopyToDemuxPacket( TY_A
, tivo
, demux
->audio
,
967 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
968 tivo
->lastAudioPTS
);
972 // MPEG Audio with PES Header, either SA or DTiVo
973 // ================================================
974 if ( nybbleType
== 0x03 )
976 demux_ty_FindESHeader( ty_MPEGAudioPacket
, 4, &chunk
[ offset
],
979 // SA PES Header, No Audio Data
980 // ================================================
981 if ( ( esOffset1
== 0 ) && ( size
== 16 ) )
984 tivo
->lastAudioPTS
= get_ty_pts( &chunk
[ offset
+
985 SERIES2_PTS_OFFSET
] );
986 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "SA Audio PTS %7.1f\n",
987 tivo
->lastAudioPTS
);
990 // DTiVo Audio with PES Header
991 // ================================================
995 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
996 demux_ty_FindESPacket( ty_MPEGAudioPacket
, 4,
997 tivo
->lastAudio
, tivo
->lastAudioEnd
, &esOffset1
,
1000 if ( ( esOffset1
!= -1 ) && ( esOffset2
!= -1 ) )
1002 int packetSize
= esOffset2
- esOffset1
;
1006 if ( IsValidAudioPacket( packetSize
, &ptsOffset
,
1009 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
1010 "ty:Adding DTiVo Audio Packet Size %d\n",
1013 tivo
->lastAudioPTS
= get_ty_pts(
1014 &tivo
->lastAudio
[ esOffset1
+ ptsOffset
] );
1015 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
1016 "MPEG Audio PTS %7.1f\n", tivo
->lastAudioPTS
);
1018 demux_ty_CopyToDemuxPacket
1023 &( tivo
->lastAudio
[ esOffset1
+ headerSize
] ),
1024 ( packetSize
- headerSize
),
1025 ( demux
->filepos
+ offset
),
1031 // Collapse the Audio Buffer
1032 memmove( &(tivo
->lastAudio
[ 0 ] ),
1033 &( tivo
->lastAudio
[ esOffset2
] ),
1034 ( tivo
->lastAudioEnd
- esOffset2
) );
1035 tivo
->lastAudioEnd
-= esOffset2
;
1040 // SA Audio with no PES Header
1041 // ================================================
1042 if ( nybbleType
== 0x04 )
1044 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
1045 "ty:Adding Audio Packet Size %d\n", size
);
1046 demux_ty_CopyToDemuxPacket( TY_A
, tivo
, demux
->audio
,
1047 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
1048 tivo
->lastAudioPTS
);
1051 // DTiVo AC3 Audio Data with PES Header
1052 // ================================================
1053 if ( nybbleType
== 0x09 )
1057 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
1058 demux_ty_FindESPacket( ty_AC3AudioPacket
, 4,
1059 tivo
->lastAudio
, tivo
->lastAudioEnd
, &esOffset1
,
1062 if ( ( esOffset1
!= -1 ) && ( esOffset2
!= -1 ) )
1064 int packetSize
= esOffset2
- esOffset1
;
1068 if ( IsValidAudioPacket( packetSize
, &ptsOffset
,
1071 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
1072 "ty:Adding DTiVo Audio Packet Size %d\n",
1075 tivo
->lastAudioPTS
= get_ty_pts(
1076 &tivo
->lastAudio
[ esOffset1
+ ptsOffset
] );
1077 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
1078 "AC3 Audio PTS %7.1f\n", tivo
->lastAudioPTS
);
1080 // AC3 Decoder WANTS the PTS
1081 demux_ty_CopyToDemuxPacket
1086 &( tivo
->lastAudio
[ esOffset1
] ),
1088 ( demux
->filepos
+ offset
),
1094 // Collapse the Audio Buffer
1095 memmove( &(tivo
->lastAudio
[ 0 ] ),
1096 &( tivo
->lastAudio
[ esOffset2
] ),
1097 ( tivo
->lastAudioEnd
- esOffset2
) );
1098 tivo
->lastAudioEnd
-= esOffset2
;
1108 // ================================================================
1110 // ================================================================
1111 else if ( type
== 0x01 )
1116 b1
= ( ( ( recPtr
[ 0 ] & 0x0f ) << 4 ) |
1117 ( ( recPtr
[ 1 ] & 0xf0 ) >> 4 ) );
1119 b2
= ( ( ( recPtr
[ 1 ] & 0x0f ) << 4 ) |
1120 ( ( recPtr
[ 2 ] & 0xf0 ) >> 4 ) );
1123 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:CC %x %x\n", b1
, b2
);
1125 lastCC
[ 0x00 ] = 0x00;
1126 lastCC
[ 0x01 ] = 0x00;
1127 lastCC
[ 0x02 ] = 0x01;
1128 lastCC
[ 0x03 ] = 0xb2;
1129 lastCC
[ 0x04 ] = 'T';
1130 lastCC
[ 0x05 ] = 'Y';
1131 lastCC
[ 0x06 ] = 0x01;
1132 lastCC
[ 0x07 ] = b1
;
1133 lastCC
[ 0x08 ] = b2
;
1134 if ( subcc_enabled
)
1136 demux_ty_CopyToDemuxPacket( TY_V
, tivo
, demux
->video
, lastCC
, 0x09,
1137 ( demux
->filepos
+ offset
), tivo
->lastVideoPTS
);
1140 // ================================================================
1141 // Extended Data Services
1142 // ================================================================
1143 else if ( type
== 0x02 )
1148 b1
= ( ( ( recPtr
[ 0 ] & 0x0f ) << 4 ) |
1149 ( ( recPtr
[ 1 ] & 0xf0 ) >> 4 ) );
1151 b2
= ( ( ( recPtr
[ 1 ] & 0x0f ) << 4 ) |
1152 ( ( recPtr
[ 2 ] & 0xf0 ) >> 4 ) );
1155 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:XDS %x %x\n", b1
, b2
);
1157 lastXDS
[ 0x00 ] = 0x00;
1158 lastXDS
[ 0x01 ] = 0x00;
1159 lastXDS
[ 0x02 ] = 0x01;
1160 lastXDS
[ 0x03 ] = 0xb2;
1161 lastXDS
[ 0x04 ] = 'T';
1162 lastXDS
[ 0x05 ] = 'Y';
1163 lastXDS
[ 0x06 ] = 0x02;
1164 lastXDS
[ 0x07 ] = b1
;
1165 lastXDS
[ 0x08 ] = b2
;
1166 if ( subcc_enabled
)
1168 demux_ty_CopyToDemuxPacket( TY_V
, tivo
, demux
->video
, lastXDS
, 0x09,
1169 ( demux
->filepos
+ offset
), tivo
->lastVideoPTS
);
1172 // ================================================================
1173 // Found a 0x03 on Droid's TiVo, I have no idea what it is
1174 // ================================================================
1175 else if ( type
== 0x03 )
1177 if ( ( size
> 0 ) && ( ( size
+ offset
) <= CHUNKSIZE
) )
1182 // ================================================================
1183 // Found a 0x03 on Hermit's TiVo, I have no idea what it is
1184 // ================================================================
1185 else if ( type
== 0x03 )
1187 if ( ( size
> 0 ) && ( ( size
+ offset
) <= CHUNKSIZE
) )
1192 // ================================================================
1194 // ================================================================
1195 else if ( type
== 0x05 )
1197 if ( ( size
> 0 ) && ( ( size
+ offset
) <= CHUNKSIZE
) )
1204 if ( ( size
> 0 ) && ( ( size
+ offset
) <= CHUNKSIZE
) )
1208 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Invalid Type %x\n", type
);
1214 if ( errorHeader
> 0 || invalidType
> 0 )
1216 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
1217 "ty:Error Check - Records %d, Parsed %d, Errors %d + %d\n",
1218 numberRecs
, recordsDecoded
, errorHeader
, invalidType
);
1220 // Invalid MPEG ES Size Check
1221 if ( errorHeader
> ( numberRecs
/ 2 ) )
1226 // Invalid MPEG Stream Type Check
1227 if ( invalidType
> ( numberRecs
/ 2 ) )
1233 demux
->filepos
= stream_tell( demux
->stream
);
1238 static void demux_seek_ty( demuxer_t
*demuxer
, float rel_seek_secs
, float audio_delay
, int flags
)
1240 demux_stream_t
*d_audio
= demuxer
->audio
;
1241 demux_stream_t
*d_video
= demuxer
->video
;
1242 sh_audio_t
*sh_audio
= d_audio
->sh
;
1243 sh_video_t
*sh_video
= d_video
->sh
;
1248 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Seeking to %7.1f\n", rel_seek_secs
);
1250 if ( ( demuxer
->a_streams
[ MAX_A_STREAMS
- 1 ] ) != 0 )
1252 tivo
= demuxer
->a_streams
[ MAX_A_STREAMS
- 1 ];
1253 tivo
->lastAudioEnd
= 0;
1254 tivo
->lastAudioPTS
= 0;
1255 tivo
->lastVideoPTS
= 0;
1258 //================= seek in MPEG ==========================
1259 demuxer
->filepos
= stream_tell( demuxer
->stream
);
1261 newpos
= ( flags
& 1 ) ? demuxer
->movi_start
: demuxer
->filepos
;
1266 newpos
+= ( demuxer
->movi_end
- demuxer
->movi_start
) * rel_seek_secs
;
1271 if( ! sh_video
->i_bps
) // unspecified or VBR
1273 newpos
+= 2324 * 75 * rel_seek_secs
; // 174.3 kbyte/sec
1277 newpos
+= sh_video
->i_bps
* rel_seek_secs
;
1281 if ( newpos
< demuxer
->movi_start
)
1283 if( demuxer
->stream
->type
!= STREAMTYPE_VCD
) demuxer
->movi_start
= 0;
1284 if( newpos
< demuxer
->movi_start
) newpos
= demuxer
->movi_start
;
1287 res
= newpos
/ CHUNKSIZE
;
1288 if ( rel_seek_secs
>= 0 )
1290 newpos
= ( res
+ 1 ) * CHUNKSIZE
;
1294 newpos
= res
* CHUNKSIZE
;
1302 tivo
->whichChunk
= newpos
/ CHUNKSIZE
;
1304 stream_seek( demuxer
->stream
, newpos
);
1307 videobuf_code_len
= 0; // reset ES stream buffer
1309 ds_fill_buffer( d_video
);
1312 ds_fill_buffer( d_audio
);
1318 if( sh_audio
&& !d_audio
->eof
&& d_video
->pts
&& d_audio
->pts
)
1320 float a_pts
= d_audio
->pts
;
1321 a_pts
+= ( ds_tell_pts( d_audio
) - sh_audio
->a_in_buffer_len
) /
1322 (float)sh_audio
->i_bps
;
1323 if( d_video
->pts
> a_pts
)
1325 skip_audio_frame( sh_audio
); // sync audio
1329 i
= sync_video_packet( d_video
);
1330 if( i
== 0x1B3 || i
== 0x1B8 ) break; // found it!
1331 if( !i
|| !skip_video_packet( d_video
) ) break; // EOF?
1333 if ( subcc_enabled
)
1339 int demux_ty_control( demuxer_t
*demuxer
,int cmd
, void *arg
)
1341 demux_stream_t
*d_video
= demuxer
->video
;
1342 sh_video_t
*sh_video
= d_video
->sh
;
1346 case DEMUXER_CTRL_GET_TIME_LENGTH
:
1347 if(!sh_video
->i_bps
) // unspecified or VBR
1348 return DEMUXER_CTRL_DONTKNOW
;
1350 ((double)demuxer
->movi_end
-demuxer
->movi_start
)/sh_video
->i_bps
;
1351 return DEMUXER_CTRL_GUESS
;
1353 case DEMUXER_CTRL_GET_PERCENT_POS
:
1354 return DEMUXER_CTRL_DONTKNOW
;
1356 return DEMUXER_CTRL_NOTIMPL
;
1361 static void demux_close_ty( demuxer_t
*demux
)
1365 if ( ( demux
->a_streams
[ MAX_A_STREAMS
- 1 ] ) != 0 )
1367 tivo
= demux
->a_streams
[ MAX_A_STREAMS
- 1 ];
1369 demux
->a_streams
[ MAX_A_STREAMS
- 1 ] = 0;
1375 static int ty_check_file(demuxer_t
* demuxer
)
1377 return ds_fill_buffer(demuxer
->video
) ? DEMUXER_TYPE_MPEG_TY
: 0;
1381 static demuxer_t
* demux_open_ty(demuxer_t
* demuxer
)
1383 sh_audio_t
*sh_audio
=NULL
;
1384 sh_video_t
*sh_video
=NULL
;
1386 sh_video
=demuxer
->video
->sh
;sh_video
->ds
=demuxer
->video
;
1388 if(demuxer
->audio
->id
!=-2) {
1389 if(!ds_fill_buffer(demuxer
->audio
)){
1390 mp_msg(MSGT_DEMUXER
,MSGL_INFO
,"MPEG: " MSGTR_MissingAudioStream
);
1391 demuxer
->audio
->sh
=NULL
;
1393 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
1401 demuxer_desc_t demuxer_desc_mpeg_ty
= {
1405 "Christopher R. Wingert",
1406 "Demux streams from TiVo",
1407 DEMUXER_TYPE_MPEG_TY
,
1408 0, // unsafe autodetect
1410 demux_ty_fill_buffer
,