Commit 97c3185d authored by Stéphane Borel's avatar Stéphane Borel

 First serie of changes in DVD module for the forthcoming interface menus
 There is a new capability in input type modules for setting the
attributes of a new area. It is set to NULL for PS and TS plugins.
 It should be called for every title change, chapter change,
audio mode change or spu channel change.

But this part of code is not used at the moment, and is not completed
yet.
parent a6fe4de4
......@@ -2,7 +2,7 @@
* input.h: structures of the input not exported to other modules
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input.h,v 1.29 2001/02/12 13:20:14 massiot Exp $
* $Id: input.h,v 1.30 2001/02/20 02:53:13 stef Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -57,6 +57,8 @@ struct pgrm_descriptor_s * input_FindProgram( struct input_thread_s *, u16 );
struct pgrm_descriptor_s * input_AddProgram ( struct input_thread_s *,
u16, size_t );
void input_DelProgram( struct input_thread_s *, struct pgrm_descriptor_s * );
struct input_area_s * input_AddArea( struct input_thread_s * );
void input_DelArea ( struct input_thread_s *, struct input_area_s * );
void input_DumpStream( struct input_thread_s * );
struct es_descriptor_s * input_FindES( struct input_thread_s *, u16 );
struct es_descriptor_s * input_AddES ( struct input_thread_s *,
......
......@@ -4,7 +4,7 @@
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.22 2001/02/19 19:08:59 massiot Exp $
* $Id: input_ext-intf.h,v 1.23 2001/02/20 02:53:13 stef Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -50,6 +50,9 @@ typedef struct es_descriptor_s
boolean_t b_audio; /* is the stream an audio stream that
* will need to be discarded with
* fast forward and slow motion ? */
char psz_desc[20]; /* description of ES: audio language
* for instance ; NULL if not
* available */
/* Demultiplexer information */
void * p_demux_data;
......@@ -131,6 +134,33 @@ typedef struct pgrm_descriptor_s
#define SYNCHRO_START 1
#define SYNCHRO_REINIT 2
/*****************************************************************************
* input_area_t
*****************************************************************************
* Attributes for current area (title for DVD)
*****************************************************************************/
typedef struct input_area_s
{
/* selected area attributes */
int i_id; /* identificator for area */
off_t i_start; /* start offset of area */
off_t i_size; /* total size of the area
* (in arbitrary units) */
/* navigation parameters */
off_t i_tell; /* actual location in the area
* (in arbitrary units) */
off_t i_seek; /* next requested location
* (changed by the interface thread */
/* area subdivision */
int i_part_nb; /* number of parts (chapter for DVD)*/
int i_part; /* currently selected part */
/* offset to plugin related data */
off_t i_plugin_data;
} input_area_t;
/*****************************************************************************
* stream_descriptor_t
*****************************************************************************
......@@ -146,26 +176,14 @@ typedef struct stream_descriptor_s
/* Input method data */
boolean_t b_pace_control; /* can we read when we want ? */
boolean_t b_seekable; /* can we do lseek() ? */
/* if (b_seekable) : */
off_t i_size; /* total size of the file
* (in arbitrary units) */
off_t i_tell; /* actual location in the file
* (in arbitrary units) */
off_t i_seek; /* next requested location (changed
* by the interface thread */
int i_area_nb;
input_area_t ** pp_areas; /* list of areas in stream == offset
* interval with own properties */
u32 i_mux_rate; /* the rate we read the stream (in
* units of 50 bytes/s) ; 0 if undef */
/* For DVD streams: */
int i_title_nb;
int * pi_chapter; /* Number of chapter for each title */
char ** ppsz_audio; /* Audio language names */
char ** ppsz_spu; /* Sub-pictures names */
int i_title; /* selected title */
int i_chapter; /* selected chapter */
int i_audio; /* selected audio stream */
int i_spu; /* selected spu */
/* New status and rate requested by the interface */
int i_new_status, i_new_rate;
vlc_cond_t stream_wait; /* interface -> input in case of a
......
......@@ -81,6 +81,9 @@ typedef struct function_list_s
void ( * pf_close )( struct input_thread_s * );
void ( * pf_end ) ( struct input_thread_s * );
int ( * pf_set_area ) ( struct input_thread_s *,
int, int, int, int );
int ( * pf_read ) ( struct input_thread_s *,
struct data_packet_s *
pp_packets[] );
......
......@@ -2,7 +2,7 @@
* dvd_css.c: Functions for DVD authentification and unscrambling
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_css.c,v 1.10 2001/02/18 01:42:04 stef Exp $
* $Id: dvd_css.c,v 1.11 2001/02/20 02:53:13 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -659,8 +659,8 @@ static void CSSCryptKey( int i_key_type, int i_varient,
static int CSSCracker( int i_start,
unsigned char * p_crypted,
unsigned char * p_decrypted,
DVD_key_t * p_sector_key,
DVD_key_t * p_key )
dvd_key_t * p_sector_key,
dvd_key_t * p_key )
{
unsigned char pi_buffer[10];
unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
......@@ -1027,19 +1027,19 @@ css_t CSSInit( int i_fd )
}
/*****************************************************************************
* CSSGetKeys : get the title keys.
* CSSGetKey : get title key.
* The DVD should have been opened and authenticated before.
*****************************************************************************/
int CSSGetKeys( css_t * p_css )
int CSSGetKey( css_t * p_css )
{
/*
* Title key cracking method from Ethan Hawke,
* with Frank A. Stevenson algorithm.
* Does not use any player key table and ioctls.
*/
u8 pi_buf[0x800] ;
DVD_key_t key;
title_key_t p_title_key[10] ;
u8 pi_buf[0x800];
dvd_key_t pi_key;
title_key_t p_title_key[10];
off_t i_pos;
boolean_t b_encrypted;
boolean_t b_stop_scanning;
......@@ -1052,163 +1052,160 @@ int CSSGetKeys( css_t * p_css )
int i_highest;
int i,j,k;
for( i_title = 0 ; i_title < p_css->i_title_nb ; i_title++ )
{
/* Initialization for each title */
memset( p_title_key, 0, 10 );
memset( &key, 0, 10 );
b_encrypted = 0;
b_stop_scanning = 0;
i_registered_keys = 0 ;
i_total_keys_found = 0 ;
i_highest = 0;
/* Position of the title on the disc */
i_pos = p_css->p_title_key[i_title].i;
memset( p_title_key, 0, 10 );
memset( &pi_key, 0, 10 );
b_encrypted = 0;
b_stop_scanning = 0;
i_registered_keys = 0 ;
i_total_keys_found = 0 ;
i_highest = 0;
/* Position of the title on the disc */
i_title = p_css->i_title;
i_pos = p_css->i_title_pos;
//fprintf( stderr, "CSS %d start pos: %lld\n", i_title, i_pos );
do {
i_pos = lseek( p_css->i_fd, i_pos, SEEK_SET );
i_bytes_read = read( p_css->i_fd, pi_buf, 0x800 );
do {
i_pos = lseek( p_css->i_fd, i_pos, SEEK_SET );
i_bytes_read = read( p_css->i_fd, pi_buf, 0x800 );
/* PES_scrambling_control */
if( pi_buf[0x14] & 0x30 )
{
b_encrypted = 1;
i_best_plen = 0;
i_best_p = 0;
/* PES_scrambling_control */
if( pi_buf[0x14] & 0x30 )
{
b_encrypted = 1;
i_best_plen = 0;
i_best_p = 0;
for( i = 2 ; i < 0x30 ; i++ )
for( i = 2 ; i < 0x30 ; i++ )
{
for( j = i ; ( j < 0x80 ) &&
( pi_buf[0x7F - (j%i)] == pi_buf[0x7F-j] ) ; j++ );
{
for( j = i ; ( j < 0x80 ) &&
( pi_buf[0x7F - (j%i)] == pi_buf[0x7F-j] ) ; j++ );
if( ( j > i_best_plen ) && ( j > i ) )
{
if( ( j > i_best_plen ) && ( j > i ) )
{
i_best_plen = j;
i_best_p = i;
}
i_best_plen = j;
i_best_p = i;
}
}
}
if( ( i_best_plen > 20 ) && ( i_best_plen / i_best_p >= 2) )
if( ( i_best_plen > 20 ) && ( i_best_plen / i_best_p >= 2) )
{
i = CSSCracker( 0, &pi_buf[0x80],
&pi_buf[0x80 - ( i_best_plen / i_best_p) *i_best_p],
(dvd_key_t*)&pi_buf[0x54],
&pi_key );
while( i>=0 )
{
i = CSSCracker( 0, &pi_buf[0x80],
&pi_buf[0x80 - ( i_best_plen / i_best_p) *i_best_p],
(DVD_key_t*)&pi_buf[0x54],
&key );
while( i>=0 )
k = 0;
for( j=0 ; j<i_registered_keys ; j++ )
{
k = 0;
for( j=0 ; j<i_registered_keys ; j++ )
if( memcmp( &(p_title_key[j].pi_key),
&pi_key, sizeof(dvd_key_t) ) == 0 )
{
if( memcmp( &(p_title_key[j].key),
&key, sizeof(DVD_key_t) ) == 0 )
{
p_title_key[j].i++;
i_total_keys_found++;
k = 1;
}
}
if( k == 0 )
{
memcpy( &(p_title_key[i_registered_keys].key),
&key, sizeof(DVD_key_t) );
p_title_key[i_registered_keys++].i = 1;
p_title_key[j].i_occ++;
i_total_keys_found++;
k = 1;
}
i = CSSCracker( i, &pi_buf[0x80],
&pi_buf[0x80 -( i_best_plen / i_best_p) *i_best_p],
(DVD_key_t*)&pi_buf[0x54], &key);
}
/* Stop search if we find one occurance of the key
* I have never found a DVD for which it is not enough
* but we should take care of that */
if( i_registered_keys == 1 && p_title_key[0].i >= 1 )
if( k == 0 )
{
b_stop_scanning = 1;
memcpy( &(p_title_key[i_registered_keys].pi_key),
&pi_key, sizeof(dvd_key_t) );
p_title_key[i_registered_keys++].i_occ = 1;
i_total_keys_found++;
}
i = CSSCracker( i, &pi_buf[0x80],
&pi_buf[0x80 - ( i_best_plen / i_best_p) *i_best_p],
(dvd_key_t*)&pi_buf[0x54], &pi_key);
}
/* Stop search if we find one occurance of the key
* I have never found a DVD for which it is not enough
* but we should take care of that */
if( i_registered_keys == 1 && p_title_key[0].i_occ >= 1 )
{
b_stop_scanning = 1;
}
}
}
i_pos += i_bytes_read;
} while( i_bytes_read == 0x800 && !b_stop_scanning);
i_pos += i_bytes_read;
} while( i_bytes_read == 0x800 && !b_stop_scanning);
if( b_stop_scanning)
{
intf_WarnMsg( 1,
"CSS: Found enough occurancies of the same key." );
}
if( b_stop_scanning)
{
intf_WarnMsg( 1,
"CSS: Found enough occurancies of the same key." );
}
if( !b_encrypted )
{
intf_WarnMsg( 3, "CSS: This file was _NOT_ encrypted!");
return(0);
}
if( !b_encrypted )
{
intf_WarnMsg( 3, "CSS: This file was _NOT_ encrypted!");
return(0);
}
if( b_encrypted && i_registered_keys == 0 )
{
intf_ErrMsg( "CSS: Unable to determine keys from file.");
return(1);
}
if( b_encrypted && i_registered_keys == 0 )
{
intf_ErrMsg( "CSS: Unable to determine keys from file.");
return(1);
}
for( i = 0 ; i < i_registered_keys - 1 ; i++ )
for( i = 0 ; i < i_registered_keys - 1 ; i++ )
{
for( j = i + 1 ; j < i_registered_keys ; j++ )
{
for( j = i + 1 ; j < i_registered_keys ; j++ )
if( p_title_key[j].i_occ > p_title_key[i].i_occ )
{
if( p_title_key[j].i > p_title_key[i].i )
{
memcpy( &key, &(p_title_key[j].key), sizeof(DVD_key_t) );
k = p_title_key[j].i;
memcpy( &pi_key, &(p_title_key[j].pi_key), sizeof(dvd_key_t) );
k = p_title_key[j].i_occ;
memcpy( &(p_title_key[j].key),
&(p_title_key[i].key), sizeof(DVD_key_t) );
p_title_key[j].i = p_title_key[i].i;
memcpy( &(p_title_key[j].pi_key),
&(p_title_key[i].pi_key), sizeof(dvd_key_t) );
p_title_key[j].i_occ = p_title_key[i].i_occ;
memcpy( &(p_title_key[i].key),&key, sizeof(DVD_key_t) );
p_title_key[i].i = k;
}
memcpy( &(p_title_key[i].pi_key),&pi_key, sizeof(dvd_key_t) );
p_title_key[i].i_occ = k;
}
}
}
#ifdef STATS
intf_WarnMsg( 1, " Key(s) & key probability\n---------------------");
intf_WarnMsg( 1, " Key(s) & key probability\n---------------------");
#endif
for( i=0 ; i<i_registered_keys ; i++ )
{
for( i=0 ; i<i_registered_keys ; i++ )
{
#ifdef STATS
intf_WarnMsg( 1, "%d) %02X %02X %02X %02X %02X - %3.2f%%", i,
p_title_key[i].key[0], p_title_key[i].key[1],
p_title_key[i].key[2], p_title_key[i].key[3],
p_title_key[i].key[4],
p_title_key[i].i * 100.0 / i_total_keys_found );
intf_WarnMsg( 1, "%d) %02X %02X %02X %02X %02X - %3.2f%%", i,
p_title_key[i].key[0], p_title_key[i].key[1],
p_title_key[i].key[2], p_title_key[i].key[3],
p_title_key[i].key[4],
p_title_key[i].i_occ * 100.0 / i_total_keys_found );
#endif
if( p_title_key[i_highest].i * 100.0 / i_total_keys_found
<= p_title_key[i].i*100.0 / i_total_keys_found )
{
i_highest = i;
}
if( p_title_key[i_highest].i_occ * 100.0 / i_total_keys_found
<= p_title_key[i].i_occ*100.0 / i_total_keys_found )
{
i_highest = i;
}
}
/* The "find the key with the highest probability" code
* is untested, as I haven't been able to find a VOB that
* produces multiple keys (RT)
*/
intf_WarnMsg( 3, "CSS: Title %d key: %02X %02X %02X %02X %02X",
i_title + 1,
p_title_key[i_highest].key[0],
p_title_key[i_highest].key[1],
p_title_key[i_highest].key[2],
p_title_key[i_highest].key[3],
p_title_key[i_highest].key[4] );
memcpy( p_css->p_title_key[i_title].key,
p_title_key[i_highest].key, KEY_SIZE );
}
/* The "find the key with the highest probability" code
* is untested, as I haven't been able to find a VOB that
* produces multiple keys (RT)
*/
intf_WarnMsg( 3, "CSS: Title %d key: %02X %02X %02X %02X %02X",
i_title + 1,
p_title_key[i_highest].pi_key[0],
p_title_key[i_highest].pi_key[1],
p_title_key[i_highest].pi_key[2],
p_title_key[i_highest].pi_key[3],
p_title_key[i_highest].pi_key[4] );
memcpy( p_css->pi_title_key,
p_title_key[i_highest].pi_key, KEY_SIZE );
return 0;
}
......@@ -1219,7 +1216,7 @@ int CSSGetKeys( css_t * p_css )
* sec : sector to descramble
* key : title key for this sector
*****************************************************************************/
int CSSDescrambleSector( DVD_key_t key, u8* pi_sec )
int CSSDescrambleSector( dvd_key_t pi_key, u8* pi_sec )
{
unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
u8* pi_end = pi_sec + 0x800;
......@@ -1227,10 +1224,10 @@ int CSSDescrambleSector( DVD_key_t key, u8* pi_sec )
/* PES_scrambling_control */
if( pi_sec[0x14] & 0x30)
{
i_t1 = ((key)[0] ^ pi_sec[0x54]) | 0x100;
i_t2 = (key)[1] ^ pi_sec[0x55];
i_t3 = (((key)[2]) | ((key)[3] << 8) |
((key)[4] << 16)) ^ ((pi_sec[0x56]) |
i_t1 = ((pi_key)[0] ^ pi_sec[0x54]) | 0x100;
i_t2 = (pi_key)[1] ^ pi_sec[0x55];
i_t3 = (((pi_key)[2]) | ((pi_key)[3] << 8) |
((pi_key)[4] << 16)) ^ ((pi_sec[0x56]) |
(pi_sec[0x57] << 8) | (pi_sec[0x58] << 16));
i_t4 = i_t3 & 7;
i_t3 = i_t3 * 2 + 8 - i_t4;
......
......@@ -2,7 +2,7 @@
* dvd_css.h: Structures for DVD authentification and unscrambling
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_css.h,v 1.3 2001/02/15 21:03:27 stef Exp $
* $Id: dvd_css.h,v 1.4 2001/02/20 02:53:13 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -10,7 +10,7 @@
* - css-auth by Derek Fawcus <derek@spider.com>
* - DVD CSS ioctls example program by Andrew T. Veliath <andrewtv@usa.net>
* - DeCSSPlus by Ethan Hawke
* - The Divide and conquer attack by Frank A. Stevenson<frank@funcom.com>
* - The Divide and conquer attack by Frank A. Stevenson <frank@funcom.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -28,24 +28,21 @@
*****************************************************************************/
#define KEY_SIZE 5
typedef u8 DVD_key_t[KEY_SIZE];
typedef u8 dvd_key_t[KEY_SIZE];
typedef struct disc_s
{
u8 pi_challenge[2*KEY_SIZE];
u8 pi_key1[KEY_SIZE];
u8 pi_key2[KEY_SIZE];
u8 pi_key_check[KEY_SIZE];
dvd_key_t pi_key1;
dvd_key_t pi_key2;
dvd_key_t pi_key_check;
u8 i_varient;
} disc_t;
typedef struct title_key_s
{
off_t i; /* This signification of this parameter
depends on the function it is called from :
*from DVDInit -> i == position
*from CSSGetKeys -> i == nb occurence */
DVD_key_t key;
int i_occ;
dvd_key_t pi_key;
} title_key_t;
typedef struct css_s
......@@ -55,6 +52,7 @@ typedef struct css_s
int i_agid;
disc_t disc;
u8 pi_disc_key[2048];
int i_title_nb;
title_key_t* p_title_key;
int i_title;
off_t i_title_pos;
dvd_key_t pi_title_key;
} css_t;
......@@ -2,7 +2,7 @@
* dvd_ifo.c: Functions for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_ifo.c,v 1.10 2001/02/19 03:12:26 stef Exp $
* $Id: dvd_ifo.c,v 1.11 2001/02/20 02:53:13 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -41,7 +41,11 @@
#include "dvd_udf.h"
#include "input_dvd.h"
void CommandRead( ifo_command_t );
/*
* Local prototypes
*/
static vmg_t ReadVMG ( ifo_t* );
void CommandRead( ifo_command_t );
/*
* IFO Management.
......@@ -64,6 +68,10 @@ ifo_t IfoInit( int i_fd )
ifo.i_off = (off_t)(i_lba) * DVD_LB_SIZE;
ifo.i_pos = lseek( ifo.i_fd, ifo.i_off, SEEK_SET );
/* Video Manager Initialization */
intf_WarnMsg( 2, "ifo: initializing VMG" );
ifo.vmg = ReadVMG( &ifo );
return ifo;
}
......@@ -72,6 +80,7 @@ ifo_t IfoInit( int i_fd )
*****************************************************************************/
void IfoEnd( ifo_t* p_ifo )
{
#if 0
int i,j;
/* Free structures from video title sets */
......@@ -121,7 +130,7 @@ void IfoEnd( ifo_t* p_ifo )
free( p_ifo->vmg.pgc.com_tab.p_cell_com );
free( p_ifo->vmg.pgc.com_tab.p_post_com );
free( p_ifo->vmg.pgc.com_tab.p_pre_com );
#endif
return;
}
......@@ -215,11 +224,12 @@ static pgc_t ReadPGC( ifo_t* p_ifo )
int i;
off_t i_start = p_ifo->i_pos;
//fprintf( stderr, "PGC\n" );
fprintf( stderr, "PGC\n" );
FLUSH(2);
GETC( &pgc.i_prg_nb );
GETC( &pgc.i_cell_nb );
fprintf( stderr, "PGC: Prg: %d Cell: %d\n", pgc.i_prg_nb, pgc.i_cell_nb );
GETL( &pgc.i_play_time );
GETL( &pgc.i_prohibited_user_op );
for( i=0 ; i<8 ; i++ )
......@@ -233,6 +243,7 @@ static pgc_t ReadPGC( ifo_t* p_ifo )
GETS( &pgc.i_next_pgc_nb );
GETS( &pgc.i_prev_pgc_nb );
GETS( &pgc.i_goup_pgc_nb );
fprintf( stderr, "PGC: Prev: %d Next: %d Up: %d\n",pgc.i_prev_pgc_nb ,pgc.i_next_pgc_nb, pgc.i_goup_pgc_nb );
GETC( &pgc.i_still_time );
GETC( &pgc.i_play_mode );
for( i=0 ; i<16 ; i++ )
......@@ -371,7 +382,7 @@ static pgci_inf_t ReadUnit( ifo_t* p_ifo )
int i;
off_t i_start = p_ifo->i_pos;
//fprintf( stderr, "Unit\n" );
fprintf( stderr, "Unit\n" );
GETS( &inf.i_srp_nb );
FLUSH( 2 );
......@@ -395,6 +406,7 @@ static pgci_inf_t ReadUnit( ifo_t* p_ifo )
p_ifo->i_pos = lseek( p_ifo->i_fd,
i_start + inf.p_srp[i].i_pgci_sbyte,
SEEK_SET );
fprintf( stderr, "Unit: PGC %d\n", i );
inf.p_srp[i].pgc = ReadPGC( p_ifo );
}
......@@ -410,7 +422,7 @@ static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
int i;
off_t i_start = p_ifo->i_pos;
//fprintf( stderr, "Unit Table\n" );
fprintf( stderr, "Unit Table\n" );
GETS( &pgci.i_lu_nb );
FLUSH( 2 );
......@@ -577,9 +589,10 @@ static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
int i;
// off_t i_start = p_ifo->i_pos;
//fprintf( stderr, "PTR\n" );
fprintf( stderr, "PTR\n" );
GETS( &ptr.i_ttu_nb );
fprintf( stderr, "PTR: TTU nb %d\n", ptr.i_ttu_nb );
FLUSH( 2 );
GETL( &ptr.i_ebyte );
/* Parsing of tts */
......@@ -599,7 +612,7 @@ static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
GETC( &ptr.p_tts[i].i_tts_nb );
GETC( &ptr.p_tts[i].i_vts_ttn );
GETL( &ptr.p_tts[i].i_ssector );
//fprintf( stderr, "PTR: %d %d %d\n",ptr.p_tts[i].i_tts_nb,ptr.p_tts[i].i_vts_ttn, ptr.p_tts[i].i_ssector );
fprintf( stderr, "PTR: %d %d %d\n", ptr.p_tts[i].i_ptt_nb, ptr.p_tts[i].i_tts_nb,ptr.p_tts[i].i_vts_ttn );
}
return ptr;
......@@ -673,9 +686,10 @@ static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
int i, j;
off_t i_start = p_ifo->i_pos;
//fprintf( stderr, "VTS ATTR\n" );
fprintf( stderr, "VTS ATTR\n" );
GETS( &atrt.i_vts_nb );
fprintf( stderr, "VTS ATTR Nb: %d\n", atrt.i_vts_nb );
FLUSH( 2 );