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 "stream/stream.h"
43 #include "demux_ty_osd.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 // ===========================================================================
108 #define TMF_SIG "showing.xml"
110 // ===========================================================================
111 static int ty_tmf_filetoparts( demuxer_t
*demux
, TiVoInfo
*tivo
)
115 stream_seek(demux
->stream
, 0);
117 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Dumping tar contents\n" );
118 while (!demux
->stream
->eof
)
126 if (stream_read(demux
->stream
, header
, 512) < 512)
128 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "Read bad\n" );
133 sizestr
= &header
[124];
135 size
= strtol(sizestr
, NULL
, 8);
137 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "name %-20.20s size %-12.12s %d\n",
138 name
, sizestr
, size
);
140 extension
= strrchr(name
, '.');
141 if (extension
&& strcmp(extension
, ".ty") == 0)
143 if ( parts
>= MAX_TMF_PARTS
) {
144 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "ty:tmf too big\n" );
147 tivo
->tmfparts
[ parts
].fileSize
= size
;
148 tivo
->tmfparts
[ parts
].startOffset
= stream_tell(demux
->stream
);
149 tivo
->tmfparts
[ parts
].chunks
= size
/ CHUNKSIZE
;
150 mp_msg(MSGT_DEMUX
, MSGL_DBG3
,
151 "tmf_filetoparts(): index %d, chunks %d\n"
152 "tmf_filetoparts(): size %"PRId64
"\n"
153 "tmf_filetoparts(): startOffset %"PRId64
"\n",
154 parts
, tivo
->tmfparts
[ parts
].chunks
,
155 tivo
->tmfparts
[ parts
].fileSize
, tivo
->tmfparts
[ parts
].startOffset
160 // size rounded up to blocks
161 skip
= (size
+ 511) & ~511;
162 stream_skip(demux
->stream
, skip
);
164 stream_reset(demux
->stream
);
165 tivo
->tmf_totalparts
= parts
;
166 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
167 "tmf_filetoparts(): No More Part Files %d\n", parts
);
173 // ===========================================================================
174 static off_t
tmf_filetooffset(TiVoInfo
*tivo
, int chunk
)
177 for (i
= 0; i
< tivo
->tmf_totalparts
; i
++) {
178 if (chunk
< tivo
->tmfparts
[i
].chunks
)
179 return tivo
->tmfparts
[i
].startOffset
+ chunk
* CHUNKSIZE
;
180 chunk
-= tivo
->tmfparts
[i
].chunks
;
186 // ===========================================================================
187 static int tmf_load_chunk( demuxer_t
*demux
, TiVoInfo
*tivo
,
188 unsigned char *buff
, int readChunk
)
193 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "\ntmf_load_chunk() begin %d\n",
196 fileoffset
= tmf_filetooffset(tivo
, readChunk
);
198 if (fileoffset
== -1 || !stream_seek(demux
->stream
, fileoffset
)) {
199 mp_msg( MSGT_DEMUX
, MSGL_ERR
, "Read past EOF()\n" );
202 count
= stream_read( demux
->stream
, buff
, CHUNKSIZE
);
203 demux
->filepos
= stream_tell( demux
->stream
);
205 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() count %x\n",
208 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
209 "tmf_load_chunk() bytes %x %x %x %x %x %x %x %x\n",
210 buff
[ 0 ], buff
[ 1 ], buff
[ 2 ], buff
[ 3 ],
211 buff
[ 4 ], buff
[ 5 ], buff
[ 6 ], buff
[ 7 ] );
213 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "tmf_load_chunk() end\n" );
218 // ===========================================================================
220 // DTiVo MPEG 336, 480, 576, 768
224 #define SERIES1_PTS_LENGTH 11
225 #define SERIES1_PTS_OFFSET 6
226 #define SERIES2_PTS_LENGTH 16
227 #define SERIES2_PTS_OFFSET 9
228 #define AC3_PTS_LENGTH 16
229 #define AC3_PTS_OFFSET 9
231 static int IsValidAudioPacket( int size
, int *ptsOffset
, int *ptsLen
)
234 if ( size
== 1550 || size
== 1552 )
236 *ptsOffset
= AC3_PTS_OFFSET
;
237 *ptsLen
= AC3_PTS_LENGTH
;
242 if ( (size
& 15) == (SERIES1_PTS_LENGTH
& 15) )
244 *ptsOffset
= SERIES1_PTS_OFFSET
;
245 *ptsLen
= SERIES1_PTS_LENGTH
;
248 if ( (size
& 15) == (SERIES2_PTS_LENGTH
& 15) )
250 *ptsOffset
= SERIES2_PTS_OFFSET
;
251 *ptsLen
= SERIES2_PTS_LENGTH
;
254 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Tossing Audio Packet Size %d\n",
260 static int64_t get_ty_pts( unsigned char *buf
)
262 int a
= buf
[0] & 0xe;
263 int b
= AV_RB16(buf
+ 1);
264 int c
= AV_RB16(buf
+ 3);
266 if (!(1 & a
& b
& c
)) // invalid MPEG timestamp
267 return MP_NOPTS_VALUE
;
268 a
>>= 1; b
>>= 1; c
>>= 1;
269 return (((uint64_t)a
) << 30) | (b
<< 15) | c
;
272 static void demux_ty_AddToAudioBuffer( TiVoInfo
*tivo
, unsigned char *buffer
,
275 if ( tivo
->lastAudioEnd
+ size
< MAX_AUDIO_BUFFER
)
277 memcpy( &tivo
->lastAudio
[ tivo
->lastAudioEnd
],
279 tivo
->lastAudioEnd
+= size
;
282 mp_msg( MSGT_DEMUX
, MSGL_ERR
,
283 "ty:WARNING - Would have blown my audio buffer\n" );
286 static void demux_ty_CopyToDemuxPacket( demux_stream_t
*ds
,
287 unsigned char *buffer
, int size
, off_t pos
, int64_t pts
)
289 demux_packet_t
*dp
= new_demux_packet( size
);
290 memcpy( dp
->buffer
, buffer
, size
);
291 if (pts
!= MP_NOPTS_VALUE
)
292 dp
->pts
= pts
/ 90000.0;
295 ds_add_packet( ds
, dp
);
298 static int demux_ty_FindESHeader( uint8_t nal
,
299 unsigned char *buffer
, int bufferSize
)
301 uint32_t search
= 0x00000100 | nal
;
304 uint8_t *end
= p
+ bufferSize
;
309 return p
- buffer
- 4;
314 static void demux_ty_FindESPacket( uint8_t nal
,
315 unsigned char *buffer
, int bufferSize
, int *esOffset1
, int *esOffset2
)
317 *esOffset1
= demux_ty_FindESHeader(nal
, buffer
, bufferSize
);
318 if (*esOffset1
== -1) {
322 buffer
+= *esOffset1
+ 1;
323 bufferSize
-= *esOffset1
+ 1;
324 *esOffset2
= demux_ty_FindESHeader(nal
, buffer
, bufferSize
);
325 if (*esOffset2
!= -1)
326 *esOffset2
+= *esOffset1
+ 1;
329 #define VIDEO_NAL 0xe0
330 #define AUDIO_NAL 0xc0
333 static int demux_ty_fill_buffer( demuxer_t
*demux
, demux_stream_t
*dsds
)
337 int recordsDecoded
= 0;
342 unsigned char *recPtr
;
349 TiVoInfo
*tivo
= demux
->priv
;
350 unsigned char *chunk
= tivo
->chunk
;
352 if ( demux
->stream
->type
== STREAMTYPE_DVD
)
355 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty processing\n" );
357 if( demux
->stream
->eof
) return 0;
359 // ======================================================================
360 // If we haven't figured out the size of the stream, let's do so
361 // ======================================================================
362 if ( demux
->stream
->type
== STREAMTYPE_VSTREAM
)
364 // The vstream code figures out the exact size of the stream
365 demux
->movi_start
= 0;
366 demux
->movi_end
= demux
->stream
->end_pos
;
367 tivo
->size
= demux
->stream
->end_pos
;
371 // If its a local file, try to find the Part Headers, so we can
372 // calculate the ACTUAL stream size
373 // If we can't find it, go off with the file size and hope the
374 // extract program did the "right thing"
375 if ( tivo
->readHeader
== 0 )
378 tivo
->readHeader
= 1;
380 filePos
= demux
->filepos
;
381 stream_seek( demux
->stream
, 0 );
383 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
385 if ( memcmp( chunk
, TMF_SIG
, sizeof( TMF_SIG
) ) == 0 )
387 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Detected a tmf\n" );
389 ty_tmf_filetoparts( demux
, tivo
);
390 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, 0 );
393 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
399 if ( tivo
->tmf
!= 1 )
403 numberParts
= demux
->stream
->end_pos
/ TIVO_PART_LENGTH
;
404 offset
= numberParts
* TIVO_PART_LENGTH
;
406 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty/ty+Number Parts %"PRId64
"\n",
407 (int64_t)numberParts
);
409 if ( offset
+ CHUNKSIZE
< demux
->stream
->end_pos
)
411 stream_seek( demux
->stream
, offset
);
412 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
417 numberParts
= tivo
->tmf_totalparts
;
418 offset
= numberParts
* TIVO_PART_LENGTH
;
419 readSize
= tmf_load_chunk( demux
, tivo
, chunk
,
420 numberParts
* ( TIVO_PART_LENGTH
- CHUNKSIZE
) /
424 if ( readSize
== CHUNKSIZE
&& AV_RB32(chunk
) == TIVO_PES_FILEID
)
426 int size
= AV_RB24(chunk
+ 12);
429 tivo
->size
= numberParts
* TIVO_PART_LENGTH
;
431 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
432 "ty:Header Calc Stream Size %"PRId64
"\n", tivo
->size
);
436 if ( demux
->stream
->start_pos
> 0 )
437 filePos
= demux
->stream
->start_pos
;
438 stream_seek( demux
->stream
, filePos
);
439 demux
->filepos
= stream_tell( demux
->stream
);
440 tivo
->whichChunk
= filePos
/ CHUNKSIZE
;
442 demux
->movi_start
= 0;
443 demux
->movi_end
= tivo
->size
;
446 // ======================================================================
447 // Give a clue as to where we are in the stream
448 // ======================================================================
449 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
450 "ty:ty header size %"PRIx64
"\n", (int64_t)tivo
->size
);
451 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
452 "ty:ty which Chunk %d\n", tivo
->whichChunk
);
453 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
454 "ty:file end_pos %"PRIx64
"\n", (int64_t)demux
->stream
->end_pos
);
455 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
456 "\nty:wanted current offset %"PRIx64
"\n", (int64_t)stream_tell( demux
->stream
) );
458 if ( tivo
->size
> 0 && stream_tell( demux
->stream
) > tivo
->size
)
460 demux
->stream
->eof
= 1;
465 if ( tivo
->tmf
!= 1 )
467 // Make sure we are on a 128k boundary
468 if ( demux
->filepos
% CHUNKSIZE
!= 0 )
470 int whichChunk
= demux
->filepos
/ CHUNKSIZE
;
471 if ( demux
->filepos
% CHUNKSIZE
> CHUNKSIZE
/ 2 )
473 stream_seek( demux
->stream
, whichChunk
* CHUNKSIZE
);
476 demux
->filepos
= stream_tell( demux
->stream
);
477 tivo
->whichChunk
= demux
->filepos
/ CHUNKSIZE
;
478 readSize
= stream_read( demux
->stream
, chunk
, CHUNKSIZE
);
479 if ( readSize
!= CHUNKSIZE
)
484 readSize
= tmf_load_chunk( demux
, tivo
, chunk
, tivo
->whichChunk
);
485 if ( readSize
!= CHUNKSIZE
)
489 if (AV_RB32(chunk
) == TIVO_PES_FILEID
)
490 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Skipping PART Header\n" );
491 } while (AV_RB32(chunk
) == TIVO_PES_FILEID
);
493 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
494 "\nty:actual current offset %"PRIx64
"\n", stream_tell( demux
->stream
) -
498 // Let's make a Video Demux Stream for MPlayer
500 if( !demux
->v_streams
[ aid
] ) new_sh_video( demux
, aid
);
501 if( demux
->video
->id
== -1 ) demux
->video
->id
= aid
;
502 if( demux
->video
->id
== aid
)
504 demux_stream_t
*ds
= demux
->video
;
505 if( !ds
->sh
) ds
->sh
= demux
->v_streams
[ aid
];
508 // ======================================================================
509 // Finally, we get to actually parse the chunk
510 // ======================================================================
511 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:ty parsing a chunk\n" );
512 numberRecs
= chunk
[ 0 ];
513 recPtr
= &chunk
[ 4 ];
514 offset
= numberRecs
* 16 + 4;
515 for ( counter
= 0 ; counter
< numberRecs
; counter
++ )
517 int size
= AV_RB24(recPtr
) >> 4;
518 int type
= recPtr
[ 3 ];
519 int nybbleType
= recPtr
[ 2 ] & 0x0f;
522 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
523 "ty:Record Type %x/%x %d\n", nybbleType
, type
, size
);
525 // ================================================================
527 // ================================================================
530 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
532 int esOffset1
= demux_ty_FindESHeader( VIDEO_NAL
, &chunk
[ offset
],
534 if ( esOffset1
!= -1 )
535 tivo
->lastVideoPTS
= get_ty_pts(
536 &chunk
[ offset
+ esOffset1
+ 9 ] );
538 // Do NOT Pass the PES Header onto the MPEG2 Decode
539 if( nybbleType
!= 0x06 )
540 demux_ty_CopyToDemuxPacket( demux
->video
,
541 &chunk
[ offset
], size
, demux
->filepos
+ offset
,
542 tivo
->lastVideoPTS
);
548 // ================================================================
550 // ================================================================
551 else if ( type
== 0xc0 )
553 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
555 if( demux
->audio
->id
== -1 )
557 if ( nybbleType
== 0x02 )
558 continue; // DTiVo inconclusive, wait for more
559 else if ( nybbleType
== 0x09 )
561 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting AC-3 Audio\n" );
566 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Setting MPEG Audio\n" );
567 aid
= 0x0; // MPEG Audio
570 demux
->audio
->id
= aid
;
571 if( !demux
->a_streams
[ aid
] ) new_sh_audio( demux
, aid
);
572 if( demux
->audio
->id
== aid
)
574 demux_stream_t
*ds
= demux
->audio
;
577 ds
->sh
= demux
->a_streams
[ aid
];
578 sh_a
= (sh_audio_t
*)ds
->sh
;
579 switch(aid
& 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
580 case 0x00: sh_a
->format
=0x50;break; // mpeg
581 case 0xA0: sh_a
->format
=0x10001;break; // dvd pcm
582 case 0x80: if((aid
& 0xF8) == 0x88) sh_a
->format
=0x2001;//dts
583 else sh_a
->format
=0x2000;break; // ac3
589 aid
= demux
->audio
->id
;
592 // SA DTiVo Audio Data, no PES
593 // ================================================
594 if ( nybbleType
== 0x02 || nybbleType
== 0x04 )
596 if ( nybbleType
== 0x02 && tivo
->tivoType
== 2 )
597 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
601 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
602 "ty:Adding Audio Packet Size %d\n", size
);
603 demux_ty_CopyToDemuxPacket( demux
->audio
,
604 &chunk
[ offset
], size
, ( demux
->filepos
+ offset
),
605 tivo
->lastAudioPTS
);
609 // 3 - MPEG Audio with PES Header, either SA or DTiVo
610 // 9 - DTiVo AC3 Audio Data with PES Header
611 // ================================================
612 if ( nybbleType
== 0x03 || nybbleType
== 0x09 )
614 int esOffset1
, esOffset2
;
615 if ( nybbleType
== 0x03 )
616 esOffset1
= demux_ty_FindESHeader( AUDIO_NAL
, &chunk
[ offset
],
619 // SA PES Header, No Audio Data
620 // ================================================
621 if ( nybbleType
== 0x03 && esOffset1
== 0 && size
== 16 )
624 tivo
->lastAudioPTS
= get_ty_pts( &chunk
[ offset
+
625 SERIES2_PTS_OFFSET
] );
628 // DTiVo Audio with PES Header
629 // ================================================
633 demux_ty_AddToAudioBuffer( tivo
, &chunk
[ offset
], size
);
634 demux_ty_FindESPacket( nybbleType
== 9 ? AC3_NAL
: AUDIO_NAL
,
635 tivo
->lastAudio
, tivo
->lastAudioEnd
, &esOffset1
,
638 if ( esOffset1
!= -1 && esOffset2
!= -1 )
640 int packetSize
= esOffset2
- esOffset1
;
644 if ( IsValidAudioPacket( packetSize
, &ptsOffset
,
647 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
648 "ty:Adding DTiVo Audio Packet Size %d\n",
651 tivo
->lastAudioPTS
= get_ty_pts(
652 &tivo
->lastAudio
[ esOffset1
+ ptsOffset
] );
654 if (nybbleType
== 9) headerSize
= 0;
655 demux_ty_CopyToDemuxPacket
658 &tivo
->lastAudio
[ esOffset1
+ headerSize
],
659 packetSize
- headerSize
,
660 demux
->filepos
+ offset
,
666 // Collapse the Audio Buffer
667 tivo
->lastAudioEnd
-= esOffset2
;
668 memmove( &tivo
->lastAudio
[ 0 ],
669 &tivo
->lastAudio
[ esOffset2
],
670 tivo
->lastAudioEnd
);
680 // ================================================================
681 // 1 = Closed Caption
682 // 2 = Extended Data Services
683 // ================================================================
684 else if ( type
== 0x01 || type
== 0x02 )
686 unsigned char lastXDS
[ 16 ];
687 int b
= AV_RB24(recPtr
) >> 4;
690 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:%s %04x\n", type
== 1 ? "CC" : "XDS", b
);
692 lastXDS
[ 0x00 ] = 0x00;
693 lastXDS
[ 0x01 ] = 0x00;
694 lastXDS
[ 0x02 ] = 0x01;
695 lastXDS
[ 0x03 ] = 0xb2;
696 lastXDS
[ 0x04 ] = 'T';
697 lastXDS
[ 0x05 ] = 'Y';
698 lastXDS
[ 0x06 ] = type
;
699 lastXDS
[ 0x07 ] = b
>> 8;
702 demux_ty_CopyToDemuxPacket( demux
->video
, lastXDS
, 0x09,
703 demux
->filepos
+ offset
, tivo
->lastVideoPTS
);
705 // ================================================================
707 // ================================================================
710 if ( size
> 0 && size
+ offset
<= CHUNKSIZE
)
712 if (type
!= 3 && type
!= 5 && (type
!= 0 || size
> 0)) {
713 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Invalid Type %x\n", type
);
720 if ( errorHeader
> 0 || invalidType
> 0 )
722 mp_msg( MSGT_DEMUX
, MSGL_DBG3
,
723 "ty:Error Check - Records %d, Parsed %d, Errors %d + %d\n",
724 numberRecs
, recordsDecoded
, errorHeader
, invalidType
);
726 // Invalid MPEG ES Size Check
727 if ( errorHeader
> numberRecs
/ 2 )
730 // Invalid MPEG Stream Type Check
731 if ( invalidType
> numberRecs
/ 2 )
735 demux
->filepos
= stream_tell( demux
->stream
);
740 static void demux_seek_ty( demuxer_t
*demuxer
, float rel_seek_secs
, float audio_delay
, int flags
)
742 demux_stream_t
*d_audio
= demuxer
->audio
;
743 demux_stream_t
*d_video
= demuxer
->video
;
744 sh_audio_t
*sh_audio
= d_audio
->sh
;
745 sh_video_t
*sh_video
= d_video
->sh
;
748 TiVoInfo
*tivo
= demuxer
->priv
;
750 mp_msg( MSGT_DEMUX
, MSGL_DBG3
, "ty:Seeking to %7.1f\n", rel_seek_secs
);
752 tivo
->lastAudioEnd
= 0;
753 tivo
->lastAudioPTS
= MP_NOPTS_VALUE
;
754 tivo
->lastVideoPTS
= MP_NOPTS_VALUE
;
756 //================= seek in MPEG ==========================
757 demuxer
->filepos
= stream_tell( demuxer
->stream
);
759 newpos
= ( flags
& SEEK_ABSOLUTE
) ? demuxer
->movi_start
: demuxer
->filepos
;
761 if( flags
& SEEK_FACTOR
)
763 newpos
+= ( demuxer
->movi_end
- demuxer
->movi_start
) * rel_seek_secs
;
767 if( ! sh_video
->i_bps
) // unspecified or VBR
768 newpos
+= 2324 * 75 * rel_seek_secs
; // 174.3 kbyte/sec
770 newpos
+= sh_video
->i_bps
* rel_seek_secs
;
773 if ( newpos
< demuxer
->movi_start
)
775 if( demuxer
->stream
->type
!= STREAMTYPE_VCD
) demuxer
->movi_start
= 0;
776 if( newpos
< demuxer
->movi_start
) newpos
= demuxer
->movi_start
;
779 res
= newpos
/ CHUNKSIZE
;
780 if ( rel_seek_secs
>= 0 )
781 newpos
= ( res
+ 1 ) * CHUNKSIZE
;
783 newpos
= res
* CHUNKSIZE
;
788 tivo
->whichChunk
= newpos
/ CHUNKSIZE
;
790 stream_seek( demuxer
->stream
, newpos
);
793 videobuf_code_len
= 0; // reset ES stream buffer
795 ds_fill_buffer( d_video
);
797 ds_fill_buffer( d_audio
);
802 if( sh_audio
&& !d_audio
->eof
&& d_video
->pts
&& d_audio
->pts
)
804 float a_pts
= d_audio
->pts
;
805 a_pts
+= ( ds_tell_pts( d_audio
) - sh_audio
->a_in_buffer_len
) /
806 (float)sh_audio
->i_bps
;
807 if( d_video
->pts
> a_pts
)
809 skip_audio_frame( sh_audio
); // sync audio
813 i
= sync_video_packet( d_video
);
814 if( i
== 0x1B3 || i
== 0x1B8 ) break; // found it!
815 if( !i
|| !skip_video_packet( d_video
) ) break; // EOF?
821 static int demux_ty_control( demuxer_t
*demuxer
,int cmd
, void *arg
)
823 demux_stream_t
*d_video
= demuxer
->video
;
824 sh_video_t
*sh_video
= d_video
->sh
;
828 case DEMUXER_CTRL_GET_TIME_LENGTH
:
829 if(!sh_video
->i_bps
) // unspecified or VBR
830 return DEMUXER_CTRL_DONTKNOW
;
832 (double)demuxer
->movi_end
-demuxer
->movi_start
/sh_video
->i_bps
;
833 return DEMUXER_CTRL_GUESS
;
835 case DEMUXER_CTRL_GET_PERCENT_POS
:
836 return DEMUXER_CTRL_DONTKNOW
;
838 return DEMUXER_CTRL_NOTIMPL
;
843 static void demux_close_ty( demuxer_t
*demux
)
845 TiVoInfo
*tivo
= demux
->priv
;
852 static int ty_check_file(demuxer_t
* demuxer
)
854 TiVoInfo
*tivo
= calloc(1, sizeof(TiVoInfo
));
855 demuxer
->priv
= tivo
;
856 return ds_fill_buffer(demuxer
->video
) ? DEMUXER_TYPE_MPEG_TY
: 0;
860 static demuxer_t
* demux_open_ty(demuxer_t
* demuxer
)
862 sh_audio_t
*sh_audio
=NULL
;
863 sh_video_t
*sh_video
=NULL
;
865 sh_video
=demuxer
->video
->sh
;sh_video
->ds
=demuxer
->video
;
867 if(demuxer
->audio
->id
!=-2) {
868 if(!ds_fill_buffer(demuxer
->audio
)){
869 mp_msg(MSGT_DEMUXER
, MSGL_INFO
, "MPEG: %s",
870 mp_gtext("No audio stream found -> no sound.\n"));
871 demuxer
->audio
->sh
=NULL
;
873 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
881 const demuxer_desc_t demuxer_desc_mpeg_ty
= {
885 "Christopher R. Wingert",
886 "Demux streams from TiVo",
887 DEMUXER_TYPE_MPEG_TY
,
888 0, // unsafe autodetect
890 demux_ty_fill_buffer
,