Mercurial > mplayer.hg
comparison libmpdemux/demux_ty.c @ 10263:0df8816f4665
TiVo demuxer and sub-cc/osd decoder
patch by usenet@wingert.org
(http://tivo-mplayer.sourceforge.net/releases/MPlayer-20030501-tivo-patch.gz)
changes by me:
- spit demux_ty to demux_ty and demux_ty_osd (later handles mpeg user-data
decoding, ie sub-cc and osd)
- removed some cosmetics changes
- some compile fixes (gcc3 specific variable decl etc)
author | arpi |
---|---|
date | Mon, 09 Jun 2003 00:24:49 +0000 |
parents | |
children | 6e35326c742f |
comparison
equal
deleted
inserted
replaced
10262:e6f5487b2042 | 10263:0df8816f4665 |
---|---|
1 /* | |
2 * tivo@wingert.org, February 2003 | |
3 * | |
4 * Copyright (C) 2003 Christopher R. Wingert | |
5 * | |
6 * The license covers the portions of this file regarding TiVo additions. | |
7 * | |
8 * Olaf Beck and Tridge (indirectly) were essential at providing | |
9 * information regarding the format of the TiVo streams. | |
10 * | |
11 * However, no code in the following subsection is directly copied from | |
12 * either author. | |
13 * | |
14 * | |
15 * This program is free software; you can redistribute it and/or | |
16 * modify it under the terms of the GNU General Public License | |
17 * as published by the Free Software Foundation; either version 2 | |
18 * of the License, or (at your option) any later version. | |
19 * | |
20 * This program is distributed in the hope that it will be useful, | |
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 * GNU General Public License for more details. | |
24 * | |
25 * You should have received a copy of the GNU General Public License | |
26 * along with this program; if not, write to the Free Software | |
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
28 * | |
29 */ | |
30 | |
31 | |
32 #include <stdio.h> | |
33 #include <stdlib.h> | |
34 #include <unistd.h> | |
35 #include <time.h> | |
36 #include <stdarg.h> | |
37 | |
38 #include "config.h" | |
39 #include "mp_msg.h" | |
40 #include "help_mp.h" | |
41 | |
42 #include "stream.h" | |
43 #include "demuxer.h" | |
44 #include "parse_es.h" | |
45 #include "stheader.h" | |
46 //#include "mp3_hdr.h" | |
47 //#include "../subreader.h" | |
48 #include "../sub_cc.h" | |
49 //#include "../libvo/sub.h" | |
50 | |
51 //#include "dvdauth.h" | |
52 | |
53 extern void resync_audio_stream( sh_audio_t *sh_audio ); | |
54 extern void skip_audio_frame( sh_audio_t *sh_audio ); | |
55 extern int sub_justify; | |
56 | |
57 // 2/c0: audio data | |
58 // 3/c0: audio packet header (PES header) | |
59 // 4/c0: audio data (S/A only?) | |
60 // 9/c0: audio packet header, AC-3 audio | |
61 // 2/e0: video data | |
62 // 6/e0: video packet header (PES header) | |
63 // 7/e0: video sequence header start | |
64 // 8/e0: video I-frame header start | |
65 // a/e0: video P-frame header start | |
66 // b/e0: video B-frame header start | |
67 // c/e0: video GOP header start | |
68 // e/01: closed-caption data | |
69 // e/02: Extended data services data | |
70 | |
71 | |
72 #define TIVO_PES_FILEID ( 0xf5467abd ) | |
73 #define TIVO_PART_LENGTH ( 0x20000000 ) | |
74 | |
75 #define CHUNKSIZE ( 128 * 1024 ) | |
76 #define MAX_AUDIO_BUFFER ( 16 * 1024 ) | |
77 | |
78 #define PTS_MHZ ( 90 ) | |
79 #define PTS_KHZ ( PTS_MHZ * 1000 ) | |
80 | |
81 #define TY_V ( 1 ) | |
82 #define TY_A ( 1 ) | |
83 | |
84 typedef struct sTivoInfo | |
85 { | |
86 unsigned char lastAudio[ MAX_AUDIO_BUFFER ]; | |
87 int lastAudioEnd; | |
88 | |
89 int tivoType; // 1 = SA, 2 = DTiVo | |
90 | |
91 float firstAudioPTS; | |
92 float firstVideoPTS; | |
93 | |
94 float lastAudioPTS; | |
95 float lastVideoPTS; | |
96 | |
97 int headerOk; | |
98 unsigned int pesFileId; // Should be 0xf5467abd | |
99 int streamType; // Should be 0x02 | |
100 int chunkSize; // Should always be 128k | |
101 off_t size; | |
102 int readHeader; | |
103 } TiVoInfo; | |
104 | |
105 off_t vstream_streamsize( ); | |
106 void ty_ClearOSD( int start ); | |
107 | |
108 // DTiVo MPEG 336, 480, 576, 768 | |
109 // SA TiVo 864 | |
110 // DTiVo AC-3 1550 | |
111 // | |
112 #define SERIES1_PTS_LENGTH ( 11 ) | |
113 #define SERIES1_PTS_OFFSET ( 6 ) | |
114 #define SERIES2_PTS_LENGTH ( 16 ) | |
115 #define SERIES2_PTS_OFFSET ( 9 ) | |
116 #define AC3_PTS_LENGTH ( 16 ) | |
117 #define AC3_PTS_OFFSET ( 9 ) | |
118 | |
119 #define NUMBER_DIFFERENT_AUDIO_SIZES ( 6 ) | |
120 static int Series1AudioWithPTS[ NUMBER_DIFFERENT_AUDIO_SIZES ] = | |
121 { | |
122 336 + SERIES1_PTS_LENGTH, | |
123 480 + SERIES1_PTS_LENGTH, | |
124 576 + SERIES1_PTS_LENGTH, | |
125 768 + SERIES1_PTS_LENGTH, | |
126 864 + SERIES1_PTS_LENGTH | |
127 }; | |
128 static int Series2AudioWithPTS[ NUMBER_DIFFERENT_AUDIO_SIZES ] = | |
129 { | |
130 336 + SERIES2_PTS_LENGTH, | |
131 480 + SERIES2_PTS_LENGTH, | |
132 576 + SERIES2_PTS_LENGTH, | |
133 768 + SERIES2_PTS_LENGTH, | |
134 864 + SERIES2_PTS_LENGTH | |
135 }; | |
136 | |
137 static int IsValidAudioPacket( int size, int *ptsOffset, int *ptsLen ) | |
138 { | |
139 int count; | |
140 | |
141 *ptsOffset = 0; | |
142 *ptsLen = 0; | |
143 | |
144 // AC-3 | |
145 if ( ( size == 1550 ) || ( size == 1552 ) ) | |
146 { | |
147 *ptsOffset = AC3_PTS_OFFSET; | |
148 *ptsLen = AC3_PTS_LENGTH; | |
149 return( 1 ); | |
150 } | |
151 | |
152 // MPEG | |
153 for( count = 0 ; count < NUMBER_DIFFERENT_AUDIO_SIZES ; count++ ) | |
154 { | |
155 if ( size == Series1AudioWithPTS[ count ] ) | |
156 { | |
157 *ptsOffset = SERIES1_PTS_OFFSET; | |
158 *ptsLen = SERIES1_PTS_LENGTH; | |
159 break; | |
160 } | |
161 } | |
162 if ( *ptsOffset == 0 ) | |
163 { | |
164 for( count = 0 ; count < NUMBER_DIFFERENT_AUDIO_SIZES ; count++ ) | |
165 { | |
166 if ( size == Series2AudioWithPTS[ count ] ) | |
167 { | |
168 *ptsOffset = SERIES2_PTS_OFFSET; | |
169 *ptsLen = SERIES2_PTS_LENGTH; | |
170 break; | |
171 } | |
172 } | |
173 } | |
174 if ( *ptsOffset == 0 ) | |
175 { | |
176 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Tossing Audio Packet Size %d\n", | |
177 size ); | |
178 return( 0 ); | |
179 } | |
180 else | |
181 { | |
182 return( 1 ); | |
183 } | |
184 } | |
185 | |
186 | |
187 static float get_ty_pts( unsigned char *buf ) | |
188 { | |
189 float result = 0; | |
190 unsigned char temp; | |
191 | |
192 temp = ( buf[ 0 ] & 0xE ) >> 1; | |
193 result = ( (float) temp ) * ( (float) ( 1L << 30 ) ) / ( (float)PTS_KHZ ); | |
194 temp = buf[ 1 ]; | |
195 result += ( (float) temp ) * ( (float) ( 1L << 22 ) ) / ( (float)PTS_KHZ ); | |
196 temp = ( buf[ 2 ] & 0xFE ) >> 1; | |
197 result += ( (float) temp ) * ( (float) ( 1L << 15 ) ) / ( (float)PTS_KHZ ); | |
198 temp = buf[ 3 ]; | |
199 result += ( (float) temp ) * ( (float) ( 1L << 7 ) ) / ( (float)PTS_KHZ ); | |
200 temp = ( buf[ 4 ] & 0xFE ) >> 1; | |
201 result += ( (float) temp ) / ( (float)PTS_MHZ ); | |
202 | |
203 return result; | |
204 } | |
205 | |
206 static void demux_ty_AddToAudioBuffer( TiVoInfo *tivo, unsigned char *buffer, | |
207 int size ) | |
208 { | |
209 if ( ( tivo->lastAudioEnd + size ) < MAX_AUDIO_BUFFER ) | |
210 { | |
211 memcpy( &( tivo->lastAudio[ tivo->lastAudioEnd ] ), | |
212 buffer, size ); | |
213 tivo->lastAudioEnd += size; | |
214 } | |
215 else | |
216 { | |
217 mp_msg( MSGT_DEMUX, MSGL_ERR, | |
218 "ty:WARNING - Would have blown my audio buffer\n" ); | |
219 } | |
220 } | |
221 | |
222 static void demux_ty_CopyToDemuxPacket( int type, TiVoInfo *tivo, demux_stream_t *ds, | |
223 unsigned char *buffer, int size, off_t pos, float pts ) | |
224 { | |
225 demux_packet_t *dp; | |
226 | |
227 // mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Calling ds_add_packet() %7.1f\n", pts ); | |
228 // printf( "%x %x %x %x\n", | |
229 // buffer[ 0 ], buffer[ 1 ], buffer[ 2 ], buffer[ 3 ] ); | |
230 | |
231 dp = new_demux_packet( size ); | |
232 memcpy( dp->buffer, buffer, size ); | |
233 dp->pts = pts; | |
234 dp->pos = pos; | |
235 dp->flags = 0; | |
236 ds_add_packet( ds, dp ); | |
237 ds->pts = pts; | |
238 if ( type == TY_V ) | |
239 { | |
240 if ( tivo->firstVideoPTS == -1 ) | |
241 { | |
242 tivo->firstVideoPTS = pts; | |
243 } | |
244 } | |
245 if ( type == TY_A ) | |
246 { | |
247 if ( tivo->firstAudioPTS == -1 ) | |
248 { | |
249 tivo->firstAudioPTS = pts; | |
250 } | |
251 } | |
252 } | |
253 | |
254 static int demux_ty_FindESHeader( unsigned char *header, int headerSize, | |
255 unsigned char *buffer, int bufferSize, int *esOffset1 ) | |
256 { | |
257 int count; | |
258 | |
259 *esOffset1 = -1; | |
260 for( count = 0 ; count < bufferSize ; count++ ) | |
261 { | |
262 if ( ( buffer[ count + 0 ] == header[ 0 ] ) && | |
263 ( buffer[ count + 1 ] == header[ 1 ] ) && | |
264 ( buffer[ count + 2 ] == header[ 2 ] ) && | |
265 ( buffer[ count + 3 ] == header[ 3 ] ) ) | |
266 { | |
267 *esOffset1 = count; | |
268 return( 1 ); | |
269 } | |
270 } | |
271 return( -1 ); | |
272 } | |
273 | |
274 static void demux_ty_FindESPacket( unsigned char *header, int headerSize, | |
275 unsigned char *buffer, int bufferSize, int *esOffset1, int *esOffset2 ) | |
276 { | |
277 int count; | |
278 | |
279 *esOffset1 = -1; | |
280 *esOffset2 = -1; | |
281 | |
282 for( count = 0 ; count < bufferSize ; count++ ) | |
283 { | |
284 if ( ( buffer[ count + 0 ] == header[ 0 ] ) && | |
285 ( buffer[ count + 1 ] == header[ 1 ] ) && | |
286 ( buffer[ count + 2 ] == header[ 2 ] ) && | |
287 ( buffer[ count + 3 ] == header[ 3 ] ) ) | |
288 { | |
289 *esOffset1 = count; | |
290 break; | |
291 } | |
292 } | |
293 | |
294 if ( *esOffset1 != -1 ) | |
295 { | |
296 for( count = *esOffset1 + 1 ; | |
297 count < bufferSize ; count++ ) | |
298 { | |
299 if ( ( buffer[ count + 0 ] == header[ 0 ] ) && | |
300 ( buffer[ count + 1 ] == header[ 1 ] ) && | |
301 ( buffer[ count + 2 ] == header[ 2 ] ) && | |
302 ( buffer[ count + 3 ] == header[ 3 ] ) ) | |
303 { | |
304 *esOffset2 = count; | |
305 break; | |
306 } | |
307 } | |
308 } | |
309 } | |
310 | |
311 static int tivobuffer2hostlong( unsigned char *buffer ) | |
312 { | |
313 return | |
314 ( | |
315 buffer[ 0 ] << 24 | buffer[ 1 ] << 16 | buffer[ 2 ] << 8 | buffer[ 3 ] | |
316 ); | |
317 } | |
318 | |
319 static unsigned char tivo_reversebyte( unsigned char val ) | |
320 { | |
321 int count; | |
322 unsigned char ret; | |
323 | |
324 ret = 0; | |
325 for ( count = 0 ; count < 8 ; count++ ) | |
326 { | |
327 ret = ret << 1; | |
328 ret |= ( ( val >> count ) & 0x01 ); | |
329 } | |
330 return( ret ); | |
331 } | |
332 | |
333 | |
334 static unsigned char ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 }; | |
335 static unsigned char ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 }; | |
336 static unsigned char ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd }; | |
337 | |
338 int demux_ty_fill_buffer( demuxer_t *demux ) | |
339 { | |
340 int invalidType = 0; | |
341 int errorHeader = 0; | |
342 int recordsDecoded = 0; | |
343 off_t filePos = 0; | |
344 | |
345 unsigned char chunk[ CHUNKSIZE ]; | |
346 int whichChunk; | |
347 int readSize; | |
348 unsigned int pesFileId = 0; | |
349 | |
350 int numberRecs; | |
351 unsigned char *recPtr; | |
352 int offset; | |
353 int size; | |
354 | |
355 int type; | |
356 int nybbleType; | |
357 | |
358 int counter; | |
359 | |
360 int aid; | |
361 demux_stream_t *ds = NULL; | |
362 | |
363 int esOffset1; | |
364 int esOffset2; | |
365 | |
366 TiVoInfo *tivo = 0; | |
367 | |
368 if ( demux->stream->type == STREAMTYPE_DVD ) | |
369 { | |
370 return( 0 ); | |
371 } | |
372 | |
373 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Parsing a chunk\n" ); | |
374 if ( ( demux->a_streams[ MAX_A_STREAMS - 1 ] ) == 0 ) | |
375 { | |
376 demux->a_streams[ MAX_A_STREAMS - 1 ] = malloc( sizeof( TiVoInfo ) ); | |
377 tivo = demux->a_streams[ MAX_A_STREAMS - 1 ]; | |
378 memset( tivo, 0, sizeof( TiVoInfo ) ); | |
379 tivo->firstAudioPTS = -1; | |
380 tivo->firstVideoPTS = -1; | |
381 } | |
382 else | |
383 { | |
384 tivo = demux->a_streams[ MAX_A_STREAMS - 1 ]; | |
385 } | |
386 | |
387 if( demux->stream->eof ) return 0; | |
388 | |
389 // ====================================================================== | |
390 // If we haven't figured out the size of the stream, lets do so | |
391 // ====================================================================== | |
392 #ifdef STREAMTYPE_STREAM_TY | |
393 if ( demux->stream->type == STREAMTYPE_STREAM_TY ) | |
394 { | |
395 // The vstream code figures out the exact size of the stream | |
396 demux->movi_start = 0; | |
397 demux->movi_end = vstream_streamsize(); | |
398 tivo->size = vstream_streamsize(); | |
399 } | |
400 else | |
401 #endif | |
402 { | |
403 // If its a local file, try to find the Part Headers, so we can | |
404 // calculate the ACTUAL stream size | |
405 // If we can't find it, go off with the file size and hope the | |
406 // extract program did the "right thing" | |
407 if ( tivo->readHeader == 0 ) | |
408 { | |
409 tivo->readHeader = 1; | |
410 filePos = demux->filepos; | |
411 stream_seek( demux->stream, 0 ); | |
412 // mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
413 // "ty:Reading a chunk %d\n", __LINE__ ); | |
414 readSize = stream_read( demux->stream, chunk, CHUNKSIZE ); | |
415 if ( readSize == CHUNKSIZE ) | |
416 { | |
417 tivo->pesFileId = tivobuffer2hostlong( &chunk[ 0x00 ] ); | |
418 tivo->streamType = tivobuffer2hostlong( &chunk[ 0x04 ] ); | |
419 tivo->chunkSize = tivobuffer2hostlong( &chunk[ 0x08 ] ); | |
420 tivo->size = tivobuffer2hostlong( &chunk[ 0x0c ] ); | |
421 if ( tivo->pesFileId == TIVO_PES_FILEID ) | |
422 { | |
423 off_t numberParts; | |
424 off_t size; | |
425 | |
426 if ( demux->stream->end_pos > TIVO_PART_LENGTH ) | |
427 { | |
428 numberParts = demux->stream->end_pos / TIVO_PART_LENGTH; | |
429 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Number Parts %d\n", | |
430 numberParts ); | |
431 stream_seek( demux->stream, numberParts * TIVO_PART_LENGTH ); | |
432 // mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
433 // "ty:Reading a chunk %d\n", __LINE__ ); | |
434 readSize = stream_read( demux->stream, chunk, CHUNKSIZE ); | |
435 pesFileId = tivobuffer2hostlong( &chunk[ 0x00 ] ); | |
436 if ( pesFileId == TIVO_PES_FILEID ) | |
437 { | |
438 size = tivobuffer2hostlong( &chunk[ 0x0c ] ); | |
439 size /= 256; | |
440 size -= 4; | |
441 size *= CHUNKSIZE; | |
442 tivo->size = numberParts * TIVO_PART_LENGTH; | |
443 tivo->size += size; | |
444 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
445 "ty:Header Calc Stream Size %lld\n", tivo->size ); | |
446 } | |
447 else | |
448 { | |
449 tivo->size = demux->stream->end_pos; | |
450 } | |
451 } | |
452 else | |
453 { | |
454 tivo->size = demux->stream->end_pos; | |
455 } | |
456 } | |
457 else | |
458 { | |
459 tivo->size = demux->stream->end_pos; | |
460 } | |
461 } | |
462 if ( tivo->size > demux->stream->end_pos ) | |
463 { | |
464 tivo->size = demux->stream->end_pos; | |
465 } | |
466 | |
467 if ( demux->stream->start_pos > 0 ) | |
468 { | |
469 filePos = demux->stream->start_pos; | |
470 } | |
471 stream_seek( demux->stream, filePos ); | |
472 demux->filepos = stream_tell( demux->stream ); | |
473 } | |
474 demux->movi_start = 0; | |
475 demux->movi_end = tivo->size; | |
476 } | |
477 | |
478 // ====================================================================== | |
479 // Give a clue as to where we are in the stream | |
480 // ====================================================================== | |
481 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
482 "ty:ty header size %llx\n", tivo->size ); | |
483 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
484 "ty:file end_pos %llx\n", demux->stream->end_pos ); | |
485 // mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
486 // "ty:vstream size %llx\n", vstream_streamsize() ); | |
487 | |
488 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
489 "\nty:wanted current offset %llx\n", stream_tell( demux->stream ) ); | |
490 | |
491 if ( tivo->size > 0 ) | |
492 { | |
493 if ( stream_tell( demux->stream ) > tivo->size ) | |
494 { | |
495 demux->stream->eof = 1; | |
496 return( 0 ); | |
497 } | |
498 } | |
499 | |
500 // Make sure we are on a 128k boundary | |
501 if ( ( demux->filepos % CHUNKSIZE ) != 0 ) | |
502 { | |
503 whichChunk = demux->filepos / CHUNKSIZE; | |
504 if ( ( demux->filepos % CHUNKSIZE ) > ( CHUNKSIZE / 2 ) ) | |
505 { | |
506 whichChunk++; | |
507 } | |
508 stream_seek( demux->stream, ( whichChunk * CHUNKSIZE ) ); | |
509 } | |
510 | |
511 demux->filepos = stream_tell( demux->stream ); | |
512 readSize = stream_read( demux->stream, chunk, CHUNKSIZE ); | |
513 if ( readSize != CHUNKSIZE ) | |
514 { | |
515 return( 0 ); | |
516 } | |
517 | |
518 // We found a part header, skip it | |
519 pesFileId = tivobuffer2hostlong( &chunk[ 0x00 ] ); | |
520 if( pesFileId == TIVO_PES_FILEID ) | |
521 { | |
522 demux->filepos = stream_tell( demux->stream ); | |
523 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Skipping PART Header\n" ); | |
524 readSize = stream_read( demux->stream, chunk, CHUNKSIZE ); | |
525 if ( readSize != CHUNKSIZE ) | |
526 { | |
527 return( 0 ); | |
528 } | |
529 } | |
530 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
531 "\nty:actual current offset %llx\n", ( stream_tell( demux->stream ) - | |
532 0x20000 ) ); | |
533 | |
534 | |
535 // Lets make a Video Demux Stream for Mplayer | |
536 aid = 0x0; | |
537 if( !demux->v_streams[ aid ] ) new_sh_video( demux, aid ); | |
538 if( demux->video->id == -1 ) demux->video->id = aid; | |
539 if( demux->video->id == aid ) | |
540 { | |
541 ds = demux->video; | |
542 if( !ds->sh ) ds->sh = demux->v_streams[ aid ]; | |
543 } | |
544 | |
545 // ====================================================================== | |
546 // Finally, we get to actually parse the chunk | |
547 // ====================================================================== | |
548 numberRecs = chunk[ 0 ]; | |
549 recPtr = &chunk[ 4 ]; | |
550 offset = ( numberRecs * 16 ) + 4; | |
551 for ( counter = 0 ; counter < numberRecs ; counter++ ) | |
552 { | |
553 size = ( recPtr[ 0 ] << 8 | recPtr[ 1 ] ) << 4 | ( recPtr[ 2 ] >> 4 ); | |
554 type = recPtr[ 3 ]; | |
555 nybbleType = recPtr[ 2 ] & 0x0f; | |
556 recordsDecoded++; | |
557 | |
558 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
559 "ty:Record Type %x/%x %d\n", nybbleType, type, size ); | |
560 | |
561 // ================================================================ | |
562 // Video Parsing | |
563 // ================================================================ | |
564 if ( type == 0xe0 ) | |
565 { | |
566 if ( ( size > 0 ) && ( ( size + offset ) <= CHUNKSIZE ) ) | |
567 { | |
568 #if 0 | |
569 printf( "Video Chunk Header " ); | |
570 for( count = 0 ; count < 24 ; count++ ) | |
571 { | |
572 printf( "%2.2x ", chunk[ offset + count ] ); | |
573 } | |
574 printf( "\n" ); | |
575 #endif | |
576 demux_ty_FindESHeader( ty_VideoPacket, 4, &chunk[ offset ], | |
577 size, &esOffset1 ); | |
578 if ( esOffset1 != -1 ) | |
579 { | |
580 tivo->lastVideoPTS = get_ty_pts( | |
581 &chunk[ offset + esOffset1 + 9 ] ); | |
582 mp_msg( MSGT_DEMUX, MSGL_DBG3, "Video PTS %7.1f\n", | |
583 tivo->lastVideoPTS ); | |
584 } | |
585 | |
586 // Do NOT Pass the PES Header onto the MPEG2 Decode | |
587 if( nybbleType != 0x06 ) | |
588 { | |
589 demux_ty_CopyToDemuxPacket( TY_V, tivo, demux->video, | |
590 &chunk[ offset ], size, ( demux->filepos + offset ), | |
591 tivo->lastVideoPTS ); | |
592 } | |
593 offset += size; | |
594 } | |
595 else | |
596 { | |
597 errorHeader++; | |
598 } | |
599 } | |
600 // ================================================================ | |
601 // Audio Parsing | |
602 // ================================================================ | |
603 else if ( type == 0xc0 ) | |
604 { | |
605 if ( ( size > 0 ) && ( ( size + offset ) <= CHUNKSIZE ) ) | |
606 { | |
607 #if 0 | |
608 printf( "Audio Chunk Header " ); | |
609 for( count = 0 ; count < 24 ; count++ ) | |
610 { | |
611 printf( "%2.2x ", chunk[ offset + count ] ); | |
612 } | |
613 printf( "\n" ); | |
614 #endif | |
615 | |
616 if( demux->audio->id == -1 ) | |
617 { | |
618 if ( nybbleType == 0x02 ) | |
619 { | |
620 continue; // DTiVo inconclusive, wait for more | |
621 } | |
622 else if ( nybbleType == 0x09 ) | |
623 { | |
624 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Setting AC-3 Audio\n" ); | |
625 aid = 0x80; // AC-3 | |
626 } | |
627 else | |
628 { | |
629 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Setting MPEG Audio\n" ); | |
630 aid = 0x0; // MPEG Audio | |
631 } | |
632 | |
633 demux->audio->id = aid; | |
634 if( !demux->a_streams[ aid ] ) new_sh_audio( demux, aid ); | |
635 if( demux->audio->id == aid ) | |
636 { | |
637 ds = demux->audio; | |
638 if( !ds->sh ) ds->sh = demux->a_streams[ aid ]; | |
639 } | |
640 } | |
641 | |
642 aid = demux->audio->id; | |
643 | |
644 | |
645 // SA DTiVo Audio Data, no PES | |
646 // ================================================ | |
647 if ( nybbleType == 0x02 ) | |
648 { | |
649 if ( tivo->tivoType == 2 ) | |
650 { | |
651 demux_ty_AddToAudioBuffer( tivo, &chunk[ offset ], size ); | |
652 } | |
653 else | |
654 { | |
655 | |
656 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
657 "ty:Adding Audio Packet Size %d\n", size ); | |
658 demux_ty_CopyToDemuxPacket( TY_A, tivo, demux->audio, | |
659 &chunk[ offset ], size, ( demux->filepos + offset ), | |
660 tivo->lastAudioPTS ); | |
661 } | |
662 } | |
663 | |
664 // MPEG Audio with PES Header, either SA or DTiVo | |
665 // ================================================ | |
666 if ( nybbleType == 0x03 ) | |
667 { | |
668 demux_ty_FindESHeader( ty_MPEGAudioPacket, 4, &chunk[ offset ], | |
669 size, &esOffset1 ); | |
670 | |
671 // SA PES Header, No Audio Data | |
672 // ================================================ | |
673 if ( ( esOffset1 == 0 ) && ( size == 16 ) ) | |
674 { | |
675 tivo->tivoType = 1; | |
676 tivo->lastAudioPTS = get_ty_pts( &chunk[ offset + | |
677 SERIES2_PTS_OFFSET ] ); | |
678 mp_msg( MSGT_DEMUX, MSGL_DBG3, "SA Audio PTS %7.1f\n", | |
679 tivo->lastAudioPTS ); | |
680 } | |
681 else | |
682 // DTiVo Audio with PES Header | |
683 // ================================================ | |
684 { | |
685 tivo->tivoType = 2; | |
686 | |
687 demux_ty_AddToAudioBuffer( tivo, &chunk[ offset ], size ); | |
688 demux_ty_FindESPacket( ty_MPEGAudioPacket, 4, | |
689 tivo->lastAudio, tivo->lastAudioEnd, &esOffset1, | |
690 &esOffset2 ); | |
691 | |
692 if ( ( esOffset1 != -1 ) && ( esOffset2 != -1 ) ) | |
693 { | |
694 int packetSize = esOffset2 - esOffset1; | |
695 int headerSize; | |
696 int ptsOffset; | |
697 | |
698 if ( IsValidAudioPacket( packetSize, &ptsOffset, | |
699 &headerSize ) ) | |
700 { | |
701 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
702 "ty:Adding DTiVo Audio Packet Size %d\n", | |
703 packetSize ); | |
704 | |
705 tivo->lastAudioPTS = get_ty_pts( | |
706 &tivo->lastAudio[ esOffset1 + ptsOffset ] ); | |
707 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
708 "MPEG Audio PTS %7.1f\n", tivo->lastAudioPTS ); | |
709 | |
710 demux_ty_CopyToDemuxPacket | |
711 ( | |
712 TY_A, | |
713 tivo, | |
714 demux->audio, | |
715 &( tivo->lastAudio[ esOffset1 + headerSize ] ), | |
716 ( packetSize - headerSize ), | |
717 ( demux->filepos + offset ), | |
718 tivo->lastAudioPTS | |
719 ); | |
720 | |
721 } | |
722 | |
723 // Collapse the Audio Buffer | |
724 memmove( &(tivo->lastAudio[ 0 ] ), | |
725 &( tivo->lastAudio[ esOffset2 ] ), | |
726 ( tivo->lastAudioEnd - esOffset2 ) ); | |
727 tivo->lastAudioEnd -= esOffset2; | |
728 } | |
729 } | |
730 } | |
731 | |
732 // SA Audio with no PES Header | |
733 // ================================================ | |
734 if ( nybbleType == 0x04 ) | |
735 { | |
736 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
737 "ty:Adding Audio Packet Size %d\n", size ); | |
738 demux_ty_CopyToDemuxPacket( TY_A, tivo, demux->audio, | |
739 &chunk[ offset ], size, ( demux->filepos + offset ), | |
740 tivo->lastAudioPTS ); | |
741 } | |
742 | |
743 // DTiVo AC3 Audio Data with PES Header | |
744 // ================================================ | |
745 if ( nybbleType == 0x09 ) | |
746 { | |
747 tivo->tivoType = 2; | |
748 | |
749 demux_ty_AddToAudioBuffer( tivo, &chunk[ offset ], size ); | |
750 demux_ty_FindESPacket( ty_AC3AudioPacket, 4, | |
751 tivo->lastAudio, tivo->lastAudioEnd, &esOffset1, | |
752 &esOffset2 ); | |
753 | |
754 if ( ( esOffset1 != -1 ) && ( esOffset2 != -1 ) ) | |
755 { | |
756 int packetSize = esOffset2 - esOffset1; | |
757 int headerSize; | |
758 int ptsOffset; | |
759 | |
760 if ( IsValidAudioPacket( packetSize, &ptsOffset, | |
761 &headerSize ) ) | |
762 { | |
763 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
764 "ty:Adding DTiVo Audio Packet Size %d\n", | |
765 packetSize ); | |
766 | |
767 tivo->lastAudioPTS = get_ty_pts( | |
768 &tivo->lastAudio[ esOffset1 + ptsOffset ] ); | |
769 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
770 "AC3 Audio PTS %7.1f\n", tivo->lastAudioPTS ); | |
771 | |
772 // AC3 Decoder WANTS the PTS | |
773 demux_ty_CopyToDemuxPacket | |
774 ( | |
775 TY_A, | |
776 tivo, | |
777 demux->audio, | |
778 &( tivo->lastAudio[ esOffset1 ] ), | |
779 ( packetSize ), | |
780 ( demux->filepos + offset ), | |
781 tivo->lastAudioPTS | |
782 ); | |
783 | |
784 } | |
785 | |
786 // Collapse the Audio Buffer | |
787 memmove( &(tivo->lastAudio[ 0 ] ), | |
788 &( tivo->lastAudio[ esOffset2 ] ), | |
789 ( tivo->lastAudioEnd - esOffset2 ) ); | |
790 tivo->lastAudioEnd -= esOffset2; | |
791 } | |
792 } | |
793 offset += size; | |
794 } | |
795 else | |
796 { | |
797 errorHeader++; | |
798 } | |
799 } | |
800 // ================================================================ | |
801 // Closed Caption | |
802 // ================================================================ | |
803 else if ( type == 0x01 ) | |
804 { | |
805 unsigned char b1; | |
806 unsigned char b2; | |
807 unsigned char buffer[ 16 ]; | |
808 | |
809 b1 = ( ( ( recPtr[ 0 ] & 0x0f ) << 4 ) | | |
810 ( ( recPtr[ 1 ] & 0xf0 ) >> 4 ) ); | |
811 b1 &= 0x7f; | |
812 b2 = ( ( ( recPtr[ 1 ] & 0x0f ) << 4 ) | | |
813 ( ( recPtr[ 2 ] & 0xf0 ) >> 4 ) ); | |
814 b2 &= 0x7f; | |
815 | |
816 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:CC %x %x\n", b1, b2 ); | |
817 | |
818 buffer[ 0x00 ] = 0x00; | |
819 buffer[ 0x01 ] = 0x00; | |
820 buffer[ 0x02 ] = 0x01; | |
821 buffer[ 0x03 ] = 0xb2; | |
822 buffer[ 0x04 ] = 'T'; | |
823 buffer[ 0x05 ] = 'Y'; | |
824 buffer[ 0x06 ] = 0x01; | |
825 buffer[ 0x07 ] = b1; | |
826 buffer[ 0x08 ] = b2; | |
827 demux_ty_CopyToDemuxPacket( TY_V, tivo, demux->video, buffer, 0x09, | |
828 ( demux->filepos + offset ), tivo->lastVideoPTS ); | |
829 } | |
830 // ================================================================ | |
831 // Extended Data Services | |
832 // ================================================================ | |
833 else if ( type == 0x02 ) | |
834 { | |
835 unsigned char b1; | |
836 unsigned char b2; | |
837 unsigned char buffer[ 16 ]; | |
838 | |
839 b1 = ( ( ( recPtr[ 0 ] & 0x0f ) << 4 ) | | |
840 ( ( recPtr[ 1 ] & 0xf0 ) >> 4 ) ); | |
841 b1 &= 0x7f; | |
842 b2 = ( ( ( recPtr[ 1 ] & 0x0f ) << 4 ) | | |
843 ( ( recPtr[ 2 ] & 0xf0 ) >> 4 ) ); | |
844 b2 &= 0x7f; | |
845 | |
846 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:XDS %x %x\n", b1, b2 ); | |
847 | |
848 buffer[ 0x00 ] = 0x00; | |
849 buffer[ 0x01 ] = 0x00; | |
850 buffer[ 0x02 ] = 0x01; | |
851 buffer[ 0x03 ] = 0xb2; | |
852 buffer[ 0x04 ] = 'T'; | |
853 buffer[ 0x05 ] = 'Y'; | |
854 buffer[ 0x06 ] = 0x02; | |
855 buffer[ 0x07 ] = b1; | |
856 buffer[ 0x08 ] = b2; | |
857 demux_ty_CopyToDemuxPacket( TY_V, tivo, demux->video, buffer, 0x09, | |
858 ( demux->filepos + offset ), tivo->lastVideoPTS ); | |
859 } | |
860 // ================================================================ | |
861 // Found a 0x03 on Droid's TiVo, I have no idea what it is | |
862 // ================================================================ | |
863 else if ( type == 0x03 ) | |
864 { | |
865 if ( ( size > 0 ) && ( ( size + offset ) <= CHUNKSIZE ) ) | |
866 { | |
867 offset += size; | |
868 } | |
869 } | |
870 // ================================================================ | |
871 // Unknown | |
872 // ================================================================ | |
873 else if ( type == 0x05 ) | |
874 { | |
875 if ( ( size > 0 ) && ( ( size + offset ) <= CHUNKSIZE ) ) | |
876 { | |
877 offset += size; | |
878 } | |
879 } | |
880 else | |
881 { | |
882 if ( ( size > 0 ) && ( ( size + offset ) <= CHUNKSIZE ) ) | |
883 { | |
884 offset += size; | |
885 } | |
886 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Invalid Type %x\n", type ); | |
887 invalidType++; | |
888 } | |
889 recPtr += 16; | |
890 } | |
891 | |
892 if ( errorHeader > 0 ) | |
893 { | |
894 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
895 "ty:Error Check - Records %d, Parsed %d, Errors %d\n", | |
896 numberRecs, recordsDecoded, errorHeader ); | |
897 | |
898 // Invalid MPEG ES Size Check | |
899 if ( errorHeader > ( numberRecs / 2 ) ) | |
900 { | |
901 return( 0 ); | |
902 } | |
903 | |
904 // Invalid MPEG Stream Type Check | |
905 if ( invalidType > ( numberRecs / 2 ) ) | |
906 { | |
907 return( 0 ); | |
908 } | |
909 } | |
910 | |
911 demux->filepos = stream_tell( demux->stream ); | |
912 | |
913 return( 1 ); | |
914 } | |
915 | |
916 void demux_seek_ty( demuxer_t *demuxer, float rel_seek_secs, int flags ) | |
917 { | |
918 demux_stream_t *d_audio = demuxer->audio; | |
919 demux_stream_t *d_video = demuxer->video; | |
920 sh_audio_t *sh_audio = d_audio->sh; | |
921 sh_video_t *sh_video = d_video->sh; | |
922 off_t newpos; | |
923 off_t res; | |
924 TiVoInfo *tivo = 0; | |
925 | |
926 mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Seeking to %7.1f\n", rel_seek_secs ); | |
927 | |
928 if ( ( demuxer->a_streams[ MAX_A_STREAMS - 1 ] ) != 0 ) | |
929 { | |
930 tivo = demuxer->a_streams[ MAX_A_STREAMS - 1 ]; | |
931 tivo->lastAudioEnd = 0; | |
932 tivo->lastAudioPTS = 0; | |
933 tivo->lastVideoPTS = 0; | |
934 } | |
935 // | |
936 //================= seek in MPEG ========================== | |
937 demuxer->filepos = stream_tell( demuxer->stream ); | |
938 | |
939 newpos = ( flags & 1 ) ? demuxer->movi_start : demuxer->filepos; | |
940 | |
941 if( flags & 2 ) | |
942 { | |
943 // float seek 0..1 | |
944 newpos += ( demuxer->movi_end - demuxer->movi_start ) * rel_seek_secs; | |
945 } | |
946 else | |
947 { | |
948 // time seek (secs) | |
949 if( ! sh_video->i_bps ) // unspecified or VBR | |
950 { | |
951 newpos += 2324 * 75 * rel_seek_secs; // 174.3 kbyte/sec | |
952 } | |
953 else | |
954 { | |
955 newpos += sh_video->i_bps * rel_seek_secs; | |
956 } | |
957 } | |
958 | |
959 if ( newpos < demuxer->movi_start ) | |
960 { | |
961 if( demuxer->stream->type != STREAMTYPE_VCD ) demuxer->movi_start = 0; | |
962 if( newpos < demuxer->movi_start ) newpos = demuxer->movi_start; | |
963 } | |
964 | |
965 res = newpos / CHUNKSIZE; | |
966 if ( rel_seek_secs >= 0 ) | |
967 { | |
968 newpos = ( res + 1 ) * CHUNKSIZE; | |
969 } | |
970 else | |
971 { | |
972 newpos = res * CHUNKSIZE; | |
973 } | |
974 | |
975 if ( newpos < 0 ) | |
976 { | |
977 newpos = 0; | |
978 } | |
979 stream_seek( demuxer->stream, newpos ); | |
980 | |
981 // re-sync video: | |
982 videobuf_code_len = 0; // reset ES stream buffer | |
983 | |
984 ds_fill_buffer( d_video ); | |
985 if( sh_audio ) | |
986 { | |
987 ds_fill_buffer( d_audio ); | |
988 resync_audio_stream( sh_audio ); | |
989 } | |
990 | |
991 while( 1 ) | |
992 { | |
993 int i; | |
994 if( sh_audio && !d_audio->eof && d_video->pts && d_audio->pts ) | |
995 { | |
996 float a_pts = d_audio->pts; | |
997 a_pts += ( ds_tell_pts( d_audio ) - sh_audio->a_in_buffer_len ) / | |
998 (float)sh_audio->i_bps; | |
999 if( d_video->pts > a_pts ) | |
1000 { | |
1001 skip_audio_frame( sh_audio ); // sync audio | |
1002 continue; | |
1003 } | |
1004 } | |
1005 i = sync_video_packet( d_video ); | |
1006 if( i == 0x1B3 || i == 0x1B8 ) break; // found it! | |
1007 if( !i || !skip_video_packet( d_video ) ) break; // EOF? | |
1008 } | |
1009 if ( subcc_enabled ) | |
1010 { | |
1011 ty_ClearOSD( 0 ); | |
1012 } | |
1013 } | |
1014 | |
1015 int demux_ty_control( demuxer_t *demuxer,int cmd, void *arg ) | |
1016 { | |
1017 demux_stream_t *d_video = demuxer->video; | |
1018 sh_video_t *sh_video = d_video->sh; | |
1019 | |
1020 switch(cmd) | |
1021 { | |
1022 case DEMUXER_CTRL_GET_TIME_LENGTH: | |
1023 if(!sh_video->i_bps) // unspecified or VBR | |
1024 return DEMUXER_CTRL_DONTKNOW; | |
1025 *((unsigned long *)arg)= | |
1026 (demuxer->movi_end-demuxer->movi_start)/sh_video->i_bps; | |
1027 return DEMUXER_CTRL_GUESS; | |
1028 | |
1029 case DEMUXER_CTRL_GET_PERCENT_POS: | |
1030 if (demuxer->movi_end==demuxer->movi_start) | |
1031 return DEMUXER_CTRL_DONTKNOW; | |
1032 *((int *)arg)= | |
1033 (int)((demuxer->filepos-demuxer->movi_start)/ | |
1034 ((demuxer->movi_end-demuxer->movi_start)/100)); | |
1035 return DEMUXER_CTRL_OK; | |
1036 default: | |
1037 return DEMUXER_CTRL_NOTIMPL; | |
1038 } | |
1039 } | |
1040 | |
1041 | |
1042 int demux_close_ty( demuxer_t *demux ) | |
1043 { | |
1044 TiVoInfo *tivo = 0; | |
1045 | |
1046 if ( ( demux->a_streams[ MAX_A_STREAMS - 1 ] ) != 0 ) | |
1047 { | |
1048 tivo = demux->a_streams[ MAX_A_STREAMS - 1 ]; | |
1049 free( tivo ); | |
1050 demux->a_streams[ MAX_A_STREAMS - 1 ] = 0; | |
1051 sub_justify = 0; | |
1052 } | |
1053 return( 0 ); | |
1054 } | |
1055 | |
1056 |