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.
38 #include <libavutil/avstring.h>
39 #include <libavutil/intreadwrite.h>
44 #include "libmpcodecs/dec_audio.h"
45 #include "stream/stream.h"
48 #include "demux_ty_osd.h"
52 #include "sub/sub_cc.h"
54 extern int sub_justify
;
57 // 3/c0: audio packet header (PES header)
58 // 4/c0: audio data (S/A only?)
59 // 9/c0: audio packet header, AC-3 audio
61 // 6/e0: video packet header (PES header)
62 // 7/e0: video sequence header start
63 // 8/e0: video I-frame header start
64 // a/e0: video P-frame header start
65 // b/e0: video B-frame header start
66 // c/e0: video GOP header start
67 // e/01: closed-caption data
68 // e/02: Extended data services data
71 #define TIVO_PES_FILEID 0xf5467abd
72 #define TIVO_PART_LENGTH 0x20000000
74 #define CHUNKSIZE ( 128 * 1024 )
75 #define MAX_AUDIO_BUFFER ( 16 * 1024 )
87 #define MAX_TMF_PARTS 16
92 unsigned char chunk
[ CHUNKSIZE
];
94 unsigned char lastAudio
[ MAX_AUDIO_BUFFER
];
97 int tivoType
; // 1 = SA, 2 = DTiVo
100 int64_t lastVideoPTS
;
106 tmf_fileParts tmfparts
[ MAX_TMF_PARTS
];
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 if ( demux
->stream
->type
== STREAMTYPE_VSTREAM
)
367 // The vstream code figures out the exact size of the stream
368 demux
->movi_start
= 0;
369 demux
->movi_end
= demux
->stream
->end_pos
;
370 tivo
->size
= demux
->stream
->end_pos
;
374 // If its a local file, try to find the Part Headers, so we can
375 // calculate the ACTUAL stream size
376 // If we can't find it, go off with the file size and hope the
377 // extract program did the "right thing"
378 if ( tivo
->readHeader
== 0 )
381 tivo
->readHeader
= 1;
383 filePos
= demux
->filepos
;
384 stream_seek( demux
->stream
, 0 );
386 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
388 if ( memcmp( chunk
, TMF_SIG
, sizeof( TMF_SIG
) ) == 0 )
390 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Detected a tmf\n" );
392 ty_tmf_filetoparts( demux
, tivo
);
393 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, 0 );
396 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
402 if ( tivo
->tmf
!= 1 )
406 numberParts
= demux
->stream
->end_pos
/ TIVO_PART_LENGTH
;
407 offset
= numberParts
* TIVO_PART_LENGTH
;
409 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty/ty+Number Parts %"PRId64
"\n",
410 (int64_t)numberParts
);
412 if ( offset
+ CHUNKSIZE
< demux
->stream
->end_pos
)
414 stream_seek( demux
->stream
, offset
);
415 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
420 numberParts
= tivo
->tmf_totalparts
;
421 offset
= numberParts
* TIVO_PART_LENGTH
;
422 readSize
= tmf_load_chunk( demux
, tivo
, chunk
,
423 numberParts
* ( TIVO_PART_LENGTH
- CHUNKSIZE
) /
427 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
429 int size
= AV_RB24(chunk
+ 12);
432 tivo
->size
= numberParts
* TIVO_PART_LENGTH
;
434 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
435 "ty:Header Calc Stream Size %"PRId64
"\n", tivo
->size
);
439 if ( demux
->stream
->start_pos
> 0 )
440 filePos
= demux
->stream
->start_pos
;
441 stream_seek( demux
->stream
, filePos
);
442 demux
->filepos
= stream_tell( demux
->stream
);
443 tivo
->whichChunk
= filePos
/ CHUNKSIZE
;
445 demux
->movi_start
= 0;
446 demux
->movi_end
= tivo
->size
;
449 // ======================================================================
450 // Give a clue as to where we are in the stream
451 // ======================================================================
452 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
453 "ty:ty header size %"PRIx64
"\n", (int64_t)tivo
->size
);
454 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
455 "ty:ty which Chunk %d\n", tivo
->whichChunk
);
456 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
457 "ty:file end_pos %"PRIx64
"\n", (int64_t)demux
->stream
->end_pos
);
458 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
459 "\nty:wanted current offset %"PRIx64
"\n", (int64_t)stream_tell( demux
->stream
) );
461 if ( tivo
->size
> 0 && stream_tell( demux
->stream
) > tivo
->size
)
463 demux
->stream
->eof
= 1;
468 if ( tivo
->tmf
!= 1 )
470 // Make sure we are on a 128k boundary
471 if ( demux
->filepos
% CHUNKSIZE
!= 0 )
473 int whichChunk
= demux
->filepos
/ CHUNKSIZE
;
474 if ( demux
->filepos
% CHUNKSIZE
> CHUNKSIZE
/ 2 )
476 stream_seek( demux
->stream
, whichChunk
* CHUNKSIZE
);
479 demux
->filepos
= stream_tell( demux
->stream
);
480 tivo
->whichChunk
= demux
->filepos
/ CHUNKSIZE
;
481 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
482 if ( readSize
!= CHUNKSIZE
)
487 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, tivo
->whichChunk
);
488 if ( readSize
!= CHUNKSIZE
)
492 if (AV_RB32(chunk
) == TIVO_PES_FILEID
)
493 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Skipping PART Header\n" );
494 } while (AV_RB32(chunk
) == TIVO_PES_FILEID
);
496 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
497 "\nty:actual current offset %"PRIx64
"\n", stream_tell( demux
->stream
) -
501 // Let's make a Video Demux Stream for MPlayer
503 if( !demux
->v_streams
[ aid
] ) new_sh_video( demux
, aid
);
504 if( demux
->video
->id
== -1 ) demux
->video
->id
= aid
;
505 if( demux
->video
->id
== aid
)
507 demux_stream_t
*ds
= demux
->video
;
508 if( !ds
->sh
) ds
->sh
= demux
->v_streams
[ aid
];
511 // ======================================================================
512 // Finally, we get to actually parse the chunk
513 // ======================================================================
514 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty parsing a chunk\n" );
515 numberRecs
= chunk
[ 0 ];
516 recPtr
= &chunk
[ 4 ];
517 offset
= numberRecs
* 16 + 4;
518 for ( counter
= 0 ; counter
< numberRecs
; counter
++ )
520 int size
= AV_RB24(recPtr
) >> 4;
521 int type
= recPtr
[ 3 ];
522 int nybbleType
= recPtr
[ 2 ] & 0x0f;
525 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
526 "ty:Record Type %x/%x %d\n", nybbleType
, type
, size
);
528 // ================================================================
530 // ================================================================
533 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
535 int esOffset1
= demux_ty_FindESHeader( VIDEO_NAL
, &chunk
[ offset
],
537 if ( esOffset1
!= -1 )
538 tivo
->lastVideoPTS
= get_ty_pts(
539 &chunk
[ offset
+ esOffset1
+ 9 ] );
541 // Do NOT Pass the PES Header onto the MPEG2 Decode
542 if( nybbleType
!= 0x06 )
543 demux_ty_CopyToDemuxPacket( demux
->video
,
544 &chunk
[ offset
], size
, demux
->filepos
+ offset
,
545 tivo
->lastVideoPTS
);
551 // ================================================================
553 // ================================================================
554 else if ( type
== 0xc0 )
556 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
558 if( demux
->audio
->id
== -1 )
560 if ( nybbleType
== 0x02 )
561 continue; // DTiVo inconclusive, wait for more
562 else if ( nybbleType
== 0x09 )
564 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting AC-3 Audio\n" );
569 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting MPEG Audio\n" );
570 aid
= 0x0; // MPEG Audio
573 demux
->audio
->id
= aid
;
574 if( !demux
->a_streams
[ aid
] ) new_sh_audio( demux
, aid
);
575 if( demux
->audio
->id
== aid
)
577 demux_stream_t
*ds
= demux
->audio
;
580 ds
->sh
= demux
->a_streams
[ aid
];
581 sh_a
= (sh_audio_t
*)ds
->sh
;
582 switch(aid
& 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
583 case 0x00: sh_a
->format
=0x50;break; // mpeg
584 case 0xA0: sh_a
->format
=0x10001;break; // dvd pcm
585 case 0x80: if((aid
& 0xF8) == 0x88) sh_a
->format
=0x2001;//dts
586 else sh_a
->format
=0x2000;break; // ac3
592 aid
= demux
->audio
->id
;
595 // SA DTiVo Audio Data, no PES
596 // ================================================
597 if ( nybbleType
== 0x02 || nybbleType
== 0x04 )
599 if ( nybbleType
== 0x02 && tivo
->tivoType
== 2 )
600 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
604 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
605 "ty:Adding Audio Packet Size %d\n", size
);
606 demux_ty_CopyToDemuxPacket( demux
->audio
,
607 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
608 tivo
->lastAudioPTS
);
612 // 3 - MPEG Audio with PES Header, either SA or DTiVo
613 // 9 - DTiVo AC3 Audio Data with PES Header
614 // ================================================
615 if ( nybbleType
== 0x03 || nybbleType
== 0x09 )
617 int esOffset1
, esOffset2
;
618 if ( nybbleType
== 0x03 )
619 esOffset1
= demux_ty_FindESHeader( AUDIO_NAL
, &chunk
[ offset
],
622 // SA PES Header, No Audio Data
623 // ================================================
624 if ( nybbleType
== 0x03 && esOffset1
== 0 && size
== 16 )
627 tivo
->lastAudioPTS
= get_ty_pts( &chunk
[ offset
+
628 SERIES2_PTS_OFFSET
] );
631 // DTiVo Audio with PES Header
632 // ================================================
636 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
637 demux_ty_FindESPacket( nybbleType
== 9 ? AC3_NAL
: AUDIO_NAL
,
638 tivo
->lastAudio
, tivo
->lastAudioEnd
, &esOffset1
,
641 if ( esOffset1
!= -1 && esOffset2
!= -1 )
643 int packetSize
= esOffset2
- esOffset1
;
647 if ( IsValidAudioPacket( packetSize
, &ptsOffset
,
650 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
651 "ty:Adding DTiVo Audio Packet Size %d\n",
654 tivo
->lastAudioPTS
= get_ty_pts(
655 &tivo
->lastAudio
[ esOffset1
+ ptsOffset
] );
657 if (nybbleType
== 9) headerSize
= 0;
658 demux_ty_CopyToDemuxPacket
661 &tivo
->lastAudio
[ esOffset1
+ headerSize
],
662 packetSize
- headerSize
,
663 demux
->filepos
+ offset
,
669 // Collapse the Audio Buffer
670 tivo
->lastAudioEnd
-= esOffset2
;
671 memmove( &tivo
->lastAudio
[ 0 ],
672 &tivo
->lastAudio
[ esOffset2
],
673 tivo
->lastAudioEnd
);
683 // ================================================================
684 // 1 = Closed Caption
685 // 2 = Extended Data Services
686 // ================================================================
687 else if ( type
== 0x01 || type
== 0x02 )
689 unsigned char lastXDS
[ 16 ];
690 int b
= AV_RB24(recPtr
) >> 4;
693 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:%s %04x\n", type
== 1 ? "CC" : "XDS", b
);
695 lastXDS
[ 0x00 ] = 0x00;
696 lastXDS
[ 0x01 ] = 0x00;
697 lastXDS
[ 0x02 ] = 0x01;
698 lastXDS
[ 0x03 ] = 0xb2;
699 lastXDS
[ 0x04 ] = 'T';
700 lastXDS
[ 0x05 ] = 'Y';
701 lastXDS
[ 0x06 ] = type
;
702 lastXDS
[ 0x07 ] = b
>> 8;
705 demux_ty_CopyToDemuxPacket( demux
->video
, lastXDS
, 0x09,
706 demux
->filepos
+ offset
, tivo
->lastVideoPTS
);
708 // ================================================================
710 // ================================================================
713 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
715 if (type
!= 3 && type
!= 5 && (type
!= 0 || size
> 0)) {
716 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Invalid Type %x\n", type
);
723 if ( errorHeader
> 0 || invalidType
> 0 )
725 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
726 "ty:Error Check - Records %d, Parsed %d, Errors %d + %d\n",
727 numberRecs
, recordsDecoded
, errorHeader
, invalidType
);
729 // Invalid MPEG ES Size Check
730 if ( errorHeader
> numberRecs
/ 2 )
733 // Invalid MPEG Stream Type Check
734 if ( invalidType
> numberRecs
/ 2 )
738 demux
->filepos
= stream_tell( demux
->stream
);
743 static void demux_seek_ty( demuxer_t
*demuxer
, float rel_seek_secs
, float audio_delay
, int flags
)
745 demux_stream_t
*d_audio
= demuxer
->audio
;
746 demux_stream_t
*d_video
= demuxer
->video
;
747 sh_audio_t
*sh_audio
= d_audio
->sh
;
748 sh_video_t
*sh_video
= d_video
->sh
;
751 TiVoInfo
*tivo
= demuxer
->priv
;
753 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Seeking to %7.1f\n", rel_seek_secs
);
755 tivo
->lastAudioEnd
= 0;
756 tivo
->lastAudioPTS
= MP_NOPTS_VALUE
;
757 tivo
->lastVideoPTS
= MP_NOPTS_VALUE
;
759 //================= seek in MPEG ==========================
760 demuxer
->filepos
= stream_tell( demuxer
->stream
);
762 newpos
= ( flags
& SEEK_ABSOLUTE
) ? demuxer
->movi_start
: demuxer
->filepos
;
764 if( flags
& SEEK_FACTOR
)
766 newpos
+= ( demuxer
->movi_end
- demuxer
->movi_start
) * rel_seek_secs
;
770 if( ! sh_video
->i_bps
) // unspecified or VBR
771 newpos
+= 2324 * 75 * rel_seek_secs
; // 174.3 kbyte/sec
773 newpos
+= sh_video
->i_bps
* rel_seek_secs
;
776 if ( newpos
< demuxer
->movi_start
)
778 if( demuxer
->stream
->type
!= STREAMTYPE_VCD
) demuxer
->movi_start
= 0;
779 if( newpos
< demuxer
->movi_start
) newpos
= demuxer
->movi_start
;
782 res
= newpos
/ CHUNKSIZE
;
783 if ( rel_seek_secs
>= 0 )
784 newpos
= ( res
+ 1 ) * CHUNKSIZE
;
786 newpos
= res
* CHUNKSIZE
;
791 tivo
->whichChunk
= newpos
/ CHUNKSIZE
;
793 stream_seek( demuxer
->stream
, newpos
);
796 videobuf_code_len
= 0; // reset ES stream buffer
798 ds_fill_buffer( d_video
);
800 ds_fill_buffer( d_audio
);
805 if( sh_audio
&& !d_audio
->eof
&& d_video
->pts
&& d_audio
->pts
)
807 float a_pts
= d_audio
->pts
;
808 a_pts
+= ( ds_tell_pts( d_audio
) - sh_audio
->a_in_buffer_len
) /
809 (float)sh_audio
->i_bps
;
810 if( d_video
->pts
> a_pts
)
812 skip_audio_frame( sh_audio
); // sync audio
816 i
= sync_video_packet( d_video
);
817 if( i
== 0x1B3 || i
== 0x1B8 ) break; // found it!
818 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 demuxer
->filepos
= 0;
860 TiVoInfo
*tivo
= calloc(1, sizeof(TiVoInfo
));
861 demuxer
->priv
= tivo
;
862 return ds_fill_buffer(demuxer
->video
) ? DEMUXER_TYPE_MPEG_TY
: 0;
866 static demuxer_t
* demux_open_ty(demuxer_t
* demuxer
)
868 sh_audio_t
*sh_audio
=NULL
;
869 sh_video_t
*sh_video
=NULL
;
871 sh_video
=demuxer
->video
->sh
;sh_video
->ds
=demuxer
->video
;
873 if(demuxer
->audio
->id
!=-2) {
874 if(!ds_fill_buffer(demuxer
->audio
)){
875 mp_msg(MSGT_DEMUXER
, MSGL_INFO
, "MPEG: %s",
876 mp_gtext("No audio stream found -> no sound.\n"));
877 demuxer
->audio
->sh
=NULL
;
879 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
887 const demuxer_desc_t demuxer_desc_mpeg_ty
= {
891 "Christopher R. Wingert",
892 "Demux streams from TiVo",
893 DEMUXER_TYPE_MPEG_TY
,
894 0, // unsafe autodetect
896 demux_ty_fill_buffer
,