Commit 8e3c802c authored by Stéphane Borel's avatar Stéphane Borel

-UDF filesystem support so that we know the location of the first video

related file with 100% reliability (great change that should make DVDs
with binaries and extra stuff work with vlc).

-Correction of a bug in ifo reading that falsified the adress of
video titles.

-Changed the method for selecting title at start. It is _not_ reliable
though, but it is better than the preceding one.
parent f1175e71
...@@ -294,6 +294,7 @@ PLUGIN_DUMMY = plugins/dummy/dummy.o \ ...@@ -294,6 +294,7 @@ PLUGIN_DUMMY = plugins/dummy/dummy.o \
PLUGIN_DVD = plugins/dvd/dvd.o \ PLUGIN_DVD = plugins/dvd/dvd.o \
plugins/dvd/input_dvd.o \ plugins/dvd/input_dvd.o \
plugins/dvd/dvd_ifo.o \ plugins/dvd/dvd_ifo.o \
plugins/dvd/dvd_udf.o \
plugins/dvd/dvd_css.o plugins/dvd/dvd_css.o
PLUGIN_ESD = plugins/esd/esd.o \ PLUGIN_ESD = plugins/esd/esd.o \
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* dvd_css.c: Functions for DVD authentification and unscrambling * dvd_css.c: Functions for DVD authentification and unscrambling
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_css.c,v 1.9 2001/02/15 21:03:27 stef Exp $ * $Id: dvd_css.c,v 1.10 2001/02/18 01:42:04 stef Exp $
* *
* Author: Stphane Borel <stef@via.ecp.fr> * Author: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -1052,7 +1052,7 @@ int CSSGetKeys( css_t * p_css ) ...@@ -1052,7 +1052,7 @@ int CSSGetKeys( css_t * p_css )
int i_highest; int i_highest;
int i,j,k; int i,j,k;
for( i_title = 0 ; i_title < 1/*p_css->i_title_nb*/ ; i_title++ ) for( i_title = 0 ; i_title < p_css->i_title_nb ; i_title++ )
{ {
/* Initialization for each title */ /* Initialization for each title */
memset( p_title_key, 0, 10 ); memset( p_title_key, 0, 10 );
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* dvd_ifo.c: Functions for ifo parsing * dvd_ifo.c: Functions for ifo parsing
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_ifo.c,v 1.8 2001/02/15 21:03:27 stef Exp $ * $Id: dvd_ifo.c,v 1.9 2001/02/18 01:42:05 stef Exp $
* *
* Author: Stphane Borel <stef@via.ecp.fr> * Author: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "intf_msg.h" #include "intf_msg.h"
#include "dvd_ifo.h" #include "dvd_ifo.h"
#include "dvd_udf.h"
#include "input_dvd.h" #include "input_dvd.h"
void CommandRead( ifo_command_t ); void CommandRead( ifo_command_t );
...@@ -46,57 +47,6 @@ void CommandRead( ifo_command_t ); ...@@ -46,57 +47,6 @@ void CommandRead( ifo_command_t );
* IFO Management. * IFO Management.
*/ */
/*****************************************************************************
* IfoFindVMG : When reading directly on a device, finds the offset to the
* beginning of video_ts.ifo.
*****************************************************************************/
static int IfoFindVMG( ifo_t* p_ifo )
{
char psz_ifo_start[12] = "DVDVIDEO-VMG";
char psz_test[12];
read( p_ifo->i_fd, psz_test, 12 );
while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
{
/* The start of ifo file is on a sector boundary */
p_ifo->i_pos = lseek( p_ifo->i_fd,
p_ifo->i_pos + DVD_LB_SIZE,
SEEK_SET );
read( p_ifo->i_fd, psz_test, 12 );
}
p_ifo->i_off = p_ifo->i_pos;
fprintf( stderr, "VMG Off : %lld\n", (long long)(p_ifo->i_off) );
return 0;
}
/*****************************************************************************
* IfoFindVTS : beginning of vts_*.ifo.
*****************************************************************************/
static int IfoFindVTS( ifo_t* p_ifo )
{
char psz_ifo_start[12] = "DVDVIDEO-VTS";
char psz_test[12];
read( p_ifo->i_fd, psz_test, 12 );
while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
{
/* The start of ifo file is on a sector boundary */
p_ifo->i_pos = lseek( p_ifo->i_fd,
p_ifo->i_pos + DVD_LB_SIZE,
SEEK_SET );
read( p_ifo->i_fd, psz_test, 12 );
}
p_ifo->i_off = p_ifo->i_pos;
fprintf( stderr, "VTS Off : %lld\n", (long long)(p_ifo->i_off) );
return 0;
}
/***************************************************************************** /*****************************************************************************
* IfoInit : Creates an ifo structure and prepares for parsing directly * IfoInit : Creates an ifo structure and prepares for parsing directly
* on DVD device. * on DVD device.
...@@ -104,14 +54,15 @@ fprintf( stderr, "VTS Off : %lld\n", (long long)(p_ifo->i_off) ); ...@@ -104,14 +54,15 @@ fprintf( stderr, "VTS Off : %lld\n", (long long)(p_ifo->i_off) );
ifo_t IfoInit( int i_fd ) ifo_t IfoInit( int i_fd )
{ {
ifo_t ifo; ifo_t ifo;
u32 i_lba;
/* If we are here the dvd device has already been opened */ /* If we are here the dvd device has already been opened */
ifo.i_fd = i_fd; ifo.i_fd = i_fd;
/* No data at the beginning of the disk
* 512000 bytes is just another value :) */ i_lba = UDFFindFile( i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
ifo.i_pos = lseek( ifo.i_fd, 250 *DVD_LB_SIZE, SEEK_SET );
/* FIXME : use udf filesystem to find the beginning of the file */ ifo.i_off = (off_t)(i_lba) * DVD_LB_SIZE;
IfoFindVMG( &ifo ); ifo.i_pos = lseek( ifo.i_fd, ifo.i_off, SEEK_SET );
return ifo; return ifo;
} }
...@@ -648,6 +599,7 @@ static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo ) ...@@ -648,6 +599,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_tts_nb );
GETC( &ptr.p_tts[i].i_vts_ttn ); GETC( &ptr.p_tts[i].i_vts_ttn );
GETL( &ptr.p_tts[i].i_ssector ); 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 );
} }
return ptr; return ptr;
...@@ -1030,56 +982,56 @@ static vts_t ReadVTS( ifo_t* p_ifo ) ...@@ -1030,56 +982,56 @@ static vts_t ReadVTS( ifo_t* p_ifo )
vts.mat = ReadVTSInfMat( p_ifo ); vts.mat = ReadVTSInfMat( p_ifo );
if( vts.mat.i_ptt_srpt_ssector ) if( vts.mat.i_ptt_srpt_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE, vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.ptt_srpt = ReadVTSTitlePointer( p_ifo ); vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
} }
if( vts.mat.i_m_pgci_ut_ssector ) if( vts.mat.i_m_pgci_ut_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE, vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.pgci_ut = ReadUnitTable( p_ifo ); vts.pgci_ut = ReadUnitTable( p_ifo );
} }
if( vts.mat.i_pgcit_ssector ) if( vts.mat.i_pgcit_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_pgcit_ssector *DVD_LB_SIZE, vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.pgci_ti = ReadUnit( p_ifo ); vts.pgci_ti = ReadUnit( p_ifo );
} }
if( vts.mat.i_tmap_ti_ssector ) if( vts.mat.i_tmap_ti_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE, vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.tmap_ti = ReadVTSTimeMap( p_ifo ); vts.tmap_ti = ReadVTSTimeMap( p_ifo );
} }
if( vts.mat.i_m_c_adt_ssector ) if( vts.mat.i_m_c_adt_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE, vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.m_c_adt = ReadCellInf( p_ifo ); vts.m_c_adt = ReadCellInf( p_ifo );
} }
if( vts.mat.i_m_vobu_admap_ssector ) if( vts.mat.i_m_vobu_admap_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE, vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.m_vobu_admap = ReadMap( p_ifo ); vts.m_vobu_admap = ReadMap( p_ifo );
} }
if( vts.mat.i_c_adt_ssector ) if( vts.mat.i_c_adt_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_c_adt_ssector *DVD_LB_SIZE, vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.c_adt = ReadCellInf( p_ifo ); vts.c_adt = ReadCellInf( p_ifo );
} }
if( vts.mat.i_vobu_admap_ssector ) if( vts.mat.i_vobu_admap_ssector )
{ {
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE, vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
SEEK_SET ); SEEK_SET );
vts.vobu_admap = ReadMap( p_ifo ); vts.vobu_admap = ReadMap( p_ifo );
...@@ -1113,19 +1065,24 @@ void IfoRead( ifo_t* p_ifo ) ...@@ -1113,19 +1065,24 @@ void IfoRead( ifo_t* p_ifo )
p_ifo->b_error = 1; p_ifo->b_error = 1;
return; return;
} }
for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ ) for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ )
{ {
intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 ); intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 );
i_off = (off_t)(p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector) *DVD_LB_SIZE; i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector ) *DVD_LB_SIZE
+ p_ifo->i_off;
p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET ); p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
fprintf( stderr, "%lld\n" , p_ifo->i_pos );
/* FIXME : use udf filesystem to avoid this */ /* FIXME : I really don't know why udf find file
IfoFindVTS( p_ifo ); * does not give the exact beginning of file */
p_ifo->p_vts[i] = ReadVTS( p_ifo ); p_ifo->p_vts[i] = ReadVTS( p_ifo );
} }
return; return;
} }
......
/***************************************************************************** /*****************************************************************************
* dvd_udf.c: udf filesystem tools. * dvd_udf.c: udf filesystem tools.
* --- * ---
* Mainly used to find asolute logical block adress of *.ifo files * Mainly used to find asolute logical block adress of *.ifo files. It only
* contains the basic udf handling functions
***************************************************************************** *****************************************************************************
* Copyright (C) 1998-2001 VideoLAN * Copyright (C) 1998-2001 VideoLAN
* $Id: dvd_udf.c,v 1.1 2001/02/15 21:03:27 stef Exp $ * $Id: dvd_udf.c,v 1.2 2001/02/18 01:42:05 stef Exp $
* *
* Author: Stphane Borel <stef@via.ecp.fr> * Author: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -34,25 +35,28 @@ ...@@ -34,25 +35,28 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <netinet/in.h>
#include "common.h" #include "common.h"
#include "intf_msg.h" #include "intf_msg.h"
#include "dvd_css.h"
#include "dvd_ifo.h"
#include "input_dvd.h" #include "input_dvd.h"
/* #define UDFADshort 1
* Local structures #define UDFADlong 2
*/ #define UDFADext 4
typedef struct partition_s typedef struct partition_s
{ {
int i_valid; boolean_t b_valid;
u8 pi_volume_desc[128]; u8 pi_volume_desc[128];
u16 i_flags; u16 i_flags;
u16 i_number; u16 i_number;
u8 pi_contents[32]; u8 pi_contents[32];
u32 i_accessType; u32 i_access_type;
u32 i_start; u32 i_start;
u32 i_length; u32 i_length;
int i_fd;
} partition_t; } partition_t;
typedef struct ad_s typedef struct ad_s
...@@ -63,12 +67,37 @@ typedef struct ad_s ...@@ -63,12 +67,37 @@ typedef struct ad_s
u16 i_partition; u16 i_partition;
} ad_t; } ad_t;
/* /* for direct data access, LSB first */
* Local functions #define GETN1(p) ((u8)pi_data[p])
*/ #define GETN2(p) ((u16)pi_data[p]|((u16)pi_data[(p)+1]<<8))
#define GETN4(p) ((u32)pi_data[p]|((u32)pi_data[(p)+1]<<8)|((u32)pi_data[(p)+2]<<16)|((u32)pi_data[(p)+3]<<24))
#define GETN(p,n,target) memcpy(target,&pi_data[p],n)
/*****************************************************************************
* UDFReadLB: reads absolute Logical Block of the disc
* ---
* returns number of read bytes on success, 0 on error
*****************************************************************************/
static int UDFReadLB( int i_fd, off_t i_lba, size_t i_block_count, u8 *pi_data )
{
if( i_fd < 0 )
{
return 0;
}
if( lseek( i_fd, i_lba * (off_t) DVD_LB_SIZE, SEEK_SET ) < 0 )
{
intf_ErrMsg( "UDF: Postion not found" );
return 0;
}
return read( i_fd, pi_data, i_block_count *DVD_LB_SIZE);
}
/***************************************************************************** /*****************************************************************************
* UDFDecode: decode udf data that is unicode encoded * UDFDecode: decode unicode encoded udf data
*****************************************************************************/ *****************************************************************************/
static int UDFDecode( u8 * pi_data, int i_len, char * psz_target ) static int UDFDecode( u8 * pi_data, int i_len, char * psz_target )
{ {
...@@ -77,11 +106,11 @@ static int UDFDecode( u8 * pi_data, int i_len, char * psz_target ) ...@@ -77,11 +106,11 @@ static int UDFDecode( u8 * pi_data, int i_len, char * psz_target )
if( !( pi_data[0] & 0x18 ) ) if( !( pi_data[0] & 0x18 ) )
{ {
psz_target[0] ='\0'; psz_target[0] = '\0';
return 0; return 0;
} }
if( data[0] & 0x10 ) if( pi_data[0] & 0x10 )
{ {
/* ignore MSB of unicode16 */ /* ignore MSB of unicode16 */
p++; p++;
...@@ -104,69 +133,183 @@ static int UDFDecode( u8 * pi_data, int i_len, char * psz_target ) ...@@ -104,69 +133,183 @@ static int UDFDecode( u8 * pi_data, int i_len, char * psz_target )
return 0; return 0;
} }
#if 0
/**
*
**/
int UDFEntity (u8 *data, u8 *Flags, char *Identifier)
{
Flags[0] = data[0];
strncpy (Identifier, &data[1], 5);
return 0;
}
#endif
/*****************************************************************************
* UDFDescriptor: gives a tag ID from your data to find out what it refers to
*****************************************************************************/
static int UDFDescriptor( u8 * pi_data, u16 * pi_tag_id )
{
pi_tag_id[0] = GETN2( 0 );
/* TODO: check CRC 'n stuff */
return 0;
}
/***************************************************************************** /*****************************************************************************
* UDFInit: some check and initialization in udf filesystem * UDFExtendAD: main volume information
*****************************************************************************/ *****************************************************************************/
int UDFInit( u8 * pi_data, udf_t * p_udf ) static int UDFExtentAD (u8 * pi_data, u32 * pi_length, u32 * pi_location)
{ {
u32i lbsize,MT_L,N_PM; pi_length[0] = GETN4( 0 );
pi_location[0] = GETN4( 4 );
return 0;
}
UDFDecode( &pi_data[84], 128, p_udf->psz_volume_desc );
lbsize = GETN4(212); // should be 2048
MT_L = GETN4(264); // should be 6
N_PM = GETN4(268); // should be 1
if( lbsize != DVD_LB_SIZE ) /*****************************************************************************
* UDFAD: file set information
*****************************************************************************/
static int UDFAD( u8 * pi_data, struct ad_s * p_ad, u8 i_type,
struct partition_s partition )
{
p_ad->i_length = GETN4( 0 );
p_ad->i_flags = p_ad->i_length >> 30;
p_ad->i_length &= 0x3FFFFFFF;
switch( i_type )
{ {
case UDFADshort:
p_ad->i_location = GETN4( 4 );
/* use number of current partition */
p_ad->i_partition = partition.i_number;
break;
case UDFADlong:
p_ad->i_location = GETN4( 4 );
p_ad->i_partition = GETN2( 8 );
break;
case UDFADext:
p_ad->i_location = GETN4( 12 );
p_ad->i_partition = GETN2( 16 );
break;
}
return 0;
}
/*****************************************************************************
* UDFICB: takes Information Control Block from pi_data
*****************************************************************************/
static int UDFICB( u8 * pi_data, u8 * pi_file_type, u16 * pi_flags)
{
pi_file_type[0] = GETN1( 11 );
pi_flags[0] = GETN2( 18 );
return 0;
}
/*****************************************************************************
* UDFPartition: gets partition descriptor
*****************************************************************************/
static int UDFPartition( u8 * pi_data, u16 * pi_flags, u16 * pi_nb,
char * ps_contents, u32 * pi_start, u32 * pi_length )
{
pi_flags[0] = GETN2( 20 );
pi_nb[0] = GETN2( 22 );
GETN( 24, 32, ps_contents );
pi_start[0] = GETN4( 188 );
pi_length[0] = GETN4( 192 );
return 0;
}
/*****************************************************************************
* UDFLogVolume: reads the volume descriptor and checks the parameters
* ---
* returns 0 on OK, 1 on error
*****************************************************************************/
static int UDFLogVolume(u8 * pi_data, char * p_volume_descriptor )
{
u32 i_lb_size;
u32 i_MT_L;
u32 i_N_PM;
UDFDecode( &pi_data[84], 128, p_volume_descriptor );
i_lb_size = GETN4( 212 ); // should be 2048
i_MT_L = GETN4( 264 ); // should be 6
i_N_PM = GETN4( 268 ); // should be 1
if( i_lb_size != DVD_LB_SIZE )
{
intf_ErrMsg( "UDF: Non valid sector size (%d)", i_lb_size );
return 1; return 1;
} }
return 0; return 0;
} }
/***************************************************************************** /*****************************************************************************
* UDFFileEntry: * UDFFileEntry: fills a ad_t struct with information at pi_data
*****************************************************************************/ *****************************************************************************/
int UDFFileEntry (uint8_t *data, uint8_t *FileType, struct AD *ad) static int UDFFileEntry( u8 * pi_data, u8 * pi_file_type, struct ad_s * p_ad,
struct partition_s partition )
{ {
uint8_t filetype; u8 i_file_type;
uint16_t flags; u16 i_flags;
uint32_t L_EA,L_AD; u32 i_L_EA;
u32 i_L_AD;
int p; int p;
UDFICB(&data[16],&filetype,&flags); UDFICB( &pi_data[16], &i_file_type, &i_flags );
FileType[0]=filetype;
L_EA=GETN4(168); pi_file_type[0] = i_file_type;
L_AD=GETN4(172); i_L_EA = GETN4( 168 );
p=176+L_EA; i_L_AD = GETN4( 172 );
p = 176 + i_L_EA;
while (p<176+L_EA+L_AD) { while( p < 176 + i_L_EA + i_L_AD )
switch (flags&0x07) { {
switch( i_flags & 0x07 )
{
case 0: case 0:
UDFAD (&data[p], ad, UDFADshort); UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
p += 0x08; p += 0x08;
break; break;
case 1: case 1:
UDFAD (&data[p], ad, UDFADlong); UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
p += 0x10; p += 0x10;
break; break;
case 2: UDFAD (&data[p], ad, UDFADext); case 2:
UDFAD( &pi_data[p], p_ad, UDFADext, partition );
p += 0x14; p += 0x14;
break; break;
case 3: case 3:
switch (L_AD) { switch( i_L_AD )
{
case 0x08: case 0x08:
UDFAD (&data[p], ad, UDFADshort); UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
break; break;
case 0x10: case 0x10:
UDFAD (&data[p], ad, UDFADlong); UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
break; break;
case 0x14: case 0x14:
UDFAD (&data[p], ad, UDFADext); UDFAD( &pi_data[p], p_ad, UDFADext, partition );
break; break;
} }
default: default:
p += L_AD; p += i_L_AD;
break; break;
} }
} }
...@@ -174,25 +317,376 @@ int UDFFileEntry (uint8_t *data, uint8_t *FileType, struct AD *ad) ...@@ -174,25 +317,376 @@ int UDFFileEntry (uint8_t *data, uint8_t *FileType, struct AD *ad)
return 0; return 0;
} }
/***************************************************************************** /*****************************************************************************
* UDFFileIdentifier: * UDFFileIdentifier: gives filename and characteristics of pi_data
*****************************************************************************/ *****************************************************************************/
int UDFFileIdentifier (uint8_t *data, uint8_t *FileCharacteristics, char *FileName, struct AD *FileICB) static int UDFFileIdentifier( u8 * pi_data, u8 * pi_file_characteristics,
char * psz_filename, struct ad_s * p_file_icb,
struct partition_s partition )
{ {
uint8_t L_FI; u8 i_L_FI;
uint16_t L_IU; u16 i_L_IU;
FileCharacteristics[0]=GETN1(18); pi_file_characteristics[0] = GETN1( 18 );
L_FI=GETN1(19); i_L_FI = GETN1( 19 );
UDFAD(&data[20],FileICB,UDFADlong); UDFAD( &pi_data[20], p_file_icb, UDFADlong, partition );
L_IU=GETN2(36); i_L_IU = GETN2( 36 );
if (L_FI) if( i_L_FI )
_Unicodedecode (&data[38+L_IU],L_FI,FileName); {
UDFDecode( &pi_data[38+i_L_IU], i_L_FI, psz_filename );
}
else else
FileName[0]='\0'; {
psz_filename[0]='\0';
}
return 4*((38+L_FI+L_IU+3)/4); return 4 * ( ( 38 + i_L_FI + i_L_IU + 3 ) / 4 );
} }
/*****************************************************************************
* UDFMapICB: Maps ICB to FileAD
* ---
* ICB: Location of ICB of directory to scan
* FileType: Type of the file
* File: Location of file the ICB is pointing to
* return 1 on success, 0 on error;
*****************************************************************************/
static int UDFMapICB( struct ad_s icb, u8 * pi_file_type, struct ad_s * p_file,
struct partition_s partition )
{
u8 pi_lb[DVD_LB_SIZE];
u32 i_lba;
u16 i_tag_id;
i_lba = partition.i_start + icb.i_location;
do
{
if( !UDFReadLB( partition.i_fd, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb , &i_tag_id );
}
if( i_tag_id == 261 )
{
UDFFileEntry( pi_lb, pi_file_type, p_file, partition );
return 1;
}
} while( ( i_lba <= partition.i_start + icb.i_location +
( icb.i_length - 1 ) / DVD_LB_SIZE ) && ( i_tag_id != 261 ) );
return 0;
}
/*****************************************************************************
* UDFScanDir: serach filename in dir
* ---
* Dir: Location of directory to scan
* FileName: Name of file to look for
* FileICB: Location of ICB of the found file
* return 1 on success, 0 on error;
*****************************************************************************/
static int UDFScanDir( struct ad_s dir, char * psz_filename,
struct ad_s * p_file_icb, struct partition_s partition )
{
u8 pi_lb[DVD_LB_SIZE];
u32 i_lba;
u16 i_tag_id;
u8 i_file_char;
char psz_temp[DVD_LB_SIZE];
int p;
/* Scan dir for ICB of file */
i_lba = partition.i_start + dir.i_location;
do
{
if( !UDFReadLB( partition.i_fd, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
p=0;
while( p < DVD_LB_SIZE )
{
UDFDescriptor( &pi_lb[p], &i_tag_id );
if( i_tag_id == 257 )
{
p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
psz_temp, p_file_icb, partition );
if( !strcasecmp( psz_filename, psz_temp ) )
{
return 1;
}
}
else
{
p = DVD_LB_SIZE;
}
}
}
} while( i_lba <=
partition.i_start + dir.i_location + ( dir.i_length - 1 ) / DVD_LB_SIZE );
return 0;
}
/******************************************************************************
* UDFFindPartition: looks for a partition on the disc
* ---
* partnum: number of the partition, starting at 0
* part: structure to fill with the partition information
* return 1 if partition found, 0 on error;
******************************************************************************/
static int UDFFindPartition( int i_part_nb, struct partition_s *p_partition )
{
u8 pi_lb[DVD_LB_SIZE];
u8 pi_anchor[DVD_LB_SIZE];
u16 i_tag_id;
u32 i_lba;
u32 i_MVDS_location;
u32 i_MVDS_length;
u32 i_last_sector;
boolean_t b_term;
boolean_t b_vol_valid;
int i;
/* Find Anchor */
i_last_sector = 0;
/* try #1, prime anchor */
i_lba = 256;
b_term = 0;
/* Search anchor loop */
while( 1 )
{
if( UDFReadLB( p_partition->i_fd, i_lba, 1, pi_anchor ) )
{
UDFDescriptor( pi_anchor, &i_tag_id );
}
else
{
i_tag_id = 0;
}
if( i_tag_id != 2 )
{
/* not an anchor? */
if( b_term )
{
/* final try failed */
return 0;
}
if( i_last_sector )
{
/* we already found the last sector
* try #3, alternative backup anchor */
i_lba = i_last_sector;
/* but that's just about enough, then! */
b_term = 1;
}
else
{
/* TODO: find last sector of the disc (this is optional) */
if( i_last_sector )
{
/* try #2, backup anchor */
i_lba = i_last_sector - 256;
}
else
{
/* unable to find last sector */
return 0;
}
}
}
else
{
/* it is an anchor! continue... */
break;
}
}
/* main volume descriptor */
UDFExtentAD( &pi_anchor[16], &i_MVDS_length, &i_MVDS_location );
p_partition->b_valid = 0;
b_vol_valid = 0;
p_partition->pi_volume_desc[0] = '\0';
i = 1;
/* Find Volume Descriptor */
do
{
i_lba = i_MVDS_location;
do
{
if( !UDFReadLB( p_partition->i_fd, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb, &i_tag_id );
}
if( ( i_tag_id == 5 ) && ( !p_partition->b_valid ) )
{
/* Partition Descriptor */
UDFPartition( pi_lb,
&p_partition->i_flags,
&p_partition->i_number,
p_partition->pi_contents,
&p_partition->i_start,
&p_partition->i_length );
p_partition->b_valid = ( i_part_nb == p_partition->i_number );
}
else if( ( i_tag_id == 6 ) && ( !b_vol_valid) )
{
/* Logical Volume Descriptor */
if( UDFLogVolume( pi_lb , p_partition->pi_volume_desc ) )
{
/* TODO: sector size wrong! */
}
else
{
b_vol_valid = 1;
}
}
} while( ( i_lba <= i_MVDS_location +
( i_MVDS_length - 1 ) / DVD_LB_SIZE )
&& ( i_tag_id != 8 )
&& ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
if( ( !p_partition->b_valid ) || ( !b_vol_valid ) )
{
/* backup volume descriptor */
UDFExtentAD( &pi_anchor[24], &i_MVDS_length, &i_MVDS_location );
}
} while( i-- && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
/* we only care for the partition, not the volume */
return( p_partition->b_valid);
}
/******************************************************************************
* UDFFindFile: looks for a file on the UDF disc/imagefile
* ---
* Path has to be the absolute pathname on the UDF filesystem,
* starting with '/'.
* returns absolute LB number, or 0 on error
******************************************************************************/
u32 UDFFindFile( int i_fd, char * psz_path )
{
struct partition_s partition;
struct ad_s root_icb;
struct ad_s file;
struct ad_s icb;
u32 i_lba;
u16 i_tag_id;
u8 pi_lb[DVD_LB_SIZE];
u8 i_file_type;
char psz_tokenline[DVD_LB_SIZE] = "";
char * psz_token;
int i_partition;
strcat( psz_tokenline, psz_path );
/* Init file descriptor of UDF filesystem (== DVD) */
partition.i_fd = i_fd;
/* Find partition 0, standard partition for DVD-Video */
i_partition = 0;
if( !UDFFindPartition( i_partition, &partition ) )
{
intf_ErrMsg( "UDF: Partition 0 not found" );
return 0;
}
/* Find root dir ICB */
i_lba = partition.i_start;
do
{
if( !UDFReadLB( i_fd, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb, &i_tag_id );
}
if( i_tag_id == 256 )
{
/* File Set Descriptor */
UDFAD( &pi_lb[400], &root_icb, UDFADlong, partition );
}
} while( ( i_lba < partition.i_start + partition.i_length )
&& ( i_tag_id != 8) && ( i_tag_id != 256 ) );
if( i_tag_id != 256 )
{
intf_ErrMsg( "UDF: Bad descriptor" );
return 0;
}
if( root_icb.i_partition != i_partition )
{
intf_ErrMsg( "UDF: Bad partition" );
return 0;
}
/* Find root dir */
if( !UDFMapICB( root_icb, &i_file_type, &file, partition ) )
{
intf_ErrMsg( "UDF: Can't find root dir" );
return 0;
}
/* root dir should be dir */
if( i_file_type != 4 )
{
intf_ErrMsg( "UDF: Root dir error" );
return 0;
}
/* Tokenize filepath */
psz_token = strtok( psz_tokenline, "/" );
while( psz_token )
{
if( !UDFScanDir( file, psz_token, &icb, partition ) )
{
intf_ErrMsg( "UDF: Scan dir error" );
return 0;
}
if( !UDFMapICB ( icb, &i_file_type, &file, partition ) )
{
intf_ErrMsg( "UDF: ICB error" );
return 0;
}
psz_token = strtok( NULL, "/" );
}
return partition.i_start + file.i_location;
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* dvd_udf.h: structures for udf filesystem tools. * dvd_udf.h: structures for udf filesystem tools.
***************************************************************************** *****************************************************************************
* Copyright (C) 1998-2001 VideoLAN * Copyright (C) 1998-2001 VideoLAN
* $Id: dvd_udf.h,v 1.1 2001/02/15 21:03:27 stef Exp $ * $Id: dvd_udf.h,v 1.2 2001/02/18 01:42:05 stef Exp $
* *
* Author: Stéphane Borel <stef@via.ecp.fr> * Author: Stéphane Borel <stef@via.ecp.fr>
* *
...@@ -23,3 +23,8 @@ ...@@ -23,3 +23,8 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/ *****************************************************************************/
/*
* Fonctions in dvd_udf.c
*/
u32 UDFFindFile( int, char * );
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* -dvd_udf to find files * -dvd_udf to find files
***************************************************************************** *****************************************************************************
* Copyright (C) 1998-2001 VideoLAN * Copyright (C) 1998-2001 VideoLAN
* $Id: input_dvd.c,v 1.12 2001/02/16 09:25:03 sam Exp $ * $Id: input_dvd.c,v 1.13 2001/02/18 01:42:05 stef Exp $
* *
* Author: Stphane Borel <stef@via.ecp.fr> * Author: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -159,6 +159,16 @@ static int DVDCheckCSS( input_thread_t * p_input ) ...@@ -159,6 +159,16 @@ static int DVDCheckCSS( input_thread_t * p_input )
#endif #endif
} }
/*****************************************************************************
* DVDSetRegion: initialize input data for title x, chapter y. It should
* be called for each user navigation request.
*****************************************************************************/
static int DVDSetRegion( int i_title, int i_chapter )
{
return 0;
}
/***************************************************************************** /*****************************************************************************
* DVDInit: initializes DVD structures * DVDInit: initializes DVD structures
*****************************************************************************/ *****************************************************************************/
...@@ -182,7 +192,6 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -182,7 +192,6 @@ static void DVDInit( input_thread_t * p_input )
p_method->i_fd = p_input->i_handle; p_method->i_fd = p_input->i_handle;
/* FIXME: read several packets once */ /* FIXME: read several packets once */
p_method->i_read_once = 1; p_method->i_read_once = 1;
p_method->i_title = 0;
p_method->b_encrypted = DVDCheckCSS( p_input ); p_method->b_encrypted = DVDCheckCSS( p_input );
lseek( p_input->i_handle, 0, SEEK_SET ); lseek( p_input->i_handle, 0, SEEK_SET );
...@@ -194,6 +203,9 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -194,6 +203,9 @@ static void DVDInit( input_thread_t * p_input )
/* Ifo initialisation */ /* Ifo initialisation */
p_method->ifo = IfoInit( p_input->i_handle ); p_method->ifo = IfoInit( p_input->i_handle );
/* FIXME: kludge */
p_method->i_title = p_method->ifo.vmg.ptt_srpt.p_tts[0].i_tts_nb;
/* CSS initialisation */ /* CSS initialisation */
if( p_method->b_encrypted ) if( p_method->b_encrypted )
{ {
...@@ -217,7 +229,7 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -217,7 +229,7 @@ static void DVDInit( input_thread_t * p_input )
IfoRead( &(p_method->ifo) ); IfoRead( &(p_method->ifo) );
intf_WarnMsg( 3, "Ifo: Initialized" ); intf_WarnMsg( 3, "Ifo: Initialized" );
/* CSS title keys */ /* CSS title keys decryption */
if( p_method->b_encrypted ) if( p_method->b_encrypted )
{ {
...@@ -260,8 +272,8 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -260,8 +272,8 @@ static void DVDInit( input_thread_t * p_input )
i_end_cell = 0; i_end_cell = 0;
/* Loop on the number of vobs */ /* Loop on the number of vobs */
while( p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_cell].i_vob_id <= while( p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_cell].i_vob_id <=
p_method->ifo.p_vts[0].c_adt.i_vob_nb ) p_method->ifo.p_vts[p_method->i_title].c_adt.i_vob_nb )
{ {
i_cell_1 = i_cell; i_cell_1 = i_cell;
...@@ -269,17 +281,17 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -269,17 +281,17 @@ static void DVDInit( input_thread_t * p_input )
do do
{ {
i_cell++; i_cell++;
if( i_cell >= p_method->ifo.p_vts[0].c_adt.i_cell_nb ) if( i_cell >= p_method->ifo.p_vts[p_method->i_title].c_adt.i_cell_nb )
{ {
break; break;
} }
} }
while( p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_cell-1].i_cell_id < while( p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_cell-1].i_cell_id <
p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_cell].i_cell_id ); p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_cell].i_cell_id );
if( p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_cell-1].i_cell_id > if( p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_cell-1].i_cell_id >
p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_end_cell].i_cell_id ) p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_end_cell].i_cell_id )
{ {
i_start_cell = i_cell_1; i_start_cell = i_cell_1;
i_end_cell = i_cell - 1; i_end_cell = i_cell - 1;
...@@ -288,7 +300,7 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -288,7 +300,7 @@ static void DVDInit( input_thread_t * p_input )
/* The preceding does not work with all DVD, so we give the /* The preceding does not work with all DVD, so we give the
* last cell of the title as end */ * last cell of the title as end */
i_end_cell = p_method->ifo.p_vts[0].c_adt.i_cell_nb - 1; i_end_cell = p_method->ifo.p_vts[p_method->i_title].c_adt.i_cell_nb - 1;
intf_WarnMsg( 2, "DVD: Start cell: %d End Cell: %d", intf_WarnMsg( 2, "DVD: Start cell: %d End Cell: %d",
i_start_cell, i_end_cell ); i_start_cell, i_end_cell );
...@@ -297,17 +309,17 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -297,17 +309,17 @@ static void DVDInit( input_thread_t * p_input )
p_method->i_end_cell = i_end_cell; p_method->i_end_cell = i_end_cell;
/* start is : beginning of vts + offset to vobs + offset to vob x */ /* start is : beginning of vts + offset to vobs + offset to vob x */
i_start = p_method->ifo.p_vts[0].i_pos + DVD_LB_SIZE * i_start = p_method->ifo.p_vts[p_method->i_title].i_pos + DVD_LB_SIZE *
( p_method->ifo.p_vts[0].mat.i_tt_vobs_ssector + ( p_method->ifo.p_vts[p_method->i_title].mat.i_tt_vobs_ssector +
p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_start_cell].i_ssector ); p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_start_cell].i_ssector );
p_method->i_start_byte = i_start; p_method->i_start_byte = i_start;
i_start = lseek( p_input->i_handle, i_start, SEEK_SET ); i_start = lseek( p_input->i_handle, i_start, SEEK_SET );
intf_WarnMsg( 3, "DVD: VOBstart at: %lld", i_start ); intf_WarnMsg( 3, "DVD: VOBstart at: %lld", i_start );
i_size = (off_t) i_size = (off_t)
( p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_end_cell].i_esector - ( p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_end_cell].i_esector -
p_method->ifo.p_vts[0].c_adt.p_cell_inf[i_start_cell].i_ssector + 1 ) p_method->ifo.p_vts[p_method->i_title].c_adt.p_cell_inf[i_start_cell].i_ssector + 1 )
*DVD_LB_SIZE; *DVD_LB_SIZE;
intf_WarnMsg( 3, "DVD: stream size: %lld", i_size ); intf_WarnMsg( 3, "DVD: stream size: %lld", i_size );
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#define DVD_LB_SIZE 2048 #define DVD_LB_SIZE 2048
/***************************************************************************** /*****************************************************************************
* thread_dvd_data_t: extension of input_thread_t for DVD specificity * thread_dvd_data_t: extension of input_thread_t for DVD specificity.
*****************************************************************************/ *****************************************************************************/
typedef struct thread_dvd_data_s typedef struct thread_dvd_data_s
{ {
...@@ -36,7 +36,6 @@ typedef struct thread_dvd_data_s ...@@ -36,7 +36,6 @@ typedef struct thread_dvd_data_s
int i_read_once; // NB of bytes read by DVDRead int i_read_once; // NB of bytes read by DVDRead
int i_title; // Current Title int i_title; // Current Title
/* FIXME: include these in a struct */
int i_start_byte; int i_start_byte;
int i_start_cell; int i_start_cell;
int i_end_cell; int i_end_cell;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment