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
14 * This file is part of MPlayer.
16 * MPlayer is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * MPlayer is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License along
27 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
41 #include "libmpcodecs/dec_audio.h"
42 #include "stream/stream.h"
45 #include "demux_ty_osd.h"
49 #include "sub/sub_cc.h"
50 #include "libavutil/avstring.h"
51 #include "ffmpeg_files/intreadwrite.h"
53 extern int sub_justify
;
56 // 3/c0: audio packet header (PES header)
57 // 4/c0: audio data (S/A only?)
58 // 9/c0: audio packet header, AC-3 audio
60 // 6/e0: video packet header (PES header)
61 // 7/e0: video sequence header start
62 // 8/e0: video I-frame header start
63 // a/e0: video P-frame header start
64 // b/e0: video B-frame header start
65 // c/e0: video GOP header start
66 // e/01: closed-caption data
67 // e/02: Extended data services data
70 #define TIVO_PES_FILEID 0xf5467abd
71 #define TIVO_PART_LENGTH 0x20000000
73 #define CHUNKSIZE ( 128 * 1024 )
74 #define MAX_AUDIO_BUFFER ( 16 * 1024 )
86 #define MAX_TMF_PARTS 16
91 unsigned char chunk
[ CHUNKSIZE
];
93 unsigned char lastAudio
[ MAX_AUDIO_BUFFER
];
96 int tivoType
; // 1 = SA, 2 = DTiVo
105 tmf_fileParts tmfparts
[ MAX_TMF_PARTS
];
109 // ===========================================================================
110 #define TMF_SIG "showing.xml"
112 // ===========================================================================
113 static int ty_tmf_filetoparts( demuxer_t
*demux
, TiVoInfo
*tivo
)
117 stream_seek(demux
->stream
, 0);
119 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Dumping tar contents\n" );
120 while (!demux
->stream
->eof
)
128 if (stream_read(demux
->stream
, header
, 512) < 512)
130 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Read bad\n" );
135 sizestr
= &header
[124];
137 size
= strtol(sizestr
, NULL
, 8);
139 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "name %-20.20s size %-12.12s %d\n",
140 name
, sizestr
, size
);
142 extension
= strrchr(name
, '.');
143 if (extension
&& strcmp(extension
, ".ty") == 0)
145 if ( parts
>= MAX_TMF_PARTS
) {
146 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "ty:tmf too big\n" );
149 tivo
->tmfparts
[ parts
].fileSize
= size
;
150 tivo
->tmfparts
[ parts
].startOffset
= stream_tell(demux
->stream
);
151 tivo
->tmfparts
[ parts
].chunks
= size
/ CHUNKSIZE
;
152 mp_msg(MSGT_DEMUX
, MSGL_DBG3
,
153 "tmf_filetoparts(): index %d, chunks %d\n"
154 "tmf_filetoparts(): size %"PRId64
"\n"
155 "tmf_filetoparts(): startOffset %"PRId64
"\n",
156 parts
, tivo
->tmfparts
[ parts
].chunks
,
157 tivo
->tmfparts
[ parts
].fileSize
, tivo
->tmfparts
[ parts
].startOffset
162 // size rounded up to blocks
163 skip
= (size
+ 511) & ~511;
164 stream_skip(demux
->stream
, skip
);
166 stream_reset(demux
->stream
);
167 tivo
->tmf_totalparts
= parts
;
168 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
169 "tmf_filetoparts(): No More Part Files %d\n", parts
);
175 // ===========================================================================
176 static off_t
tmf_filetooffset(TiVoInfo
*tivo
, int chunk
)
179 for (i
= 0; i
< tivo
->tmf_totalparts
; i
++) {
180 if (chunk
< tivo
->tmfparts
[i
].chunks
)
181 return tivo
->tmfparts
[i
].startOffset
+ chunk
* CHUNKSIZE
;
182 chunk
-= tivo
->tmfparts
[i
].chunks
;
188 // ===========================================================================
189 static int tmf_load_chunk( demuxer_t
*demux
, TiVoInfo
*tivo
,
190 unsigned char *buff
, int readChunk
)
195 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "\ntmf_load_chunk() begin %d\n",
198 fileoffset
= tmf_filetooffset(tivo
, readChunk
);
200 if (fileoffset
== -1 || !stream_seek(demux
->stream
, fileoffset
)) {
201 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "Read past EOF()\n" );
204 count
= stream_read( demux
->stream
, buff
, CHUNKSIZE
);
205 demux
->filepos
= stream_tell( demux
->stream
);
207 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() count %x\n",
210 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
211 "tmf_load_chunk() bytes %x %x %x %x %x %x %x %x\n",
212 buff
[ 0 ], buff
[ 1 ], buff
[ 2 ], buff
[ 3 ],
213 buff
[ 4 ], buff
[ 5 ], buff
[ 6 ], buff
[ 7 ] );
215 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() end\n" );
220 // ===========================================================================
222 // DTiVo MPEG 336, 480, 576, 768
226 #define SERIES1_PTS_LENGTH 11
227 #define SERIES1_PTS_OFFSET 6
228 #define SERIES2_PTS_LENGTH 16
229 #define SERIES2_PTS_OFFSET 9
230 #define AC3_PTS_LENGTH 16
231 #define AC3_PTS_OFFSET 9
233 static int IsValidAudioPacket( int size
, int *ptsOffset
, int *ptsLen
)
236 if ( size
== 1550 || size
== 1552 )
238 *ptsOffset
= AC3_PTS_OFFSET
;
239 *ptsLen
= AC3_PTS_LENGTH
;
244 if ( (size
& 15) == (SERIES1_PTS_LENGTH
& 15) )
246 *ptsOffset
= SERIES1_PTS_OFFSET
;
247 *ptsLen
= SERIES1_PTS_LENGTH
;
250 if ( (size
& 15) == (SERIES2_PTS_LENGTH
& 15) )
252 *ptsOffset
= SERIES2_PTS_OFFSET
;
253 *ptsLen
= SERIES2_PTS_LENGTH
;
256 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Tossing Audio Packet Size %d\n",
262 static int64_t get_ty_pts( unsigned char *buf
)
264 int a
= buf
[0] & 0xe;
265 int b
= AV_RB16(buf
+ 1);
266 int c
= AV_RB16(buf
+ 3);
268 if (!(1 & a
& b
& c
)) // invalid MPEG timestamp
269 return MP_NOPTS_VALUE
;
270 a
>>= 1; b
>>= 1; c
>>= 1;
271 return (((uint64_t)a
) << 30) | (b
<< 15) | c
;
274 static void demux_ty_AddToAudioBuffer( TiVoInfo
*tivo
, unsigned char *buffer
,
277 if ( tivo
->lastAudioEnd
+ size
< MAX_AUDIO_BUFFER
)
279 memcpy( &tivo
->lastAudio
[ tivo
->lastAudioEnd
],
281 tivo
->lastAudioEnd
+= size
;
284 mp_msg( MSGT_DEMUX
, MSGL_ERR
,
285 "ty:WARNING - Would have blown my audio buffer\n" );
288 static void demux_ty_CopyToDemuxPacket( demux_stream_t
*ds
,
289 unsigned char *buffer
, int size
, off_t pos
, int64_t pts
)
291 demux_packet_t
*dp
= new_demux_packet( size
);
292 memcpy( dp
->buffer
, buffer
, size
);
293 if (pts
!= MP_NOPTS_VALUE
)
294 dp
->pts
= pts
/ 90000.0;
297 ds_add_packet( ds
, dp
);
300 static int demux_ty_FindESHeader( uint8_t nal
,
301 unsigned char *buffer
, int bufferSize
)
303 uint32_t search
= 0x00000100 | nal
;
306 uint8_t *end
= p
+ bufferSize
;
311 return p
- buffer
- 4;
316 static void demux_ty_FindESPacket( uint8_t nal
,
317 unsigned char *buffer
, int bufferSize
, int *esOffset1
, int *esOffset2
)
319 *esOffset1
= demux_ty_FindESHeader(nal
, buffer
, bufferSize
);
320 if (*esOffset1
== -1) {
324 buffer
+= *esOffset1
+ 1;
325 bufferSize
-= *esOffset1
+ 1;
326 *esOffset2
= demux_ty_FindESHeader(nal
, buffer
, bufferSize
);
327 if (*esOffset2
!= -1)
328 *esOffset2
+= *esOffset1
+ 1;
331 #define VIDEO_NAL 0xe0
332 #define AUDIO_NAL 0xc0
335 static int demux_ty_fill_buffer( demuxer_t
*demux
, demux_stream_t
*dsds
)
339 int recordsDecoded
= 0;
344 unsigned char *recPtr
;
351 TiVoInfo
*tivo
= demux
->priv
;
352 unsigned char *chunk
= tivo
->chunk
;
354 if ( demux
->stream
->type
== STREAMTYPE_DVD
)
357 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty processing\n" );
359 if( demux
->stream
->eof
) return 0;
361 // ======================================================================
362 // If we haven't figured out the size of the stream, let's do so
363 // ======================================================================
364 if ( demux
->stream
->type
== STREAMTYPE_VSTREAM
)
366 // The vstream code figures out the exact size of the stream
367 demux
->movi_start
= 0;
368 demux
->movi_end
= demux
->stream
->end_pos
;
369 tivo
->size
= demux
->stream
->end_pos
;
373 // If its a local file, try to find the Part Headers, so we can
374 // calculate the ACTUAL stream size
375 // If we can't find it, go off with the file size and hope the
376 // extract program did the "right thing"
377 if ( tivo
->readHeader
== 0 )
380 tivo
->readHeader
= 1;
382 filePos
= demux
->filepos
;
383 stream_seek( demux
->stream
, 0 );
385 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
387 if ( memcmp( chunk
, TMF_SIG
, sizeof( TMF_SIG
) ) == 0 )
389 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Detected a tmf\n" );
391 ty_tmf_filetoparts( demux
, tivo
);
392 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, 0 );
395 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
401 if ( tivo
->tmf
!= 1 )
405 numberParts
= demux
->stream
->end_pos
/ TIVO_PART_LENGTH
;
406 offset
= numberParts
* TIVO_PART_LENGTH
;
408 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty/ty+Number Parts %"PRId64
"\n",
409 (int64_t)numberParts
);
411 if ( offset
+ CHUNKSIZE
< demux
->stream
->end_pos
)
413 stream_seek( demux
->stream
, offset
);
414 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
419 numberParts
= tivo
->tmf_totalparts
;
420 offset
= numberParts
* TIVO_PART_LENGTH
;
421 readSize
= tmf_load_chunk( demux
, tivo
, chunk
,
422 numberParts
* ( TIVO_PART_LENGTH
- CHUNKSIZE
) /
426 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
428 int size
= AV_RB24(chunk
+ 12);
431 tivo
->size
= numberParts
* TIVO_PART_LENGTH
;
433 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
434 "ty:Header Calc Stream Size %"PRId64
"\n", tivo
->size
);
438 if ( demux
->stream
->start_pos
> 0 )
439 filePos
= demux
->stream
->start_pos
;
440 stream_seek( demux
->stream
, filePos
);
441 demux
->filepos
= stream_tell( demux
->stream
);
442 tivo
->whichChunk
= filePos
/ CHUNKSIZE
;
444 demux
->movi_start
= 0;
445 demux
->movi_end
= tivo
->size
;
448 // ======================================================================
449 // Give a clue as to where we are in the stream
450 // ======================================================================
451 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
452 "ty:ty header size %"PRIx64
"\n", (int64_t)tivo
->size
);
453 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
454 "ty:ty which Chunk %d\n", tivo
->whichChunk
);
455 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
456 "ty:file end_pos %"PRIx64
"\n", (int64_t)demux
->stream
->end_pos
);
457 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
458 "\nty:wanted current offset %"PRIx64
"\n", (int64_t)stream_tell( demux
->stream
) );
460 if ( tivo
->size
> 0 && stream_tell( demux
->stream
) > tivo
->size
)
462 demux
->stream
->eof
= 1;
467 if ( tivo
->tmf
!= 1 )
469 // Make sure we are on a 128k boundary
470 if ( demux
->filepos
% CHUNKSIZE
!= 0 )
472 int whichChunk
= demux
->filepos
/ CHUNKSIZE
;
473 if ( demux
->filepos
% CHUNKSIZE
> CHUNKSIZE
/ 2 )
475 stream_seek( demux
->stream
, whichChunk
* CHUNKSIZE
);
478 demux
->filepos
= stream_tell( demux
->stream
);
479 tivo
->whichChunk
= demux
->filepos
/ CHUNKSIZE
;
480 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
481 if ( readSize
!= CHUNKSIZE
)
486 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, tivo
->whichChunk
);
487 if ( readSize
!= CHUNKSIZE
)
491 if (AV_RB32(chunk
) == TIVO_PES_FILEID
)
492 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Skipping PART Header\n" );
493 } while (AV_RB32(chunk
) == TIVO_PES_FILEID
);
495 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
496 "\nty:actual current offset %"PRIx64
"\n", stream_tell( demux
->stream
) -
500 // Let's make a Video Demux Stream for MPlayer
502 if( !demux
->v_streams
[ aid
] ) new_sh_video( demux
, aid
);
503 if( demux
->video
->id
== -1 ) demux
->video
->id
= aid
;
504 if( demux
->video
->id
== aid
)
506 demux_stream_t
*ds
= demux
->video
;
507 if( !ds
->sh
) ds
->sh
= demux
->v_streams
[ aid
];
510 // ======================================================================
511 // Finally, we get to actually parse the chunk
512 // ======================================================================
513 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty parsing a chunk\n" );
514 numberRecs
= chunk
[ 0 ];
515 recPtr
= &chunk
[ 4 ];
516 offset
= numberRecs
* 16 + 4;
517 for ( counter
= 0 ; counter
< numberRecs
; counter
++ )
519 int size
= AV_RB24(recPtr
) >> 4;
520 int type
= recPtr
[ 3 ];
521 int nybbleType
= recPtr
[ 2 ] & 0x0f;
524 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
525 "ty:Record Type %x/%x %d\n", nybbleType
, type
, size
);
527 // ================================================================
529 // ================================================================
532 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
534 int esOffset1
= demux_ty_FindESHeader( VIDEO_NAL
, &chunk
[ offset
],
536 if ( esOffset1
!= -1 )
537 tivo
->lastVideoPTS
= get_ty_pts(
538 &chunk
[ offset
+ esOffset1
+ 9 ] );
540 // Do NOT Pass the PES Header onto the MPEG2 Decode
541 if( nybbleType
!= 0x06 )
542 demux_ty_CopyToDemuxPacket( demux
->video
,
543 &chunk
[ offset
], size
, demux
->filepos
+ offset
,
544 tivo
->lastVideoPTS
);
550 // ================================================================
552 // ================================================================
553 else if ( type
== 0xc0 )
555 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
557 if( demux
->audio
->id
== -1 )
559 if ( nybbleType
== 0x02 )
560 continue; // DTiVo inconclusive, wait for more
561 else if ( nybbleType
== 0x09 )
563 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting AC-3 Audio\n" );
568 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting MPEG Audio\n" );
569 aid
= 0x0; // MPEG Audio
572 demux
->audio
->id
= aid
;
573 if( !demux
->a_streams
[ aid
] ) new_sh_audio( demux
, aid
);
574 if( demux
->audio
->id
== aid
)
576 demux_stream_t
*ds
= demux
->audio
;
579 ds
->sh
= demux
->a_streams
[ aid
];
580 sh_a
= (sh_audio_t
*)ds
->sh
;
581 switch(aid
& 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
582 case 0x00: sh_a
->format
=0x50;break; // mpeg
583 case 0xA0: sh_a
->format
=0x10001;break; // dvd pcm
584 case 0x80: if((aid
& 0xF8) == 0x88) sh_a
->format
=0x2001;//dts
585 else sh_a
->format
=0x2000;break; // ac3
591 aid
= demux
->audio
->id
;
594 // SA DTiVo Audio Data, no PES
595 // ================================================
596 if ( nybbleType
== 0x02 || nybbleType
== 0x04 )
598 if ( nybbleType
== 0x02 && tivo
->tivoType
== 2 )
599 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
603 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
604 "ty:Adding Audio Packet Size %d\n", size
);
605 demux_ty_CopyToDemuxPacket( demux
->audio
,
606 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
607 tivo
->lastAudioPTS
);
611 // 3 - MPEG Audio with PES Header, either SA or DTiVo
612 // 9 - DTiVo AC3 Audio Data with PES Header
613 // ================================================
614 if ( nybbleType
== 0x03 || nybbleType
== 0x09 )
616 int esOffset1
, esOffset2
;
617 if ( nybbleType
== 0x03 )
618 esOffset1
= demux_ty_FindESHeader( AUDIO_NAL
, &chunk
[ offset
],
621 // SA PES Header, No Audio Data
622 // ================================================
623 if ( nybbleType
== 0x03 && esOffset1
== 0 && size
== 16 )
626 tivo
->lastAudioPTS
= get_ty_pts( &chunk
[ offset
+
627 SERIES2_PTS_OFFSET
] );
630 // DTiVo Audio with PES Header
631 // ================================================
635 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
636 demux_ty_FindESPacket( nybbleType
== 9 ? AC3_NAL
: AUDIO_NAL
,
637 tivo
->lastAudio
, tivo
->lastAudioEnd
, &esOffset1
,
640 if ( esOffset1
!= -1 && esOffset2
!= -1 )
642 int packetSize
= esOffset2
- esOffset1
;
646 if ( IsValidAudioPacket( packetSize
, &ptsOffset
,
649 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
650 "ty:Adding DTiVo Audio Packet Size %d\n",
653 tivo
->lastAudioPTS
= get_ty_pts(
654 &tivo
->lastAudio
[ esOffset1
+ ptsOffset
] );
656 if (nybbleType
== 9) headerSize
= 0;
657 demux_ty_CopyToDemuxPacket
660 &tivo
->lastAudio
[ esOffset1
+ headerSize
],
661 packetSize
- headerSize
,
662 demux
->filepos
+ offset
,
668 // Collapse the Audio Buffer
669 tivo
->lastAudioEnd
-= esOffset2
;
670 memmove( &tivo
->lastAudio
[ 0 ],
671 &tivo
->lastAudio
[ esOffset2
],
672 tivo
->lastAudioEnd
);
682 // ================================================================
683 // 1 = Closed Caption
684 // 2 = Extended Data Services
685 // ================================================================
686 else if ( type
== 0x01 || type
== 0x02 )
688 unsigned char lastXDS
[ 16 ];
689 int b
= AV_RB24(recPtr
) >> 4;
692 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:%s %04x\n", type
== 1 ? "CC" : "XDS", b
);
694 lastXDS
[ 0x00 ] = 0x00;
695 lastXDS
[ 0x01 ] = 0x00;
696 lastXDS
[ 0x02 ] = 0x01;
697 lastXDS
[ 0x03 ] = 0xb2;
698 lastXDS
[ 0x04 ] = 'T';
699 lastXDS
[ 0x05 ] = 'Y';
700 lastXDS
[ 0x06 ] = type
;
701 lastXDS
[ 0x07 ] = b
>> 8;
704 demux_ty_CopyToDemuxPacket( demux
->video
, lastXDS
, 0x09,
705 demux
->filepos
+ offset
, tivo
->lastVideoPTS
);
707 // ================================================================
709 // ================================================================
712 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
714 if (type
!= 3 && type
!= 5 && (type
!= 0 || size
> 0)) {
715 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Invalid Type %x\n", type
);
722 if ( errorHeader
> 0 || invalidType
> 0 )
724 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
725 "ty:Error Check - Records %d, Parsed %d, Errors %d + %d\n",
726 numberRecs
, recordsDecoded
, errorHeader
, invalidType
);
728 // Invalid MPEG ES Size Check
729 if ( errorHeader
> numberRecs
/ 2 )
732 // Invalid MPEG Stream Type Check
733 if ( invalidType
> numberRecs
/ 2 )
737 demux
->filepos
= stream_tell( demux
->stream
);
742 static void demux_seek_ty( demuxer_t
*demuxer
, float rel_seek_secs
, float audio_delay
, int flags
)
744 demux_stream_t
*d_audio
= demuxer
->audio
;
745 demux_stream_t
*d_video
= demuxer
->video
;
746 sh_audio_t
*sh_audio
= d_audio
->sh
;
747 sh_video_t
*sh_video
= d_video
->sh
;
750 TiVoInfo
*tivo
= demuxer
->priv
;
752 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Seeking to %7.1f\n", rel_seek_secs
);
754 tivo
->lastAudioEnd
= 0;
755 tivo
->lastAudioPTS
= MP_NOPTS_VALUE
;
756 tivo
->lastVideoPTS
= MP_NOPTS_VALUE
;
758 //================= seek in MPEG ==========================
759 demuxer
->filepos
= stream_tell( demuxer
->stream
);
761 newpos
= ( flags
& SEEK_ABSOLUTE
) ? demuxer
->movi_start
: demuxer
->filepos
;
763 if( flags
& SEEK_FACTOR
)
765 newpos
+= ( demuxer
->movi_end
- demuxer
->movi_start
) * rel_seek_secs
;
769 if( ! sh_video
->i_bps
) // unspecified or VBR
770 newpos
+= 2324 * 75 * rel_seek_secs
; // 174.3 kbyte/sec
772 newpos
+= sh_video
->i_bps
* rel_seek_secs
;
775 if ( newpos
< demuxer
->movi_start
)
777 if( demuxer
->stream
->type
!= STREAMTYPE_VCD
) demuxer
->movi_start
= 0;
778 if( newpos
< demuxer
->movi_start
) newpos
= demuxer
->movi_start
;
781 res
= newpos
/ CHUNKSIZE
;
782 if ( rel_seek_secs
>= 0 )
783 newpos
= ( res
+ 1 ) * CHUNKSIZE
;
785 newpos
= res
* CHUNKSIZE
;
790 tivo
->whichChunk
= newpos
/ CHUNKSIZE
;
792 stream_seek( demuxer
->stream
, newpos
);
795 videobuf_code_len
= 0; // reset ES stream buffer
797 ds_fill_buffer( d_video
);
799 ds_fill_buffer( d_audio
);
804 if( sh_audio
&& !d_audio
->eof
&& d_video
->pts
&& d_audio
->pts
)
806 float a_pts
= d_audio
->pts
;
807 a_pts
+= ( ds_tell_pts( d_audio
) - sh_audio
->a_in_buffer_len
) /
808 (float)sh_audio
->i_bps
;
809 if( d_video
->pts
> a_pts
)
811 skip_audio_frame( sh_audio
); // sync audio
815 i
= sync_video_packet( d_video
);
816 if( i
== 0x1B3 || i
== 0x1B8 ) break; // found it!
817 if( !i
|| !skip_video_packet( d_video
) ) break; // EOF?
825 static int demux_ty_control( demuxer_t
*demuxer
,int cmd
, void *arg
)
827 demux_stream_t
*d_video
= demuxer
->video
;
828 sh_video_t
*sh_video
= d_video
->sh
;
832 case DEMUXER_CTRL_GET_TIME_LENGTH
:
833 if(!sh_video
->i_bps
) // unspecified or VBR
834 return DEMUXER_CTRL_DONTKNOW
;
836 (double)demuxer
->movi_end
-demuxer
->movi_start
/sh_video
->i_bps
;
837 return DEMUXER_CTRL_GUESS
;
839 case DEMUXER_CTRL_GET_PERCENT_POS
:
840 return DEMUXER_CTRL_DONTKNOW
;
842 return DEMUXER_CTRL_NOTIMPL
;
847 static void demux_close_ty( demuxer_t
*demux
)
849 TiVoInfo
*tivo
= demux
->priv
;
856 static int ty_check_file(demuxer_t
* demuxer
)
858 demuxer
->filepos
= 0;
859 TiVoInfo
*tivo
= calloc(1, sizeof(TiVoInfo
));
860 demuxer
->priv
= tivo
;
861 return ds_fill_buffer(demuxer
->video
) ? DEMUXER_TYPE_MPEG_TY
: 0;
865 static demuxer_t
* demux_open_ty(demuxer_t
* demuxer
)
867 sh_audio_t
*sh_audio
=NULL
;
868 sh_video_t
*sh_video
=NULL
;
870 sh_video
=demuxer
->video
->sh
;sh_video
->ds
=demuxer
->video
;
872 if(demuxer
->audio
->id
!=-2) {
873 if(!ds_fill_buffer(demuxer
->audio
)){
874 mp_msg(MSGT_DEMUXER
, MSGL_INFO
, "MPEG: %s",
875 mp_gtext("No audio stream found -> no sound.\n"));
876 demuxer
->audio
->sh
=NULL
;
878 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
886 const demuxer_desc_t demuxer_desc_mpeg_ty
= {
890 "Christopher R. Wingert",
891 "Demux streams from TiVo",
892 DEMUXER_TYPE_MPEG_TY
,
893 0, // unsafe autodetect
895 demux_ty_fill_buffer
,