00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <stdlib.h>
00036 #include <vlc/vlc.h>
00037 #include <vlc/input.h>
00038 #include "vlc_codec.h"
00039
00040 #define SERIES1_PES_LENGTH (11)
00041 #define SERIES2_PES_LENGTH (16)
00042 #define AC3_PES_LENGTH (14)
00043 #define DTIVO_PTS_OFFSET (6)
00044 #define SA_PTS_OFFSET (9)
00045 #define AC3_PTS_OFFSET (9)
00046 static const unsigned char ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 };
00047 static const unsigned char ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 };
00048 static const unsigned char ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd };
00049
00050
00051
00052
00053 static int get_chunk_header(demux_t *);
00054 static void setup_audio_streams(char, demux_t *);
00055 static mtime_t get_pts( unsigned char *buf );
00056 static int find_es_header( unsigned const char *header,
00057 unsigned char *buffer, int bufferSize, int *esOffset1 );
00058 static int ty_stream_seek(demux_t *p_demux, double seek_pct);
00059
00060 static int TyOpen (vlc_object_t *);
00061 static void TyClose(vlc_object_t *);
00062 static int TyDemux(demux_t *);
00063 static int Control(demux_t *, int, va_list);
00064
00065
00066
00067
00068 vlc_module_begin();
00069 set_shortname( "TY" );
00070 set_description(_("TY Stream audio/video demux"));
00071 set_category( CAT_INPUT );
00072 set_subcategory( SUBCAT_INPUT_DEMUX );
00073 set_capability("demux2", 8);
00074
00075
00076
00077
00078 set_callbacks(TyOpen, TyClose);
00079 add_shortcut("ty");
00080 add_shortcut("tivo");
00081 vlc_module_end();
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 #define TIVO_PES_FILEID ( 0xf5467abd )
00101 #define TIVO_PART_LENGTH ( 0x20000000 )
00102 #define CHUNK_SIZE ( 128 * 1024 )
00103
00104 typedef struct
00105 {
00106 long l_rec_size;
00107 unsigned char ex1, ex2;
00108 unsigned char rec_type;
00109 unsigned char subrec_type;
00110 char b_ext;
00111 } ty_rec_hdr_t;
00112
00113 struct demux_sys_t
00114 {
00115 es_out_id_t *p_video;
00116 es_out_id_t *p_audio;
00117
00118 int i_chunk_count;
00119 int i_stuff_cnt;
00120 size_t i_stream_size;
00121 vlc_bool_t b_seekable;
00122 int tivoType;
00123 vlc_bool_t b_mpeg_audio;
00124 uint8_t pes_buffer[20];
00125 int i_pes_buf_cnt;
00126
00127 mtime_t firstAudioPTS;
00128 mtime_t lastAudioPTS;
00129 mtime_t lastVideoPTS;
00130
00131 ty_rec_hdr_t *rec_hdrs;
00132 int i_cur_rec;
00133 int i_num_recs;
00134 int i_seq_rec;
00135 vlc_bool_t eof;
00136 vlc_bool_t b_first_chunk;
00137 };
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 static int TyOpen(vlc_object_t *p_this)
00151 {
00152 demux_t *p_demux = (demux_t *)p_this;
00153 demux_sys_t *p_sys;
00154 es_format_t fmt;
00155 uint8_t *p_peek;
00156
00157
00158
00159 if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
00160 return VLC_EGENERIC;
00161
00162 if ( U32_AT(p_peek) != TIVO_PES_FILEID ||
00163 U32_AT(&p_peek[4]) != 0x02 ||
00164 U32_AT(&p_peek[8]) != CHUNK_SIZE )
00165 {
00166
00167 char *psz_ext = strrchr(p_demux->psz_path, '.');
00168
00169 if( !p_demux->b_force &&
00170 (!psz_ext || strcasecmp(psz_ext, ".ty")) ) return VLC_EGENERIC;
00171 msg_Warn( p_demux, "this does not look like a TY file, "
00172 "continuing anyway..." );
00173 }
00174
00175
00176 msg_Dbg( p_demux, "valid TY stream detected" );
00177
00178
00179 p_demux->pf_demux = TyDemux;
00180 p_demux->pf_control = Control;
00181
00182
00183 p_demux->p_sys = p_sys = malloc(sizeof(demux_sys_t));
00184 memset(p_sys, 0, sizeof(demux_sys_t));
00185
00186
00187 p_sys->b_first_chunk = VLC_TRUE;
00188 p_sys->firstAudioPTS = -1;
00189 p_sys->i_stream_size = stream_Size(p_demux->s);
00190 p_sys->b_mpeg_audio = VLC_FALSE;
00191
00192
00193 stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
00194
00195
00196
00197
00198
00199
00200
00201 p_sys->p_audio = NULL;
00202
00203
00204 es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', 'g', 'v' ) );
00205 p_sys->p_video = es_out_Add( p_demux->out, &fmt );
00206
00207 #if 0
00208
00209 es_format_Init( &fmt, SPU_ES, VLC_FOURCC('s', 'u', 'b', 't'));
00210 p_sys->p_subt_es = es_out_Add(p_demux->out, &fmt);
00211 #endif
00212
00213 return VLC_SUCCESS;
00214 }
00215
00216
00217
00218
00219 static void setup_audio_streams(char stream_type, demux_t *p_demux)
00220 {
00221 demux_sys_t *p_sys = p_demux->p_sys;
00222 es_format_t fmt;
00223
00224 if (stream_type == 'A') {
00225
00226 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', ' ' ) );
00227 p_sys->tivoType = 2;
00228 } else {
00229
00230 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
00231 p_sys->b_mpeg_audio = VLC_TRUE;
00232 }
00233
00234 p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
00235 }
00236
00237
00238
00239
00240
00241 static mtime_t get_pts( unsigned char *buf )
00242 {
00243 mtime_t i_pts;
00244
00245 i_pts = ((mtime_t)(buf[0]&0x0e ) << 29)|
00246 (mtime_t)(buf[1] << 22)|
00247 ((mtime_t)(buf[2]&0xfe) << 14)|
00248 (mtime_t)(buf[3] << 7)|
00249 (mtime_t)(buf[4] >> 1);
00250 i_pts *= 100 / 9;
00251 return i_pts;
00252 }
00253
00254
00255
00256 static int find_es_header( unsigned const char *header,
00257 unsigned char *buffer, int bufferSize, int *esOffset1 )
00258 {
00259 int count;
00260
00261 *esOffset1 = -1;
00262 for( count = 0 ; count < bufferSize ; count++ )
00263 {
00264 if ( ( buffer[ count + 0 ] == header[ 0 ] ) &&
00265 ( buffer[ count + 1 ] == header[ 1 ] ) &&
00266 ( buffer[ count + 2 ] == header[ 2 ] ) &&
00267 ( buffer[ count + 3 ] == header[ 3 ] ) )
00268 {
00269 *esOffset1 = count;
00270 return 1;
00271 }
00272 }
00273 return( -1 );
00274 }
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 static int check_sync_pes( demux_t *p_demux, block_t *p_block,
00286 int32_t offset, int32_t rec_len )
00287 {
00288 demux_sys_t *p_sys = p_demux->p_sys;
00289 int pts_offset;
00290 int pes_length = p_sys->b_mpeg_audio?SERIES1_PES_LENGTH:AC3_PES_LENGTH;
00291
00292 if( p_sys->tivoType == 1 )
00293 {
00294
00295 pts_offset = SA_PTS_OFFSET;
00296 }
00297 else
00298 {
00299
00300 pts_offset = p_sys->b_mpeg_audio?DTIVO_PTS_OFFSET:AC3_PTS_OFFSET;
00301 }
00302 if ( offset < 0 || offset + pes_length > rec_len )
00303 {
00304
00305 msg_Dbg( p_demux, "PES header at %d not complete in record. storing.",
00306 offset );
00307
00308 if( offset < 0 )
00309 {
00310
00311 memset( p_sys->pes_buffer, 4, 0 );
00312 p_sys->i_pes_buf_cnt = 4;
00313 if( rec_len > 4 )
00314 msg_Err( p_demux, "PES header not found in record of %d bytes!",
00315 rec_len );
00316 return -1;
00317 }
00318
00319 memcpy( p_sys->pes_buffer, p_block->p_buffer + offset,
00320 rec_len - offset );
00321 p_sys->i_pes_buf_cnt = rec_len - offset;
00322
00323 if( offset > 0 )
00324 {
00325
00326 p_block->i_buffer -= rec_len - offset;
00327 return 1;
00328 }
00329 return -1;
00330 }
00331
00332 p_sys->lastAudioPTS = get_pts( &p_block->p_buffer[ offset + pts_offset ] );
00333 if (p_sys->firstAudioPTS < 0)
00334 p_sys->firstAudioPTS = p_sys->lastAudioPTS;
00335 p_block->i_pts = p_sys->lastAudioPTS;
00336
00337
00338 memmove(p_block->p_buffer + offset, p_block->p_buffer + offset + pes_length,
00339 rec_len - pes_length);
00340 p_block->i_buffer -= pes_length;
00341 return 0;
00342 }
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 int TyDemux(demux_t *p_demux)
00355 {
00356 int invalidType = 0;
00357 int recordsDecoded = 0;
00358
00359 int rec_type;
00360 long l_rec_size;
00361 int i_cur_rec;
00362 int subrec_type;
00363 ty_rec_hdr_t *rec_hdr;
00364
00365 block_t *p_block_in = NULL;
00366 int esOffset1;
00367
00368 unsigned char lastCC[ 16 ];
00369 unsigned char lastXDS[ 16 ];
00370
00371 demux_sys_t *p_sys = p_demux->p_sys;
00372
00373
00374
00375
00376 if (p_sys->eof) return 0;
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 if (p_sys->b_first_chunk || p_sys->i_cur_rec >= p_sys->i_num_recs)
00394 if (get_chunk_header(p_demux) == 0)
00395 return 0;
00396
00397
00398
00399
00400 i_cur_rec = p_sys->i_cur_rec;
00401 recordsDecoded++;
00402 rec_hdr = &p_sys->rec_hdrs[ i_cur_rec ];
00403 subrec_type = rec_hdr->subrec_type;
00404 rec_type = rec_hdr->rec_type;
00405 l_rec_size = rec_hdr->l_rec_size;
00406
00407 if (!rec_hdr->b_ext)
00408 {
00409
00410
00411
00412
00413 if (l_rec_size > 0)
00414 {
00415
00416 if( !( p_block_in = stream_Block( p_demux->s, l_rec_size ) ) )
00417 {
00418
00419 p_sys->eof = 1;
00420 return 0;
00421 }
00422
00423 p_block_in->i_pts = p_block_in->i_dts = 0;
00424 }
00425 else
00426 {
00427
00428 p_sys->i_cur_rec++;
00429 return 1;
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 if ( rec_type == 0xe0 )
00444 {
00445 if( subrec_type == 0x06 )
00446 {
00447
00448
00449 find_es_header( ty_VideoPacket, p_block_in->p_buffer,
00450 l_rec_size, &esOffset1 );
00451 if ( esOffset1 != -1 )
00452 {
00453
00454 p_sys->lastVideoPTS = get_pts( &p_block_in->p_buffer[ esOffset1 + 9 ] );
00455
00456
00457 }
00458 block_Release(p_block_in);
00459 }
00460 else
00461 {
00462 #if 0
00463 msg_Dbg(p_demux, "packet buffer has "
00464 "%02x %02x %02x %02x %02x %02x %02x %02x "
00465 "%02x %02x %02x %02x %02x %02x %02x %02x",
00466 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
00467 p_block_in->p_buffer[2], p_block_in->p_buffer[3],
00468 p_block_in->p_buffer[4], p_block_in->p_buffer[5],
00469 p_block_in->p_buffer[6], p_block_in->p_buffer[7],
00470 p_block_in->p_buffer[8], p_block_in->p_buffer[9],
00471 p_block_in->p_buffer[10], p_block_in->p_buffer[11],
00472 p_block_in->p_buffer[12], p_block_in->p_buffer[13],
00473 p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
00474 #endif
00475
00476 if (subrec_type != 0x02)
00477 {
00478
00479
00480
00481
00482
00483
00484 if (subrec_type == 0x0c && l_rec_size >= 6)
00485 p_block_in->p_buffer[5] |= 0x08;
00486
00487 if (p_sys->lastVideoPTS > 0)
00488 {
00489 p_block_in->i_pts = p_sys->lastVideoPTS;
00490
00491
00492
00493 p_sys->lastVideoPTS = 0;
00494 }
00495 }
00496 es_out_Send(p_demux->out, p_sys->p_video, p_block_in);
00497 }
00498 }
00499
00500
00501
00502
00503
00504 else if ( rec_type == 0xc0 )
00505 {
00506 #if 0
00507 int i;
00508 printf( "Audio Packet Header " );
00509 for( i = 0 ; i < 24 ; i++ )
00510 printf( "%2.2x ", p_block_in->p_buffer[i] );
00511 printf( "\n" );
00512 #endif
00513
00514 if ( p_sys->p_audio == NULL )
00515 {
00516 if ( subrec_type == 0x09 )
00517 {
00518
00519 msg_Dbg(p_demux, "detected AC-3 Audio" );
00520 setup_audio_streams('A', p_demux);
00521 }
00522 else
00523 {
00524
00525 msg_Dbg(p_demux, "detected MPEG Audio" );
00526 setup_audio_streams('M', p_demux);
00527 }
00528 }
00529
00530
00531
00532
00533 if ( subrec_type == 2 )
00534 {
00535
00536
00537 if (p_sys->i_pes_buf_cnt > 0)
00538 {
00539 int i_need = SERIES1_PES_LENGTH - p_sys->i_pes_buf_cnt;
00540
00541 msg_Dbg(p_demux, "continuing PES header");
00542
00543 if (i_need < l_rec_size)
00544 {
00545
00546 memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
00547 p_block_in->p_buffer, i_need);
00548
00549 p_block_in->p_buffer += i_need;
00550 p_block_in->i_buffer -= i_need;
00551
00552 if (p_sys->b_mpeg_audio)
00553 find_es_header(ty_MPEGAudioPacket, p_sys->pes_buffer,
00554 10, &esOffset1);
00555 else
00556 find_es_header(ty_AC3AudioPacket, p_sys->pes_buffer,
00557 10, &esOffset1);
00558 if (esOffset1 < 0)
00559 {
00560
00561 msg_Err(p_demux, "can't find audio PES header in packet");
00562 }
00563 else
00564 {
00565 p_sys->lastAudioPTS = get_pts(
00566 &p_sys->pes_buffer[ esOffset1 + DTIVO_PTS_OFFSET ] );
00567 p_block_in->i_pts = p_sys->lastAudioPTS;
00568 }
00569 p_sys->i_pes_buf_cnt = 0;
00570 }
00571 else
00572 {
00573
00574 memcpy(&p_sys->pes_buffer[p_sys->i_pes_buf_cnt],
00575 p_block_in->p_buffer, l_rec_size);
00576 p_sys->i_pes_buf_cnt += l_rec_size;
00577 p_sys->i_cur_rec++;
00578 block_Release(p_block_in);
00579 return 1;
00580 }
00581 }
00582
00583
00584
00585 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
00586 }
00587
00588
00589
00590 if ( subrec_type == 0x03 )
00591 {
00592 find_es_header( ty_MPEGAudioPacket, p_block_in->p_buffer,
00593 l_rec_size, &esOffset1 );
00594
00595
00596
00597
00598
00599
00600
00601
00602 if ( ( esOffset1 == 0 ) && ( l_rec_size == 16 ) )
00603 {
00604 p_sys->tivoType = 1;
00605 p_sys->lastAudioPTS = get_pts( &p_block_in->p_buffer[
00606 SA_PTS_OFFSET ] );
00607 if (p_sys->firstAudioPTS < 0)
00608 p_sys->firstAudioPTS = p_sys->lastAudioPTS;
00609 block_Release(p_block_in);
00610
00611
00612 }
00613 else
00614
00615
00616 {
00617 p_sys->tivoType = 2;
00618
00619
00620
00621 if (check_sync_pes(p_demux, p_block_in, esOffset1,
00622 l_rec_size) == -1)
00623 {
00624
00625
00626 p_sys->i_cur_rec++;
00627 block_Release(p_block_in);
00628 return 1;
00629 }
00630 #if 0
00631 msg_Dbg(p_demux, "packet buffer has "
00632 "%02x %02x %02x %02x %02x %02x %02x %02x "
00633 "%02x %02x %02x %02x %02x %02x %02x %02x",
00634 p_block_in->p_buffer[0], p_block_in->p_buffer[1],
00635 p_block_in->p_buffer[2], p_block_in->p_buffer[3],
00636 p_block_in->p_buffer[4], p_block_in->p_buffer[5],
00637 p_block_in->p_buffer[6], p_block_in->p_buffer[7],
00638 p_block_in->p_buffer[8], p_block_in->p_buffer[9],
00639 p_block_in->p_buffer[10], p_block_in->p_buffer[11],
00640 p_block_in->p_buffer[12], p_block_in->p_buffer[13],
00641 p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
00642 #endif
00643
00644 if( p_block_in->i_pts > 0 )
00645 es_out_Control( p_demux->out, ES_OUT_SET_PCR,
00646 p_block_in->i_pts );
00647 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
00648 }
00649 }
00650
00651
00652
00653 if ( subrec_type == 0x04 )
00654 {
00655
00656
00657
00658
00659 if (p_sys->lastAudioPTS > 0)
00660 {
00661 p_block_in->i_pts = p_sys->lastAudioPTS;
00662 es_out_Control( p_demux->out, ES_OUT_SET_PCR,
00663 p_block_in->i_pts );
00664 }
00665 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
00666 }
00667
00668
00669
00670 if ( subrec_type == 0x09 )
00671 {
00672 find_es_header( ty_AC3AudioPacket, p_block_in->p_buffer,
00673 l_rec_size, &esOffset1 );
00674
00675
00676
00677
00678
00679
00680
00681 if (check_sync_pes(p_demux, p_block_in, esOffset1,
00682 l_rec_size) == -1)
00683 {
00684
00685 p_sys->i_cur_rec++;
00686 return 1;
00687 }
00688
00689 if( p_block_in->i_pts > 0 )
00690 {
00691 es_out_Control( p_demux->out, ES_OUT_SET_PCR,
00692 p_block_in->i_pts );
00693 }
00694 es_out_Send( p_demux->out, p_sys->p_audio, p_block_in );
00695 }
00696 }
00697
00698
00699
00700 else if ( rec_type == 0x01 )
00701 {
00702
00703
00704
00705
00706 lastCC[ 0x00 ] = 0x00;
00707 lastCC[ 0x01 ] = 0x00;
00708 lastCC[ 0x02 ] = 0x01;
00709 lastCC[ 0x03 ] = 0xb2;
00710 lastCC[ 0x04 ] = 'T';
00711 lastCC[ 0x05 ] = 'Y';
00712 lastCC[ 0x06 ] = 0x01;
00713 lastCC[ 0x07 ] = rec_hdr->ex1;
00714 lastCC[ 0x08 ] = rec_hdr->ex2;
00715
00716
00717
00718
00719 }
00720 else if ( rec_type == 0x02 )
00721 {
00722
00723
00724
00725 lastXDS[ 0x00 ] = 0x00;
00726 lastXDS[ 0x01 ] = 0x00;
00727 lastXDS[ 0x02 ] = 0x01;
00728 lastXDS[ 0x03 ] = 0xb2;
00729 lastXDS[ 0x04 ] = 'T';
00730 lastXDS[ 0x05 ] = 'Y';
00731 lastXDS[ 0x06 ] = 0x02;
00732 lastXDS[ 0x07 ] = rec_hdr->ex1;
00733 lastXDS[ 0x08 ] = rec_hdr->ex2;
00734
00735
00736
00737 }
00738
00739
00740
00741 else if ( rec_type == 0x03 )
00742 {
00743 }
00744
00745
00746
00747 else if ( rec_type == 0x05 )
00748 {
00749 }
00750 else
00751 {
00752 msg_Dbg(p_demux, "Invalid record type 0x%02x", rec_type );
00753 if (p_block_in) block_Release(p_block_in);
00754 invalidType++;
00755 }
00756 p_sys->i_cur_rec++;
00757 return 1;
00758 }
00759
00760
00761
00762 static int ty_stream_seek(demux_t *p_demux, double seek_pct)
00763 {
00764 demux_sys_t *p_sys = p_demux->p_sys;
00765 int64_t seek_pos = p_sys->i_stream_size * seek_pct;
00766 int i;
00767 long l_skip_amt;
00768
00769
00770 if (!p_sys->b_seekable)
00771 return VLC_EGENERIC;
00772
00773
00774 p_sys->i_chunk_count = seek_pos / CHUNK_SIZE;
00775
00776 if ( stream_Seek( p_demux->s, p_sys->i_chunk_count * CHUNK_SIZE))
00777 {
00778
00779 return VLC_EGENERIC;
00780 }
00781
00782 get_chunk_header(p_demux);
00783
00784
00785 p_sys->i_cur_rec = (int)
00786 ((double) ((seek_pos % CHUNK_SIZE) / (double) (CHUNK_SIZE)) * p_sys->i_num_recs);
00787 msg_Dbg(p_demux, "Seeked to file pos " I64Fd, seek_pos);
00788 msg_Dbg(p_demux, " (chunk %d, record %d)",
00789 p_sys->i_chunk_count - 1, p_sys->i_cur_rec);
00790
00791
00792
00793 l_skip_amt = 0;
00794 for (i=0; i<p_sys->i_cur_rec; i++)
00795 l_skip_amt += p_sys->rec_hdrs[i].l_rec_size;
00796 stream_Seek(p_demux->s, ((p_sys->i_chunk_count-1) * CHUNK_SIZE) +
00797 (p_sys->i_num_recs * 16) + l_skip_amt + 4);
00798
00799
00800
00801 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
00802 return VLC_SUCCESS;
00803 }
00804
00805
00806 static int Control(demux_t *p_demux, int i_query, va_list args)
00807 {
00808 demux_sys_t *p_sys = p_demux->p_sys;
00809 double f, *pf;
00810 int64_t i64, *p_i64;
00811
00812
00813 switch( i_query )
00814 {
00815 case DEMUX_GET_POSITION:
00816
00817 if( ( i64 = p_sys->i_stream_size ) > 0 )
00818 {
00819 pf = (double*) va_arg( args, double* );
00820 *pf = (double)stream_Tell( p_demux->s ) / (double) i64;
00821 return VLC_SUCCESS;
00822 }
00823 return VLC_EGENERIC;
00824
00825 case DEMUX_SET_POSITION:
00826
00827 f = (double) va_arg( args, double );
00828
00829 if ((i64 = p_sys->i_stream_size) > 0)
00830 return ty_stream_seek(p_demux, f);
00831 return VLC_EGENERIC;
00832 case DEMUX_GET_TIME:
00833
00834 p_i64 = (int64_t *) va_arg(args, int64_t *);
00835 *p_i64 = p_sys->lastAudioPTS - p_sys->firstAudioPTS;
00836 return VLC_SUCCESS;
00837 case DEMUX_SET_TIME:
00838 case DEMUX_GET_LENGTH:
00839 case DEMUX_GET_FPS:
00840 default:
00841 return VLC_EGENERIC;
00842 }
00843 }
00844
00845
00846
00847 static void TyClose( vlc_object_t *p_this )
00848 {
00849 demux_sys_t *p_sys = ((demux_t *) p_this)->p_sys;
00850
00851 free(p_sys->rec_hdrs);
00852 free(p_sys);
00853 }
00854
00855
00856
00857 static int get_chunk_header(demux_t *p_demux)
00858 {
00859 int i_readSize, i_num_recs, i;
00860 uint8_t packet_header[4];
00861 uint8_t record_header[16];
00862 ty_rec_hdr_t *p_rec_hdr;
00863 demux_sys_t *p_sys = p_demux->p_sys;
00864 int i_payload_size = 0;
00865
00866 msg_Dbg(p_demux, "parsing ty chunk #%d", p_sys->i_chunk_count );
00867
00868
00869 if (p_sys->i_stuff_cnt > 0)
00870 stream_Read( p_demux->s, NULL, p_sys->i_stuff_cnt);
00871
00872
00873 i_readSize = stream_Read( p_demux->s, packet_header, 4 );
00874 p_sys->i_chunk_count++;
00875
00876 if ( i_readSize < 4 )
00877 {
00878
00879 p_sys->eof = 1;
00880 return 0;
00881 }
00882
00883
00884 if( U32_AT( &packet_header[ 0 ] ) == TIVO_PES_FILEID )
00885 {
00886 msg_Dbg( p_demux, "skipping TY PART Header" );
00887
00888 stream_Read( p_demux->s, NULL, CHUNK_SIZE - 4 );
00889 return get_chunk_header(p_demux);
00890 }
00891
00892
00893 if (packet_header[3] & 0x80)
00894 {
00895
00896 p_sys->i_num_recs = i_num_recs = (packet_header[1] << 8) + packet_header[0];
00897 p_sys->i_seq_rec = (packet_header[3] << 8) + packet_header[2];
00898 if (p_sys->i_seq_rec != 0xffff)
00899 {
00900 p_sys->i_seq_rec &= ~0x8000;
00901 }
00902 }
00903 else
00904 {
00905
00906 p_sys->i_num_recs = i_num_recs = packet_header[0];
00907 p_sys->i_seq_rec = packet_header[1];
00908 }
00909 p_sys->i_cur_rec = 0;
00910 p_sys->b_first_chunk = VLC_FALSE;
00911
00912
00913
00914
00915 if (p_sys->rec_hdrs)
00916 free(p_sys->rec_hdrs);
00917 p_sys->rec_hdrs = malloc(i_num_recs * sizeof(ty_rec_hdr_t));
00918 for (i = 0; i < i_num_recs; i++)
00919 {
00920 i_readSize = stream_Read( p_demux->s, record_header, 16 );
00921 if (i_readSize < 16)
00922 {
00923
00924 p_sys->eof = VLC_TRUE;
00925 return 0;
00926 }
00927 p_rec_hdr = &p_sys->rec_hdrs[i];
00928 p_rec_hdr->rec_type = record_header[3];
00929 p_rec_hdr->subrec_type = record_header[2] & 0x0f;
00930 if ((record_header[ 0 ] & 0x80) == 0x80)
00931 {
00932 unsigned char b1, b2;
00933
00934 b1 = ( ( ( record_header[ 0 ] & 0x0f ) << 4 ) |
00935 ( ( record_header[ 1 ] & 0xf0 ) >> 4 ) );
00936 b1 &= 0x7f;
00937 b2 = ( ( ( record_header[ 1 ] & 0x0f ) << 4 ) |
00938 ( ( record_header[ 2 ] & 0xf0 ) >> 4 ) );
00939 b2 &= 0x7f;
00940
00941 p_rec_hdr->ex1 = b1;
00942 p_rec_hdr->ex2 = b2;
00943 p_rec_hdr->l_rec_size = 0;
00944 p_rec_hdr->b_ext = VLC_TRUE;
00945 }
00946 else
00947 {
00948 p_rec_hdr->l_rec_size = ( record_header[ 0 ] << 8 |
00949 record_header[ 1 ] ) << 4 | ( record_header[ 2 ] >> 4 );
00950 i_payload_size += p_rec_hdr->l_rec_size;
00951 p_rec_hdr->b_ext = VLC_FALSE;
00952 }
00953 }
00954 p_sys->i_stuff_cnt = CHUNK_SIZE - 4 -
00955 (p_sys->i_num_recs * 16) - i_payload_size;
00956 if (p_sys->i_stuff_cnt > 0)
00957 msg_Dbg( p_demux, "chunk has %d stuff bytes at end",
00958 p_sys->i_stuff_cnt );
00959 return 1;
00960 }