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.
42 #include "stream/stream.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/intreadwrite.h"
50 void skip_audio_frame( sh_audio_t
*sh_audio
);
51 extern int sub_justify
;
54 // 3/c0: audio packet header (PES header)
55 // 4/c0: audio data (S/A only?)
56 // 9/c0: audio packet header, AC-3 audio
58 // 6/e0: video packet header (PES header)
59 // 7/e0: video sequence header start
60 // 8/e0: video I-frame header start
61 // a/e0: video P-frame header start
62 // b/e0: video B-frame header start
63 // c/e0: video GOP header start
64 // e/01: closed-caption data
65 // e/02: Extended data services data
68 #define TIVO_PES_FILEID 0xf5467abd
69 #define TIVO_PART_LENGTH 0x20000000
71 #define CHUNKSIZE ( 128 * 1024 )
72 #define MAX_AUDIO_BUFFER ( 16 * 1024 )
84 #define MAX_TMF_PARTS 16
90 unsigned char lastAudio
[ MAX_AUDIO_BUFFER
];
93 int tivoType
; // 1 = SA, 2 = DTiVo
102 tmf_fileParts tmfparts
[ MAX_TMF_PARTS
];
106 off_t
vstream_streamsize( );
107 void ty_ClearOSD( int start
);
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;
341 unsigned char chunk
[ CHUNKSIZE
];
345 unsigned char *recPtr
;
352 TiVoInfo
*tivo
= demux
->priv
;
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 #ifdef STREAMTYPE_STREAM_TY
365 if ( demux
->stream
->type
== STREAMTYPE_STREAM_TY
)
367 // The vstream code figures out the exact size of the stream
368 demux
->movi_start
= 0;
369 demux
->movi_end
= vstream_streamsize();
370 tivo
->size
= vstream_streamsize();
375 // If its a local file, try to find the Part Headers, so we can
376 // calculate the ACTUAL stream size
377 // If we can't find it, go off with the file size and hope the
378 // extract program did the "right thing"
379 if ( tivo
->readHeader
== 0 )
382 tivo
->readHeader
= 1;
384 filePos
= demux
->filepos
;
385 stream_seek( demux
->stream
, 0 );
387 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
389 if ( memcmp( chunk
, TMF_SIG
, sizeof( TMF_SIG
) ) == 0 )
391 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Detected a tmf\n" );
393 ty_tmf_filetoparts( demux
, tivo
);
394 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, 0 );
397 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
403 if ( tivo
->tmf
!= 1 )
407 numberParts
= demux
->stream
->end_pos
/ TIVO_PART_LENGTH
;
408 offset
= numberParts
* TIVO_PART_LENGTH
;
410 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty/ty+Number Parts %"PRId64
"\n",
411 (int64_t)numberParts
);
413 if ( offset
+ CHUNKSIZE
< demux
->stream
->end_pos
)
415 stream_seek( demux
->stream
, offset
);
416 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
421 numberParts
= tivo
->tmf_totalparts
;
422 offset
= numberParts
* TIVO_PART_LENGTH
;
423 readSize
= tmf_load_chunk( demux
, tivo
, chunk
,
424 numberParts
* ( TIVO_PART_LENGTH
- CHUNKSIZE
) /
428 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
430 int size
= AV_RB24(chunk
+ 12);
433 tivo
->size
= numberParts
* TIVO_PART_LENGTH
;
435 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
436 "ty:Header Calc Stream Size %"PRId64
"\n", tivo
->size
);
440 if ( demux
->stream
->start_pos
> 0 )
441 filePos
= demux
->stream
->start_pos
;
442 stream_seek( demux
->stream
, filePos
);
443 demux
->filepos
= stream_tell( demux
->stream
);
444 tivo
->whichChunk
= filePos
/ CHUNKSIZE
;
446 demux
->movi_start
= 0;
447 demux
->movi_end
= tivo
->size
;
450 // ======================================================================
451 // Give a clue as to where we are in the stream
452 // ======================================================================
453 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
454 "ty:ty header size %"PRIx64
"\n", (int64_t)tivo
->size
);
455 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
456 "ty:ty which Chunk %d\n", tivo
->whichChunk
);
457 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
458 "ty:file end_pos %"PRIx64
"\n", (int64_t)demux
->stream
->end_pos
);
459 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
460 "\nty:wanted current offset %"PRIx64
"\n", (int64_t)stream_tell( demux
->stream
) );
462 if ( tivo
->size
> 0 && stream_tell( demux
->stream
) > tivo
->size
)
464 demux
->stream
->eof
= 1;
469 if ( tivo
->tmf
!= 1 )
471 // Make sure we are on a 128k boundary
472 if ( demux
->filepos
% CHUNKSIZE
!= 0 )
474 int whichChunk
= demux
->filepos
/ CHUNKSIZE
;
475 if ( demux
->filepos
% CHUNKSIZE
> CHUNKSIZE
/ 2 )
477 stream_seek( demux
->stream
, whichChunk
* CHUNKSIZE
);
480 demux
->filepos
= stream_tell( demux
->stream
);
481 tivo
->whichChunk
= demux
->filepos
/ CHUNKSIZE
;
482 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
483 if ( readSize
!= CHUNKSIZE
)
488 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, tivo
->whichChunk
);
489 if ( readSize
!= CHUNKSIZE
)
493 if (AV_RB32(chunk
) == TIVO_PES_FILEID
)
494 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Skipping PART Header\n" );
495 } while (AV_RB32(chunk
) == TIVO_PES_FILEID
);
497 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
498 "\nty:actual current offset %"PRIx64
"\n", stream_tell( demux
->stream
) -
502 // Let's make a Video Demux Stream for MPlayer
504 if( !demux
->v_streams
[ aid
] ) new_sh_video( demux
, aid
);
505 if( demux
->video
->id
== -1 ) demux
->video
->id
= aid
;
506 if( demux
->video
->id
== aid
)
508 demux_stream_t
*ds
= demux
->video
;
509 if( !ds
->sh
) ds
->sh
= demux
->v_streams
[ aid
];
512 // ======================================================================
513 // Finally, we get to actually parse the chunk
514 // ======================================================================
515 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty parsing a chunk\n" );
516 numberRecs
= chunk
[ 0 ];
517 recPtr
= &chunk
[ 4 ];
518 offset
= numberRecs
* 16 + 4;
519 for ( counter
= 0 ; counter
< numberRecs
; counter
++ )
521 int size
= AV_RB24(recPtr
) >> 4;
522 int type
= recPtr
[ 3 ];
523 int nybbleType
= recPtr
[ 2 ] & 0x0f;
526 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
527 "ty:Record Type %x/%x %d\n", nybbleType
, type
, size
);
529 // ================================================================
531 // ================================================================
534 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
536 int esOffset1
= demux_ty_FindESHeader( VIDEO_NAL
, &chunk
[ offset
],
538 if ( esOffset1
!= -1 )
539 tivo
->lastVideoPTS
= get_ty_pts(
540 &chunk
[ offset
+ esOffset1
+ 9 ] );
542 // Do NOT Pass the PES Header onto the MPEG2 Decode
543 if( nybbleType
!= 0x06 )
544 demux_ty_CopyToDemuxPacket( demux
->video
,
545 &chunk
[ offset
], size
, demux
->filepos
+ offset
,
546 tivo
->lastVideoPTS
);
552 // ================================================================
554 // ================================================================
555 else if ( type
== 0xc0 )
557 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
559 if( demux
->audio
->id
== -1 )
561 if ( nybbleType
== 0x02 )
562 continue; // DTiVo inconclusive, wait for more
563 else if ( nybbleType
== 0x09 )
565 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting AC-3 Audio\n" );
570 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting MPEG Audio\n" );
571 aid
= 0x0; // MPEG Audio
574 demux
->audio
->id
= aid
;
575 if( !demux
->a_streams
[ aid
] ) new_sh_audio( demux
, aid
);
576 if( demux
->audio
->id
== aid
)
578 demux_stream_t
*ds
= demux
->audio
;
581 ds
->sh
= demux
->a_streams
[ aid
];
582 sh_a
= (sh_audio_t
*)ds
->sh
;
583 switch(aid
& 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
584 case 0x00: sh_a
->format
=0x50;break; // mpeg
585 case 0xA0: sh_a
->format
=0x10001;break; // dvd pcm
586 case 0x80: if((aid
& 0xF8) == 0x88) sh_a
->format
=0x2001;//dts
587 else sh_a
->format
=0x2000;break; // ac3
593 aid
= demux
->audio
->id
;
596 // SA DTiVo Audio Data, no PES
597 // ================================================
598 if ( nybbleType
== 0x02 || nybbleType
== 0x04 )
600 if ( nybbleType
== 0x02 && tivo
->tivoType
== 2 )
601 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
605 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
606 "ty:Adding Audio Packet Size %d\n", size
);
607 demux_ty_CopyToDemuxPacket( demux
->audio
,
608 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
609 tivo
->lastAudioPTS
);
613 // 3 - MPEG Audio with PES Header, either SA or DTiVo
614 // 9 - DTiVo AC3 Audio Data with PES Header
615 // ================================================
616 if ( nybbleType
== 0x03 || nybbleType
== 0x09 )
618 int esOffset1
, esOffset2
;
619 if ( nybbleType
== 0x03 )
620 esOffset1
= demux_ty_FindESHeader( AUDIO_NAL
, &chunk
[ offset
],
623 // SA PES Header, No Audio Data
624 // ================================================
625 if ( nybbleType
== 0x03 && esOffset1
== 0 && size
== 16 )
628 tivo
->lastAudioPTS
= get_ty_pts( &chunk
[ offset
+
629 SERIES2_PTS_OFFSET
] );
632 // DTiVo Audio with PES Header
633 // ================================================
637 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
638 demux_ty_FindESPacket( nybbleType
== 9 ? AC3_NAL
: AUDIO_NAL
,
639 tivo
->lastAudio
, tivo
->lastAudioEnd
, &esOffset1
,
642 if ( esOffset1
!= -1 && esOffset2
!= -1 )
644 int packetSize
= esOffset2
- esOffset1
;
648 if ( IsValidAudioPacket( packetSize
, &ptsOffset
,
651 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
652 "ty:Adding DTiVo Audio Packet Size %d\n",
655 tivo
->lastAudioPTS
= get_ty_pts(
656 &tivo
->lastAudio
[ esOffset1
+ ptsOffset
] );
658 if (nybbleType
== 9) headerSize
= 0;
659 demux_ty_CopyToDemuxPacket
662 &tivo
->lastAudio
[ esOffset1
+ headerSize
],
663 packetSize
- headerSize
,
664 demux
->filepos
+ offset
,
670 // Collapse the Audio Buffer
671 tivo
->lastAudioEnd
-= esOffset2
;
672 memmove( &tivo
->lastAudio
[ 0 ],
673 &tivo
->lastAudio
[ esOffset2
],
674 tivo
->lastAudioEnd
);
684 // ================================================================
685 // 1 = Closed Caption
686 // 2 = Extended Data Services
687 // ================================================================
688 else if ( type
== 0x01 || type
== 0x02 )
690 unsigned char lastXDS
[ 16 ];
691 int b
= AV_RB24(recPtr
) >> 4;
694 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:%s %04x\n", type
== 1 ? "CC" : "XDS", b
);
696 lastXDS
[ 0x00 ] = 0x00;
697 lastXDS
[ 0x01 ] = 0x00;
698 lastXDS
[ 0x02 ] = 0x01;
699 lastXDS
[ 0x03 ] = 0xb2;
700 lastXDS
[ 0x04 ] = 'T';
701 lastXDS
[ 0x05 ] = 'Y';
702 lastXDS
[ 0x06 ] = type
;
703 lastXDS
[ 0x07 ] = b
>> 8;
706 demux_ty_CopyToDemuxPacket( demux
->video
, lastXDS
, 0x09,
707 demux
->filepos
+ offset
, tivo
->lastVideoPTS
);
709 // ================================================================
711 // ================================================================
714 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
716 if (type
!= 3 && type
!= 5 && (type
!= 0 || size
> 0)) {
717 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Invalid Type %x\n", type
);
724 if ( errorHeader
> 0 || invalidType
> 0 )
726 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
727 "ty:Error Check - Records %d, Parsed %d, Errors %d + %d\n",
728 numberRecs
, recordsDecoded
, errorHeader
, invalidType
);
730 // Invalid MPEG ES Size Check
731 if ( errorHeader
> numberRecs
/ 2 )
734 // Invalid MPEG Stream Type Check
735 if ( invalidType
> numberRecs
/ 2 )
739 demux
->filepos
= stream_tell( demux
->stream
);
744 static void demux_seek_ty( demuxer_t
*demuxer
, float rel_seek_secs
, float audio_delay
, int flags
)
746 demux_stream_t
*d_audio
= demuxer
->audio
;
747 demux_stream_t
*d_video
= demuxer
->video
;
748 sh_audio_t
*sh_audio
= d_audio
->sh
;
749 sh_video_t
*sh_video
= d_video
->sh
;
752 TiVoInfo
*tivo
= demuxer
->priv
;
754 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Seeking to %7.1f\n", rel_seek_secs
);
756 tivo
->lastAudioEnd
= 0;
757 tivo
->lastAudioPTS
= MP_NOPTS_VALUE
;
758 tivo
->lastVideoPTS
= MP_NOPTS_VALUE
;
760 //================= seek in MPEG ==========================
761 demuxer
->filepos
= stream_tell( demuxer
->stream
);
763 newpos
= ( flags
& SEEK_ABSOLUTE
) ? demuxer
->movi_start
: demuxer
->filepos
;
765 if( flags
& SEEK_FACTOR
)
767 newpos
+= ( demuxer
->movi_end
- demuxer
->movi_start
) * rel_seek_secs
;
771 if( ! sh_video
->i_bps
) // unspecified or VBR
772 newpos
+= 2324 * 75 * rel_seek_secs
; // 174.3 kbyte/sec
774 newpos
+= sh_video
->i_bps
* rel_seek_secs
;
777 if ( newpos
< demuxer
->movi_start
)
779 if( demuxer
->stream
->type
!= STREAMTYPE_VCD
) demuxer
->movi_start
= 0;
780 if( newpos
< demuxer
->movi_start
) newpos
= demuxer
->movi_start
;
783 res
= newpos
/ CHUNKSIZE
;
784 if ( rel_seek_secs
>= 0 )
785 newpos
= ( res
+ 1 ) * CHUNKSIZE
;
787 newpos
= res
* CHUNKSIZE
;
792 tivo
->whichChunk
= newpos
/ CHUNKSIZE
;
794 stream_seek( demuxer
->stream
, newpos
);
797 videobuf_code_len
= 0; // reset ES stream buffer
799 ds_fill_buffer( d_video
);
801 ds_fill_buffer( d_audio
);
806 if( sh_audio
&& !d_audio
->eof
&& d_video
->pts
&& d_audio
->pts
)
808 float a_pts
= d_audio
->pts
;
809 a_pts
+= ( ds_tell_pts( d_audio
) - sh_audio
->a_in_buffer_len
) /
810 (float)sh_audio
->i_bps
;
811 if( d_video
->pts
> a_pts
)
813 skip_audio_frame( sh_audio
); // sync audio
817 i
= sync_video_packet( d_video
);
818 if( i
== 0x1B3 || i
== 0x1B8 ) break; // found it!
819 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 TiVoInfo
*tivo
= calloc(1, sizeof(TiVoInfo
));
859 demuxer
->priv
= tivo
;
860 return ds_fill_buffer(demuxer
->video
) ? DEMUXER_TYPE_MPEG_TY
: 0;
864 static demuxer_t
* demux_open_ty(demuxer_t
* demuxer
)
866 sh_audio_t
*sh_audio
=NULL
;
867 sh_video_t
*sh_video
=NULL
;
869 sh_video
=demuxer
->video
->sh
;sh_video
->ds
=demuxer
->video
;
871 if(demuxer
->audio
->id
!=-2) {
872 if(!ds_fill_buffer(demuxer
->audio
)){
873 mp_msg(MSGT_DEMUXER
,MSGL_INFO
,"MPEG: " MSGTR_MissingAudioStream
);
874 demuxer
->audio
->sh
=NULL
;
876 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
884 const demuxer_desc_t demuxer_desc_mpeg_ty
= {
888 "Christopher R. Wingert",
889 "Demux streams from TiVo",
890 DEMUXER_TYPE_MPEG_TY
,
891 0, // unsafe autodetect
893 demux_ty_fill_buffer
,