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 "ffmpeg_files/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
89 unsigned char chunk
[ CHUNKSIZE
];
91 unsigned char lastAudio
[ MAX_AUDIO_BUFFER
];
94 int tivoType
; // 1 = SA, 2 = DTiVo
103 tmf_fileParts tmfparts
[ MAX_TMF_PARTS
];
107 off_t
vstream_streamsize( );
108 void ty_ClearOSD( int start
);
110 // ===========================================================================
111 #define TMF_SIG "showing.xml"
113 // ===========================================================================
114 static int ty_tmf_filetoparts( demuxer_t
*demux
, TiVoInfo
*tivo
)
118 stream_seek(demux
->stream
, 0);
120 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Dumping tar contents\n" );
121 while (!demux
->stream
->eof
)
129 if (stream_read(demux
->stream
, header
, 512) < 512)
131 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Read bad\n" );
136 sizestr
= &header
[124];
138 size
= strtol(sizestr
, NULL
, 8);
140 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "name %-20.20s size %-12.12s %d\n",
141 name
, sizestr
, size
);
143 extension
= strrchr(name
, '.');
144 if (extension
&& strcmp(extension
, ".ty") == 0)
146 if ( parts
>= MAX_TMF_PARTS
) {
147 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "ty:tmf too big\n" );
150 tivo
->tmfparts
[ parts
].fileSize
= size
;
151 tivo
->tmfparts
[ parts
].startOffset
= stream_tell(demux
->stream
);
152 tivo
->tmfparts
[ parts
].chunks
= size
/ CHUNKSIZE
;
153 mp_msg(MSGT_DEMUX
, MSGL_DBG3
,
154 "tmf_filetoparts(): index %d, chunks %d\n"
155 "tmf_filetoparts(): size %"PRId64
"\n"
156 "tmf_filetoparts(): startOffset %"PRId64
"\n",
157 parts
, tivo
->tmfparts
[ parts
].chunks
,
158 tivo
->tmfparts
[ parts
].fileSize
, tivo
->tmfparts
[ parts
].startOffset
163 // size rounded up to blocks
164 skip
= (size
+ 511) & ~511;
165 stream_skip(demux
->stream
, skip
);
167 stream_reset(demux
->stream
);
168 tivo
->tmf_totalparts
= parts
;
169 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
170 "tmf_filetoparts(): No More Part Files %d\n", parts
);
176 // ===========================================================================
177 static off_t
tmf_filetooffset(TiVoInfo
*tivo
, int chunk
)
180 for (i
= 0; i
< tivo
->tmf_totalparts
; i
++) {
181 if (chunk
< tivo
->tmfparts
[i
].chunks
)
182 return tivo
->tmfparts
[i
].startOffset
+ chunk
* CHUNKSIZE
;
183 chunk
-= tivo
->tmfparts
[i
].chunks
;
189 // ===========================================================================
190 static int tmf_load_chunk( demuxer_t
*demux
, TiVoInfo
*tivo
,
191 unsigned char *buff
, int readChunk
)
196 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "\ntmf_load_chunk() begin %d\n",
199 fileoffset
= tmf_filetooffset(tivo
, readChunk
);
201 if (fileoffset
== -1 || !stream_seek(demux
->stream
, fileoffset
)) {
202 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "Read past EOF()\n" );
205 count
= stream_read( demux
->stream
, buff
, CHUNKSIZE
);
206 demux
->filepos
= stream_tell( demux
->stream
);
208 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() count %x\n",
211 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
212 "tmf_load_chunk() bytes %x %x %x %x %x %x %x %x\n",
213 buff
[ 0 ], buff
[ 1 ], buff
[ 2 ], buff
[ 3 ],
214 buff
[ 4 ], buff
[ 5 ], buff
[ 6 ], buff
[ 7 ] );
216 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() end\n" );
221 // ===========================================================================
223 // DTiVo MPEG 336, 480, 576, 768
227 #define SERIES1_PTS_LENGTH 11
228 #define SERIES1_PTS_OFFSET 6
229 #define SERIES2_PTS_LENGTH 16
230 #define SERIES2_PTS_OFFSET 9
231 #define AC3_PTS_LENGTH 16
232 #define AC3_PTS_OFFSET 9
234 static int IsValidAudioPacket( int size
, int *ptsOffset
, int *ptsLen
)
237 if ( size
== 1550 || size
== 1552 )
239 *ptsOffset
= AC3_PTS_OFFSET
;
240 *ptsLen
= AC3_PTS_LENGTH
;
245 if ( (size
& 15) == (SERIES1_PTS_LENGTH
& 15) )
247 *ptsOffset
= SERIES1_PTS_OFFSET
;
248 *ptsLen
= SERIES1_PTS_LENGTH
;
251 if ( (size
& 15) == (SERIES2_PTS_LENGTH
& 15) )
253 *ptsOffset
= SERIES2_PTS_OFFSET
;
254 *ptsLen
= SERIES2_PTS_LENGTH
;
257 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Tossing Audio Packet Size %d\n",
263 static int64_t get_ty_pts( unsigned char *buf
)
265 int a
= buf
[0] & 0xe;
266 int b
= AV_RB16(buf
+ 1);
267 int c
= AV_RB16(buf
+ 3);
269 if (!(1 & a
& b
& c
)) // invalid MPEG timestamp
270 return MP_NOPTS_VALUE
;
271 a
>>= 1; b
>>= 1; c
>>= 1;
272 return (((uint64_t)a
) << 30) | (b
<< 15) | c
;
275 static void demux_ty_AddToAudioBuffer( TiVoInfo
*tivo
, unsigned char *buffer
,
278 if ( tivo
->lastAudioEnd
+ size
< MAX_AUDIO_BUFFER
)
280 memcpy( &tivo
->lastAudio
[ tivo
->lastAudioEnd
],
282 tivo
->lastAudioEnd
+= size
;
285 mp_msg( MSGT_DEMUX
, MSGL_ERR
,
286 "ty:WARNING - Would have blown my audio buffer\n" );
289 static void demux_ty_CopyToDemuxPacket( demux_stream_t
*ds
,
290 unsigned char *buffer
, int size
, off_t pos
, int64_t pts
)
292 demux_packet_t
*dp
= new_demux_packet( size
);
293 memcpy( dp
->buffer
, buffer
, size
);
294 if (pts
!= MP_NOPTS_VALUE
)
295 dp
->pts
= pts
/ 90000.0;
298 ds_add_packet( ds
, dp
);
301 static int demux_ty_FindESHeader( uint8_t nal
,
302 unsigned char *buffer
, int bufferSize
)
304 uint32_t search
= 0x00000100 | nal
;
307 uint8_t *end
= p
+ bufferSize
;
312 return p
- buffer
- 4;
317 static void demux_ty_FindESPacket( uint8_t nal
,
318 unsigned char *buffer
, int bufferSize
, int *esOffset1
, int *esOffset2
)
320 *esOffset1
= demux_ty_FindESHeader(nal
, buffer
, bufferSize
);
321 if (*esOffset1
== -1) {
325 buffer
+= *esOffset1
+ 1;
326 bufferSize
-= *esOffset1
+ 1;
327 *esOffset2
= demux_ty_FindESHeader(nal
, buffer
, bufferSize
);
328 if (*esOffset2
!= -1)
329 *esOffset2
+= *esOffset1
+ 1;
332 #define VIDEO_NAL 0xe0
333 #define AUDIO_NAL 0xc0
336 static int demux_ty_fill_buffer( demuxer_t
*demux
, demux_stream_t
*dsds
)
340 int recordsDecoded
= 0;
345 unsigned char *recPtr
;
352 TiVoInfo
*tivo
= demux
->priv
;
353 unsigned char *chunk
= tivo
->chunk
;
355 if ( demux
->stream
->type
== STREAMTYPE_DVD
)
358 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty processing\n" );
360 if( demux
->stream
->eof
) return 0;
362 // ======================================================================
363 // If we haven't figured out the size of the stream, let's do so
364 // ======================================================================
365 #ifdef STREAMTYPE_STREAM_TY
366 if ( demux
->stream
->type
== STREAMTYPE_STREAM_TY
)
368 // The vstream code figures out the exact size of the stream
369 demux
->movi_start
= 0;
370 demux
->movi_end
= vstream_streamsize();
371 tivo
->size
= vstream_streamsize();
376 // If its a local file, try to find the Part Headers, so we can
377 // calculate the ACTUAL stream size
378 // If we can't find it, go off with the file size and hope the
379 // extract program did the "right thing"
380 if ( tivo
->readHeader
== 0 )
383 tivo
->readHeader
= 1;
385 filePos
= demux
->filepos
;
386 stream_seek( demux
->stream
, 0 );
388 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
390 if ( memcmp( chunk
, TMF_SIG
, sizeof( TMF_SIG
) ) == 0 )
392 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Detected a tmf\n" );
394 ty_tmf_filetoparts( demux
, tivo
);
395 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, 0 );
398 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
404 if ( tivo
->tmf
!= 1 )
408 numberParts
= demux
->stream
->end_pos
/ TIVO_PART_LENGTH
;
409 offset
= numberParts
* TIVO_PART_LENGTH
;
411 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty/ty+Number Parts %"PRId64
"\n",
412 (int64_t)numberParts
);
414 if ( offset
+ CHUNKSIZE
< demux
->stream
->end_pos
)
416 stream_seek( demux
->stream
, offset
);
417 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
422 numberParts
= tivo
->tmf_totalparts
;
423 offset
= numberParts
* TIVO_PART_LENGTH
;
424 readSize
= tmf_load_chunk( demux
, tivo
, chunk
,
425 numberParts
* ( TIVO_PART_LENGTH
- CHUNKSIZE
) /
429 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
431 int size
= AV_RB24(chunk
+ 12);
434 tivo
->size
= numberParts
* TIVO_PART_LENGTH
;
436 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
437 "ty:Header Calc Stream Size %"PRId64
"\n", tivo
->size
);
441 if ( demux
->stream
->start_pos
> 0 )
442 filePos
= demux
->stream
->start_pos
;
443 stream_seek( demux
->stream
, filePos
);
444 demux
->filepos
= stream_tell( demux
->stream
);
445 tivo
->whichChunk
= filePos
/ CHUNKSIZE
;
447 demux
->movi_start
= 0;
448 demux
->movi_end
= tivo
->size
;
451 // ======================================================================
452 // Give a clue as to where we are in the stream
453 // ======================================================================
454 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
455 "ty:ty header size %"PRIx64
"\n", (int64_t)tivo
->size
);
456 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
457 "ty:ty which Chunk %d\n", tivo
->whichChunk
);
458 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
459 "ty:file end_pos %"PRIx64
"\n", (int64_t)demux
->stream
->end_pos
);
460 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
461 "\nty:wanted current offset %"PRIx64
"\n", (int64_t)stream_tell( demux
->stream
) );
463 if ( tivo
->size
> 0 && stream_tell( demux
->stream
) > tivo
->size
)
465 demux
->stream
->eof
= 1;
470 if ( tivo
->tmf
!= 1 )
472 // Make sure we are on a 128k boundary
473 if ( demux
->filepos
% CHUNKSIZE
!= 0 )
475 int whichChunk
= demux
->filepos
/ CHUNKSIZE
;
476 if ( demux
->filepos
% CHUNKSIZE
> CHUNKSIZE
/ 2 )
478 stream_seek( demux
->stream
, whichChunk
* CHUNKSIZE
);
481 demux
->filepos
= stream_tell( demux
->stream
);
482 tivo
->whichChunk
= demux
->filepos
/ CHUNKSIZE
;
483 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
484 if ( readSize
!= CHUNKSIZE
)
489 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, tivo
->whichChunk
);
490 if ( readSize
!= CHUNKSIZE
)
494 if (AV_RB32(chunk
) == TIVO_PES_FILEID
)
495 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Skipping PART Header\n" );
496 } while (AV_RB32(chunk
) == TIVO_PES_FILEID
);
498 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
499 "\nty:actual current offset %"PRIx64
"\n", stream_tell( demux
->stream
) -
503 // Let's make a Video Demux Stream for MPlayer
505 if( !demux
->v_streams
[ aid
] ) new_sh_video( demux
, aid
);
506 if( demux
->video
->id
== -1 ) demux
->video
->id
= aid
;
507 if( demux
->video
->id
== aid
)
509 demux_stream_t
*ds
= demux
->video
;
510 if( !ds
->sh
) ds
->sh
= demux
->v_streams
[ aid
];
513 // ======================================================================
514 // Finally, we get to actually parse the chunk
515 // ======================================================================
516 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty parsing a chunk\n" );
517 numberRecs
= chunk
[ 0 ];
518 recPtr
= &chunk
[ 4 ];
519 offset
= numberRecs
* 16 + 4;
520 for ( counter
= 0 ; counter
< numberRecs
; counter
++ )
522 int size
= AV_RB24(recPtr
) >> 4;
523 int type
= recPtr
[ 3 ];
524 int nybbleType
= recPtr
[ 2 ] & 0x0f;
527 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
528 "ty:Record Type %x/%x %d\n", nybbleType
, type
, size
);
530 // ================================================================
532 // ================================================================
535 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
537 int esOffset1
= demux_ty_FindESHeader( VIDEO_NAL
, &chunk
[ offset
],
539 if ( esOffset1
!= -1 )
540 tivo
->lastVideoPTS
= get_ty_pts(
541 &chunk
[ offset
+ esOffset1
+ 9 ] );
543 // Do NOT Pass the PES Header onto the MPEG2 Decode
544 if( nybbleType
!= 0x06 )
545 demux_ty_CopyToDemuxPacket( demux
->video
,
546 &chunk
[ offset
], size
, demux
->filepos
+ offset
,
547 tivo
->lastVideoPTS
);
553 // ================================================================
555 // ================================================================
556 else if ( type
== 0xc0 )
558 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
560 if( demux
->audio
->id
== -1 )
562 if ( nybbleType
== 0x02 )
563 continue; // DTiVo inconclusive, wait for more
564 else if ( nybbleType
== 0x09 )
566 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting AC-3 Audio\n" );
571 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting MPEG Audio\n" );
572 aid
= 0x0; // MPEG Audio
575 demux
->audio
->id
= aid
;
576 if( !demux
->a_streams
[ aid
] ) new_sh_audio( demux
, aid
);
577 if( demux
->audio
->id
== aid
)
579 demux_stream_t
*ds
= demux
->audio
;
582 ds
->sh
= demux
->a_streams
[ aid
];
583 sh_a
= (sh_audio_t
*)ds
->sh
;
584 switch(aid
& 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
585 case 0x00: sh_a
->format
=0x50;break; // mpeg
586 case 0xA0: sh_a
->format
=0x10001;break; // dvd pcm
587 case 0x80: if((aid
& 0xF8) == 0x88) sh_a
->format
=0x2001;//dts
588 else sh_a
->format
=0x2000;break; // ac3
594 aid
= demux
->audio
->id
;
597 // SA DTiVo Audio Data, no PES
598 // ================================================
599 if ( nybbleType
== 0x02 || nybbleType
== 0x04 )
601 if ( nybbleType
== 0x02 && tivo
->tivoType
== 2 )
602 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
606 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
607 "ty:Adding Audio Packet Size %d\n", size
);
608 demux_ty_CopyToDemuxPacket( demux
->audio
,
609 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
610 tivo
->lastAudioPTS
);
614 // 3 - MPEG Audio with PES Header, either SA or DTiVo
615 // 9 - DTiVo AC3 Audio Data with PES Header
616 // ================================================
617 if ( nybbleType
== 0x03 || nybbleType
== 0x09 )
619 int esOffset1
, esOffset2
;
620 if ( nybbleType
== 0x03 )
621 esOffset1
= demux_ty_FindESHeader( AUDIO_NAL
, &chunk
[ offset
],
624 // SA PES Header, No Audio Data
625 // ================================================
626 if ( nybbleType
== 0x03 && esOffset1
== 0 && size
== 16 )
629 tivo
->lastAudioPTS
= get_ty_pts( &chunk
[ offset
+
630 SERIES2_PTS_OFFSET
] );
633 // DTiVo Audio with PES Header
634 // ================================================
638 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
639 demux_ty_FindESPacket( nybbleType
== 9 ? AC3_NAL
: AUDIO_NAL
,
640 tivo
->lastAudio
, tivo
->lastAudioEnd
, &esOffset1
,
643 if ( esOffset1
!= -1 && esOffset2
!= -1 )
645 int packetSize
= esOffset2
- esOffset1
;
649 if ( IsValidAudioPacket( packetSize
, &ptsOffset
,
652 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
653 "ty:Adding DTiVo Audio Packet Size %d\n",
656 tivo
->lastAudioPTS
= get_ty_pts(
657 &tivo
->lastAudio
[ esOffset1
+ ptsOffset
] );
659 if (nybbleType
== 9) headerSize
= 0;
660 demux_ty_CopyToDemuxPacket
663 &tivo
->lastAudio
[ esOffset1
+ headerSize
],
664 packetSize
- headerSize
,
665 demux
->filepos
+ offset
,
671 // Collapse the Audio Buffer
672 tivo
->lastAudioEnd
-= esOffset2
;
673 memmove( &tivo
->lastAudio
[ 0 ],
674 &tivo
->lastAudio
[ esOffset2
],
675 tivo
->lastAudioEnd
);
685 // ================================================================
686 // 1 = Closed Caption
687 // 2 = Extended Data Services
688 // ================================================================
689 else if ( type
== 0x01 || type
== 0x02 )
691 unsigned char lastXDS
[ 16 ];
692 int b
= AV_RB24(recPtr
) >> 4;
695 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:%s %04x\n", type
== 1 ? "CC" : "XDS", b
);
697 lastXDS
[ 0x00 ] = 0x00;
698 lastXDS
[ 0x01 ] = 0x00;
699 lastXDS
[ 0x02 ] = 0x01;
700 lastXDS
[ 0x03 ] = 0xb2;
701 lastXDS
[ 0x04 ] = 'T';
702 lastXDS
[ 0x05 ] = 'Y';
703 lastXDS
[ 0x06 ] = type
;
704 lastXDS
[ 0x07 ] = b
>> 8;
707 demux_ty_CopyToDemuxPacket( demux
->video
, lastXDS
, 0x09,
708 demux
->filepos
+ offset
, tivo
->lastVideoPTS
);
710 // ================================================================
712 // ================================================================
715 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
717 if (type
!= 3 && type
!= 5 && (type
!= 0 || size
> 0)) {
718 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Invalid Type %x\n", type
);
725 if ( errorHeader
> 0 || invalidType
> 0 )
727 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
728 "ty:Error Check - Records %d, Parsed %d, Errors %d + %d\n",
729 numberRecs
, recordsDecoded
, errorHeader
, invalidType
);
731 // Invalid MPEG ES Size Check
732 if ( errorHeader
> numberRecs
/ 2 )
735 // Invalid MPEG Stream Type Check
736 if ( invalidType
> numberRecs
/ 2 )
740 demux
->filepos
= stream_tell( demux
->stream
);
745 static void demux_seek_ty( demuxer_t
*demuxer
, float rel_seek_secs
, float audio_delay
, int flags
)
747 demux_stream_t
*d_audio
= demuxer
->audio
;
748 demux_stream_t
*d_video
= demuxer
->video
;
749 sh_audio_t
*sh_audio
= d_audio
->sh
;
750 sh_video_t
*sh_video
= d_video
->sh
;
753 TiVoInfo
*tivo
= demuxer
->priv
;
755 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Seeking to %7.1f\n", rel_seek_secs
);
757 tivo
->lastAudioEnd
= 0;
758 tivo
->lastAudioPTS
= MP_NOPTS_VALUE
;
759 tivo
->lastVideoPTS
= MP_NOPTS_VALUE
;
761 //================= seek in MPEG ==========================
762 demuxer
->filepos
= stream_tell( demuxer
->stream
);
764 newpos
= ( flags
& SEEK_ABSOLUTE
) ? demuxer
->movi_start
: demuxer
->filepos
;
766 if( flags
& SEEK_FACTOR
)
768 newpos
+= ( demuxer
->movi_end
- demuxer
->movi_start
) * rel_seek_secs
;
772 if( ! sh_video
->i_bps
) // unspecified or VBR
773 newpos
+= 2324 * 75 * rel_seek_secs
; // 174.3 kbyte/sec
775 newpos
+= sh_video
->i_bps
* rel_seek_secs
;
778 if ( newpos
< demuxer
->movi_start
)
780 if( demuxer
->stream
->type
!= STREAMTYPE_VCD
) demuxer
->movi_start
= 0;
781 if( newpos
< demuxer
->movi_start
) newpos
= demuxer
->movi_start
;
784 res
= newpos
/ CHUNKSIZE
;
785 if ( rel_seek_secs
>= 0 )
786 newpos
= ( res
+ 1 ) * CHUNKSIZE
;
788 newpos
= res
* CHUNKSIZE
;
793 tivo
->whichChunk
= newpos
/ CHUNKSIZE
;
795 stream_seek( demuxer
->stream
, newpos
);
798 videobuf_code_len
= 0; // reset ES stream buffer
800 ds_fill_buffer( d_video
);
802 ds_fill_buffer( d_audio
);
807 if( sh_audio
&& !d_audio
->eof
&& d_video
->pts
&& d_audio
->pts
)
809 float a_pts
= d_audio
->pts
;
810 a_pts
+= ( ds_tell_pts( d_audio
) - sh_audio
->a_in_buffer_len
) /
811 (float)sh_audio
->i_bps
;
812 if( d_video
->pts
> a_pts
)
814 skip_audio_frame( sh_audio
); // sync audio
818 i
= sync_video_packet( d_video
);
819 if( i
== 0x1B3 || i
== 0x1B8 ) break; // found it!
820 if( !i
|| !skip_video_packet( d_video
) ) break; // EOF?
826 static int demux_ty_control( demuxer_t
*demuxer
,int cmd
, void *arg
)
828 demux_stream_t
*d_video
= demuxer
->video
;
829 sh_video_t
*sh_video
= d_video
->sh
;
833 case DEMUXER_CTRL_GET_TIME_LENGTH
:
834 if(!sh_video
->i_bps
) // unspecified or VBR
835 return DEMUXER_CTRL_DONTKNOW
;
837 (double)demuxer
->movi_end
-demuxer
->movi_start
/sh_video
->i_bps
;
838 return DEMUXER_CTRL_GUESS
;
840 case DEMUXER_CTRL_GET_PERCENT_POS
:
841 return DEMUXER_CTRL_DONTKNOW
;
843 return DEMUXER_CTRL_NOTIMPL
;
848 static void demux_close_ty( demuxer_t
*demux
)
850 TiVoInfo
*tivo
= demux
->priv
;
857 static int ty_check_file(demuxer_t
* demuxer
)
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_tmsg(MSGT_DEMUXER
,MSGL_INFO
,"MPEG: " "No audio stream found -> no sound.\n");
875 demuxer
->audio
->sh
=NULL
;
877 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
885 const demuxer_desc_t demuxer_desc_mpeg_ty
= {
889 "Christopher R. Wingert",
890 "Demux streams from TiVo",
891 DEMUXER_TYPE_MPEG_TY
,
892 0, // unsafe autodetect
894 demux_ty_fill_buffer
,