X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fdvd%2Fdvd_ifo.c;h=56491d8d91dbd546090a9e505207e869d9c24cf1;hb=1dea13db3581a4975cd9b4c4d2b7eb338b92465f;hp=24f8ffaf7c190a4dfab5b6de0fbc97a32b9d9f61;hpb=8e3c802c8431943acc7954b9822ff386d8c96ccf;p=vlc diff --git a/plugins/dvd/dvd_ifo.c b/plugins/dvd/dvd_ifo.c index 24f8ffaf7c..56491d8d91 100644 --- a/plugins/dvd/dvd_ifo.c +++ b/plugins/dvd/dvd_ifo.c @@ -2,9 +2,10 @@ * dvd_ifo.c: Functions for ifo parsing ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN - * $Id: dvd_ifo.c,v 1.9 2001/02/18 01:42:05 stef Exp $ + * $Id: dvd_ifo.c,v 1.39 2001/11/07 03:37:27 stef Exp $ * - * Author: Stéphane Borel + * Authors: Stéphane Borel + * German Tischler * * based on: * - libifo by Thomas Mirlacher @@ -29,1068 +30,1395 @@ /***************************************************************************** * Preamble *****************************************************************************/ +#include "defs.h" +#include "config.h" + #include -#include +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#endif + #include #include +#ifdef GOD_DAMN_DMCA +# include "dummy_dvdcss.h" +#else +# include +#endif + +#include "config.h" #include "common.h" +#include "threads.h" +#include "mtime.h" #include "intf_msg.h" + +#include "input_dvd.h" #include "dvd_ifo.h" #include "dvd_udf.h" -#include "input_dvd.h" -void CommandRead( ifo_command_t ); +#include "modules.h" +#include "modules_export.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +void CommandRead ( command_desc_t ); +static int ReadTitle ( ifo_t * , title_t *, int, int ); +static int FreeTitle ( title_t * ); +static int ReadUnitInf ( ifo_t * , unit_inf_t *, int, int ); +static int FreeUnitInf ( unit_inf_t * ); +static int ReadTitleUnit ( ifo_t * , title_unit_t *, int ); +static int FreeTitleUnit ( title_unit_t * ); +static int ReadVobuMap ( ifo_t * , vobu_map_t *, int ); +static int FreeVobuMap ( vobu_map_t * ); +static int ReadCellInf ( ifo_t * , cell_inf_t *, int ); +static int FreeCellInf ( cell_inf_t * ); +static int FreeTitleSet ( vts_t * ); + +static u8* FillBuffer ( ifo_t *, u8 *, int ); +static u8 ReadByte ( ifo_t *, u8 *, u8 ** ); +static void ReadBytes ( ifo_t *, u8 *, u8 **, u8 *, int ); +static void DumpBytes ( ifo_t *, u8 *, u8 **, int ); +static u16 ReadWord ( ifo_t *, u8 *, u8 ** ); +static u32 ReadDouble ( ifo_t *, u8 *, u8 ** ); +static u64 ReadQuad ( ifo_t *, u8 *, u8 ** ); /* * IFO Management. */ /***************************************************************************** - * IfoInit : Creates an ifo structure and prepares for parsing directly - * on DVD device. + * IfoCreate : Creates an ifo structure and prepares for parsing directly + * on DVD device *****************************************************************************/ -ifo_t IfoInit( int i_fd ) +int IfoCreate( thread_dvd_data_t * p_dvd ) { - ifo_t ifo; - u32 i_lba; - - /* If we are here the dvd device has already been opened */ - ifo.i_fd = i_fd; - - i_lba = UDFFindFile( i_fd, "/VIDEO_TS/VIDEO_TS.IFO"); + p_dvd->p_ifo = malloc( sizeof(ifo_t) ); + if( p_dvd->p_ifo == NULL ) + { + intf_ErrMsg( "ifo error: unable to allocate memory. aborting" ); + return -1; + } - ifo.i_off = (off_t)(i_lba) * DVD_LB_SIZE; - ifo.i_pos = lseek( ifo.i_fd, ifo.i_off, SEEK_SET ); + /* if we are here the dvd device has already been opened */ + p_dvd->p_ifo->dvdhandle = p_dvd->dvdhandle; - return ifo; + return 0; } /***************************************************************************** - * IfoEnd : Frees all the memory allocated to ifo structures + * IfoInit : Reads information from the management table. *****************************************************************************/ -void IfoEnd( ifo_t* p_ifo ) +int IfoInit( ifo_t * p_ifo ) { - int i,j; + u8 p_buf[DVD_LB_SIZE]; + u8* p_tmp; + u64 i_temp; + int i, j, k; + int i_start; + + /* find the start sector of video information on the dvd */ + p_ifo->i_start = UDFFindFile( p_ifo->dvdhandle, "/VIDEO_TS/VIDEO_TS.IFO" ); + if( !p_ifo->i_start ) return -1; + + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start ); + //i_start = p_ifo->i_pos; + + /* + * read the video manager information table + */ +#define MGINF p_ifo->vmg.manager_inf + //fprintf( stderr, "VMGI\n" ); + + ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id, 12 ); + MGINF.psz_id[12] = '\0'; + MGINF.i_vmg_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 12 ); + MGINF.i_vmg_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp ); + MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_volume_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + MGINF.i_volume = ReadWord( p_ifo, p_buf, &p_tmp ); + MGINF.i_disc_side = ReadByte( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 19 ); + MGINF.i_title_set_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.ps_provider_id, 32 ); + MGINF.i_pos_code = ReadQuad( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 24 ); + MGINF.i_vmg_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_first_play_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 56 ); + MGINF.i_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_parental_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_vts_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_text_data_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 32 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vmgi audio nb : %d\n", MGINF.i_audio_nb ); + + for( i = 0 ; i < 8 ; i++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vmgi subpic nb : %d\n", MGINF.i_spu_nb ); + + for( i = 0 ; i < MGINF.i_spu_nb ; i++ ) + { + ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 ); + /* FIXME : take care of endianness */ + } - /* Free structures from video title sets */ - for( j=0 ; jvmg.mat.i_tts_nb ; j++ ) + /* + * read first play title. + */ + //fprintf(stderr,"readtitle %i\n", MGINF.i_first_play_title_start_byte & 0x7ff ); + if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_start + + OFF2LB( MGINF.i_first_play_title_start_byte ), + MGINF.i_first_play_title_start_byte & 0x7ff ) < 0 ) { - free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector ); - free( p_ifo->p_vts[j].c_adt.p_cell_inf ); - free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector ); - free( p_ifo->p_vts[j].m_c_adt.p_cell_inf ); - for( i=0 ; ip_vts[j].tmap_ti.i_nb ; i++ ) + return -1; + } + + /* + * fills the title information structure. + */ +#define TITINF p_ifo->vmg.title_inf + if( MGINF.i_title_inf_start_sector ) + { + p_tmp = FillBuffer( p_ifo, p_buf, + p_ifo->i_start + MGINF.i_title_inf_start_sector ); + //fprintf( stderr, "title inf %d\n", p_ifo->i_pos ); + + TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "title_inf: TTU nb %d\n", TITINF.i_title_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + TITINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + /* parsing of title attributes */ + TITINF.p_attr = malloc( TITINF.i_title_nb *sizeof(title_attr_t) ); + if( TITINF.p_attr == NULL ) { - free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector ); + intf_ErrMsg( "ifo error: out of memory in IfoInit" ); + return -1; } - free( p_ifo->p_vts[j].tmap_ti.pi_sbyte ); - free( p_ifo->p_vts[j].tmap_ti.p_tmap ); - free( p_ifo->p_vts[j].pgci_ti.p_srp ); - for( i=0 ; ip_vts[j].pgci_ut.i_lu_nb ; i++ ) + + for( i = 0 ; i < TITINF.i_title_nb ; i++ ) { - free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp ); + TITINF.p_attr[i].i_play_type = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_angle_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_chapter_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_parental_id = ReadWord( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_title_set_num = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_title_num = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "title_inf: %d %d %d\n", TITINF.p_attr[i].i_chapter_nb, TITINF.p_attr[i].i_title_set_num, TITINF.p_attr[i].i_title_num ); } - free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf ); - free( p_ifo->p_vts[j].pgci_ut.p_lu ); } - - free( p_ifo->p_vts ); - - /* Free structures from video manager */ - free( p_ifo->vmg.vobu_admap.pi_vobu_ssector ); - free( p_ifo->vmg.c_adt.p_cell_inf ); - for( i=0 ; ivmg.pgci_ut.i_lu_nb ; i++ ) + else { - free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp ); + TITINF.p_attr = NULL; } - free( p_ifo->vmg.pgci_ut.p_pgci_inf ); - free( p_ifo->vmg.pgci_ut.p_lu ); - for( i=1 ; i<=8 ; i++ ) +#undef TITINF + + /* + * fills the title unit structure. + */ + if( MGINF.i_title_unit_start_sector ) { - free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] ); + if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_start + + MGINF.i_title_unit_start_sector ) < 0 ) + { + return -1; + } } - free( p_ifo->vmg.ptl_mait.p_ptl_desc ); - free( p_ifo->vmg.ptl_mait.p_ptl_mask ); - free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte ); - free( p_ifo->vmg.vts_atrt.p_vts_atrt ); - free( p_ifo->vmg.pgc.p_cell_pos_inf ); - free( p_ifo->vmg.pgc.p_cell_play_inf ); - free( p_ifo->vmg.pgc.prg_map.pi_entry_cell ); - 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 ); - return; -} + /* + * fills the structure about parental information. + */ +#define PARINF p_ifo->vmg.parental_inf + if( MGINF.i_parental_inf_start_sector ) + { + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start + + MGINF.i_parental_inf_start_sector ); + i_start = p_ifo->i_pos; -/* - * Macros to process ifo files - */ - -#define GET( p_field , i_len ) \ - { \ - read( p_ifo->i_fd , (p_field) , (i_len) ); \ -/*fprintf(stderr, "Pos : %lld Val : %llx\n", \ - (long long)(p_ifo->i_pos - i_start), \ - (long long)*(p_field) ); */ \ - p_ifo->i_pos += i_len; \ - } - -#define GETC( p_field ) \ - { \ - read( p_ifo->i_fd , (p_field) , 1 ); \ -/*fprintf(stderr, "Pos : %lld Value : %d\n", \ - (long long)(p_ifo->i_pos - i_start), \ - *(p_field) );*/ \ - p_ifo->i_pos += 1; \ - } - -#define GETS( p_field ) \ - { \ - read( p_ifo->i_fd , (p_field) , 2 ); \ - *(p_field) = ntohs( *(p_field) ); \ -/*fprintf(stderr, "Pos : %lld Value : %d\n", \ - (long long)(p_ifo->i_pos - i_start), \ - *(p_field) );*/ \ - p_ifo->i_pos += 2; \ - } - -#define GETL( p_field ) \ - { \ - read( p_ifo->i_fd , (p_field) , 4 ); \ - *(p_field) = ntohl( *(p_field) ); \ -/*fprintf(stderr, "Pos : %lld Value : %d\n", \ - (long long)(p_ifo->i_pos - i_start), \ - *(p_field) );*/ \ - p_ifo->i_pos += 4; \ - } - -#define GETLL( p_field ) \ - { \ - read( p_ifo->i_fd , (p_field) , 8 ); \ - *(p_field) = ntoh64( *(p_field) ); \ -/*fprintf(stderr, "Pos : %lld Value : %lld\n", \ - (long long)(p_ifo->i_pos - i_start), \ - *(p_field) );*/ \ - p_ifo->i_pos += 8; \ - } - -#define FLUSH( i_len ) \ - { \ -/*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/ \ - p_ifo->i_pos = lseek( p_ifo->i_fd , \ - p_ifo->i_pos + (i_len), SEEK_SET ); \ - } + //fprintf( stderr, "PTL\n" ); + + PARINF.i_country_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + PARINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + PARINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + PARINF.p_parental_desc = malloc( PARINF.i_country_nb + * sizeof(parental_desc_t) ); + if( PARINF.p_parental_desc == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoInit" ); + return -1; + } -/* - * Function common to Video Manager and Video Title set Processing - */ + for( i = 0 ; i < PARINF.i_country_nb ; i++ ) + { + ReadBytes( p_ifo, p_buf, &p_tmp, + PARINF.p_parental_desc[i].ps_country_code, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + PARINF.p_parental_desc[i].i_parental_mask_start_byte = + ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + } -/***************************************************************************** - * ReadPGC : Fills the Program Chain structure. - *****************************************************************************/ -#define GETCOMMAND( p_com ) \ - { \ - read( p_ifo->i_fd , (p_com) , 8 ); \ -/*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n", \ - (long long)(p_ifo->i_pos - i_start), \ - (int)((p_com)->i_type), \ - (int)((p_com)->i_direct), \ - (int)((p_com)->i_cmd), \ - (int)((p_com)->i_dir_cmp), \ - (int)((p_com)->i_cmp), \ - (int)((p_com)->i_sub_cmd), \ - (int)((p_com)->data.pi_16[0]), \ - (int)((p_com)->data.pi_16[1]), \ - (int)((p_com)->data.pi_16[2]));*/ \ -/* CommandRead( *(p_com) );*/ \ - p_ifo->i_pos += 8; \ - } - -static pgc_t ReadPGC( ifo_t* p_ifo ) -{ - pgc_t pgc; - int i; - off_t i_start = p_ifo->i_pos; + PARINF.p_parental_mask = malloc( PARINF.i_country_nb + * sizeof(parental_mask_t) ); + if( PARINF.p_parental_mask == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoInit" ); + return -1; + } -//fprintf( stderr, "PGC\n" ); + for( i = 0 ; i < PARINF.i_country_nb ; i++ ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + OFF2LB( + PARINF.p_parental_desc[i].i_parental_mask_start_byte ) ) + + (PARINF.p_parental_desc[i].i_parental_mask_start_byte & 0x7ff); - FLUSH(2); - GETC( &pgc.i_prg_nb ); - GETC( &pgc.i_cell_nb ); - GETL( &pgc.i_play_time ); - GETL( &pgc.i_prohibited_user_op ); - for( i=0 ; i<8 ; i++ ) - { - GETS( &pgc.pi_audio_status[i] ); - } - for( i=0 ; i<32 ; i++ ) - { - GETL( &pgc.pi_subpic_status[i] ); - } - GETS( &pgc.i_next_pgc_nb ); - GETS( &pgc.i_prev_pgc_nb ); - GETS( &pgc.i_goup_pgc_nb ); - GETC( &pgc.i_still_time ); - GETC( &pgc.i_play_mode ); - for( i=0 ; i<16 ; i++ ) - { - GETL( &pgc.pi_yuv_color[i] ); - /* FIXME : We have to erase the extra bit */ - } - GETS( &pgc.i_com_tab_sbyte ); - GETS( &pgc.i_prg_map_sbyte ); - GETS( &pgc.i_cell_play_inf_sbyte ); - GETS( &pgc.i_cell_pos_inf_sbyte ); - - /* Parsing of pgc_com_tab_t */ - if( pgc.i_com_tab_sbyte ) - { - p_ifo->i_pos = lseek( p_ifo->i_fd, i_start - + pgc.i_com_tab_sbyte, SEEK_SET ); - GETS( &pgc.com_tab.i_pre_com_nb ); - GETS( &pgc.com_tab.i_post_com_nb ); - GETS( &pgc.com_tab.i_cell_com_nb ); - FLUSH( 2 ); - if( pgc.com_tab.i_pre_com_nb ) - { - pgc.com_tab.p_pre_com = - malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t)); - if( pgc.com_tab.p_pre_com == NULL ) - { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return pgc; - } - for( i=0 ; ivmg.vts_inf + if( MGINF.i_vts_inf_start_sector ) + { + u64 i_temp; + + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start + + MGINF.i_vts_inf_start_sector ); + i_start = p_ifo->i_pos; + + //fprintf( stderr, "VTS ATTR\n" ); + + VTSINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );; + //fprintf( stderr, "VTS ATTR Nb: %d\n", VTSINF.i_vts_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + VTSINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + VTSINF.pi_vts_attr_start_byte = + malloc( VTSINF.i_vts_nb * sizeof(u32) ); + if( VTSINF.pi_vts_attr_start_byte == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoInit" ); + return -1; + } + + for( i = 0 ; i < VTSINF.i_vts_nb ; i++ ) + { + VTSINF.pi_vts_attr_start_byte[i] = + ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + VTSINF.p_vts_attr = malloc( VTSINF.i_vts_nb * sizeof(vts_attr_t) ); + if( VTSINF.p_vts_attr == NULL ) { - pgc.com_tab.p_post_com = - malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t)); - if( pgc.com_tab.p_post_com == NULL ) + intf_ErrMsg( "ifo error: out of memory in IfoInit" ); + return -1; + } + + for( i = 0 ; i < VTSINF.i_vts_nb ; i++ ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( VTSINF.pi_vts_attr_start_byte[i] ) ) + + ( VTSINF.pi_vts_attr_start_byte[i] & 0x7ff ); + + VTSINF.p_vts_attr[i].i_end_byte = + ReadDouble( p_ifo, p_buf, &p_tmp ); + VTSINF.p_vts_attr[i].i_cat_app_type = + ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + VTSINF.p_vts_attr[i].i_vts_menu_audio_nb = + ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "m audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_audio_nb ); + + for( j = 0 ; j < 8 ; j++ ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return pgc; + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); } - for( i=0 ; ib_error = 1; - return pgc; + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );; } - for( i=0 ; ii_pos = lseek( p_ifo->i_fd, i_start - + pgc.i_prg_map_sbyte, SEEK_SET ); - pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) ); - if( pgc.prg_map.pi_entry_cell == NULL ) + if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_start + + MGINF.i_cell_inf_start_sector ) < 0 ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return pgc; + return -1; } - GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb ); - /* FIXME : check endianness here */ } - /* Parsing of cell_play_inf_t */ - if( pgc.i_cell_play_inf_sbyte ) + + /* + * global vob unit map. + */ + if( MGINF.i_vobu_map_start_sector ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, i_start - + pgc.i_cell_play_inf_sbyte, SEEK_SET ); - pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) ); - if( pgc.p_cell_play_inf == NULL ) + if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_start + + MGINF.i_vobu_map_start_sector ) < 0 ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return pgc; + return -1; } - for( i=0 ; ivts.b_initialized = 0; + + intf_WarnMsg( 2, "ifo info: vmg initialized" ); + + return 0; +} + +/***************************************************************************** + * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure. + *****************************************************************************/ +int IfoTitleSet( ifo_t * p_ifo ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_off; + int i_start; + u64 i_temp; + u16 i_short; + int i, j; + + if( p_ifo->vts.b_initialized ) + { + FreeTitleSet( &p_ifo->vts ); + } + + i_off = p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_start_sector + + p_ifo->i_start; + + //fprintf(stderr, "offset: %d\n" , i_off ); + + p_tmp = FillBuffer( p_ifo, p_buf, i_off ); + //i_start = p_ifo->i_pos; + p_ifo->vts.i_pos = p_ifo->i_pos; + +#define MGINF p_ifo->vts.manager_inf + + /* + * read manager information + */ + //fprintf( stderr, "VTSI\n" ); + + ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id , 12 ); + MGINF.psz_id[12] = '\0'; + MGINF.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 12 ); + MGINF.i_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp ); + MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 90 ); + MGINF.i_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 60 ); + MGINF.i_menu_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_menu_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_time_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 24 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_menu_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 8 ; i++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + MGINF.i_menu_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 28 ; i++ ) + { + /* FIXME : take care of endianness */ + ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + + i_short = ReadWord( p_ifo, p_buf, &p_tmp ); + i_short >>= 2; + MGINF.video_attr.i_mode = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_letterboxed = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_source_res = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_line21_2 = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_line21_1 = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_perm_displ = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_ratio = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_system = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_compression = i_short & 0x3; + + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vtsi audio nb : %d\n", MGINF.i_audio_nb ); + + for( i = 0 ; i < 8 ; i++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "Audio %d: %llx\n", i, i_temp ); + i_temp >>= 8; + MGINF.p_audio_attr[i].i_bar = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_audio_attr[i].i_caption = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_audio_attr[i].i_foo = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_audio_attr[i].i_lang_code = i_temp & 0xffff; + i_temp >>= 16; + MGINF.p_audio_attr[i].i_num_channels = i_temp & 0x7; + i_temp >>= 3; + MGINF.p_audio_attr[i].i_test = i_temp & 0x1; + i_temp >>= 1; + MGINF.p_audio_attr[i].i_sample_freq = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_quantization = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_appl_mode = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_type = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1; + i_temp >>= 1; + MGINF.p_audio_attr[i].i_coding_mode = i_temp & 0x7; + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vtsi subpic nb : %d\n", MGINF.i_spu_nb ); + + for( i=0 ; i> 16; + //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp ); + MGINF.p_spu_attr[i].i_caption = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_spu_attr[i].i_foo = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_spu_attr[i].i_lang_code = i_temp & 0xffff; + i_temp >>= 16; + MGINF.p_spu_attr[i].i_prefix = i_temp & 0xffff; + } + + /* + * read title information: set of pointers to title + */ +#define TITINF p_ifo->vts.title_inf + if( MGINF.i_title_inf_start_sector ) + { + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos + + MGINF.i_title_inf_start_sector ); + + i_start = p_ifo->i_pos; + + //fprintf( stderr, "VTS PTR\n" ); + + TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "VTS title_inf nb: %d\n", TITINF.i_title_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + TITINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + TITINF.pi_start_byte = malloc( TITINF.i_title_nb * sizeof(u32) ); + if( TITINF.pi_start_byte == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" ); + return -1; + } + + for( i = 0 ; i < TITINF.i_title_nb ; i++ ) { - GETS( &pgc.p_cell_play_inf[i].i_cat ); - GETC( &pgc.p_cell_play_inf[i].i_still_time ); - GETC( &pgc.p_cell_play_inf[i].i_com_nb ); - GETL( &pgc.p_cell_play_inf[i].i_play_time ); - GETL( &pgc.p_cell_play_inf[i].i_entry_sector ); - GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector ); - GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector ); - GETL( &pgc.p_cell_play_inf[i].i_lsector ); + TITINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + /* Parsing of tts */ + TITINF.p_title_start = malloc( TITINF.i_title_nb + * sizeof(title_start_t) ); + if( TITINF.p_title_start == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" ); + return -1; + } + + for( i = 0 ; i < TITINF.i_title_nb ; i++ ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( TITINF.pi_start_byte[i] ) ) + + (TITINF.pi_start_byte[i] & 0x7ff); + + TITINF.p_title_start[i].i_title_id = + ReadWord( p_ifo, p_buf, &p_tmp ); + TITINF.p_title_start[i].i_chapter = + ReadWord( p_ifo, p_buf, &p_tmp ); } } - /* Parsing of cell_pos_inf_map */ - if( pgc.i_cell_pos_inf_sbyte ) +#undef TITINF + + /* + * menu unit information + */ + if( MGINF.i_menu_unit_start_sector ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, i_start - + pgc.i_cell_pos_inf_sbyte, SEEK_SET ); - pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) ); - if( pgc.p_cell_play_inf == NULL ) + if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos + + MGINF.i_menu_unit_start_sector ) < 0 ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return pgc; + return -1; } - for( i=0 ; ivts.title_unit, p_ifo->vts.i_pos + + MGINF.i_title_unit_start_sector, 0 ) < 0 ) { - GETS( &pgc.p_cell_pos_inf[i].i_vob_id ); - FLUSH( 1 ); - GETC( &pgc.p_cell_pos_inf[i].i_cell_id ); + return -1; } - } + } - return pgc; -} + /* + * time map information + */ +#define TIMINF p_ifo->vts.time_inf + if( MGINF.i_time_inf_start_sector ) + { + u8 p_buf[DVD_LB_SIZE]; -/***************************************************************************** - * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table - *****************************************************************************/ -static pgci_inf_t ReadUnit( ifo_t* p_ifo ) -{ - pgci_inf_t inf; - int i; - off_t i_start = p_ifo->i_pos; + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos + + MGINF.i_time_inf_start_sector ); + + //fprintf( stderr, "TMAP\n" ); -//fprintf( stderr, "Unit\n" ); + TIMINF.i_nb = ReadWord( p_ifo, p_buf, &p_tmp );; + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + TIMINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + TIMINF.pi_start_byte = malloc( TIMINF.i_nb * sizeof(u32) ); + if( TIMINF.pi_start_byte == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" ); + return -1; + } - GETS( &inf.i_srp_nb ); - FLUSH( 2 ); - GETL( &inf.i_lu_ebyte ); - inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) ); - if( inf.p_srp == NULL ) + for( i = 0 ; i < TIMINF.i_nb ; i++ ) + { + TIMINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + TIMINF.p_time_map = malloc( TIMINF.i_nb * sizeof(time_map_t) ); + if( TIMINF.p_time_map == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" ); + return -1; + } + + for( i = 0 ; i < TIMINF.i_nb ; i++ ) + { + TIMINF.p_time_map[i].i_time_unit = ReadByte( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + TIMINF.p_time_map[i].i_entry_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + + TIMINF.p_time_map[i].pi_sector = + malloc( TIMINF.p_time_map[i].i_entry_nb * sizeof(u32) ); + if( TIMINF.p_time_map[i].pi_sector == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" ); + return -1; + } + + for( j = 0 ; j < TIMINF.p_time_map[i].i_entry_nb ; j++ ) + { + TIMINF.p_time_map[i].pi_sector[j] = + ReadDouble( p_ifo, p_buf, &p_tmp ); + } + } + } +#undef TIMINF + + if( MGINF.i_menu_cell_inf_start_sector + && ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos + + MGINF.i_menu_cell_inf_start_sector ) < 0 ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return inf; + return -1; } - for( i=0 ; ivts.menu_vobu_map, p_ifo->vts.i_pos + + MGINF.i_menu_vobu_map_start_sector ) < 0 ) { - GETC( &inf.p_srp[i].i_pgc_cat_mask ); - GETC( &inf.p_srp[i].i_pgc_cat ); - GETS( &inf.p_srp[i].i_par_mask ); - GETL( &inf.p_srp[i].i_pgci_sbyte ); + return -1; } - for( i=0 ; ivts.cell_inf, p_ifo->vts.i_pos + + MGINF.i_cell_inf_start_sector ) ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, - i_start + inf.p_srp[i].i_pgci_sbyte, - SEEK_SET ); - inf.p_srp[i].pgc = ReadPGC( p_ifo ); + return -1; } - return inf; + if( MGINF.i_vobu_map_start_sector + && ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos + + MGINF.i_vobu_map_start_sector ) ) + { + return -1; + } +#undef MGINF + + intf_WarnMsg( 2, "ifo info: vts %d initialized", + p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_title_set_num ); + + p_ifo->vts.b_initialized = 1; + + return 0; } /***************************************************************************** - * ReadUnitTable : Fills the PGCI Unit structure. + * FreeTitleSet : free all structures allocated by IfoTitleSet *****************************************************************************/ -static pgci_ut_t ReadUnitTable( ifo_t* p_ifo ) +static int FreeTitleSet( vts_t * p_vts ) { - pgci_ut_t pgci; - int i; - off_t i_start = p_ifo->i_pos; - -//fprintf( stderr, "Unit Table\n" ); + int i; - GETS( &pgci.i_lu_nb ); - FLUSH( 2 ); - GETL( &pgci.i_ebyte ); - pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) ); - if( pgci.p_lu == NULL ) + if( p_vts->manager_inf.i_vobu_map_start_sector ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return pgci; + FreeVobuMap( &p_vts->vobu_map ); } - for( i=0 ; imanager_inf.i_cell_inf_start_sector ) { - GET( pgci.p_lu[i].ps_lang_code, 2 ); - FLUSH( 1 ); - GETC( &pgci.p_lu[i].i_existence_mask ); - GETL( &pgci.p_lu[i].i_lu_sbyte ); + FreeCellInf( &p_vts->cell_inf ); } - pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) ); - if( pgci.p_pgci_inf == NULL ) + + if( p_vts->manager_inf.i_menu_vobu_map_start_sector ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return pgci; + FreeVobuMap( &p_vts->menu_vobu_map ); } - for( i=0 ; imanager_inf.i_menu_cell_inf_start_sector ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, i_start + - pgci.p_lu[i].i_lu_sbyte, - SEEK_SET ); - pgci.p_pgci_inf[i] = ReadUnit( p_ifo ); + FreeCellInf( &p_vts->menu_cell_inf ); } - return pgci; -} + if( p_vts->manager_inf.i_time_inf_start_sector ) + { + for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ ) + { + free( p_vts->time_inf.p_time_map[i].pi_sector ); + } -/***************************************************************************** - * ReadCellInf : Fills the Cell Information structure. - *****************************************************************************/ -static c_adt_t ReadCellInf( ifo_t* p_ifo ) -{ - c_adt_t c_adt; - off_t i_start = p_ifo->i_pos; - int i; + free( p_vts->time_inf.p_time_map ); + free( p_vts->time_inf.pi_start_byte ); + } -//fprintf( stderr, "CELL ADD\n" ); + if( p_vts->manager_inf.i_title_unit_start_sector ) + { + FreeUnitInf( &p_vts->title_unit ); + } - GETS( &c_adt.i_vob_nb ); - FLUSH( 2 ); - GETL( &c_adt.i_ebyte ); - c_adt.i_cell_nb = - ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t); - c_adt.p_cell_inf = malloc( c_adt.i_cell_nb *sizeof(cell_inf_t) ); - if( c_adt.p_cell_inf == NULL ) + if( p_vts->manager_inf.i_menu_unit_start_sector ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return c_adt; + FreeTitleUnit( &p_vts->menu_unit ); } - for( i = 0 ; i < c_adt.i_cell_nb ; i++ ) + + if( p_vts->manager_inf.i_title_inf_start_sector ) { - GETS( &c_adt.p_cell_inf[i].i_vob_id ); - GETC( &c_adt.p_cell_inf[i].i_cell_id ); - FLUSH( 1 ); - GETL( &c_adt.p_cell_inf[i].i_ssector ); - GETL( &c_adt.p_cell_inf[i].i_esector ); + free( p_vts->title_inf.pi_start_byte ); + free( p_vts->title_inf.p_title_start ); } + + p_vts->b_initialized = 0; - return c_adt; + return 0; } /***************************************************************************** - * ReadMap : Fills the VOBU Map structure. + * IfoDestroy : Frees all the memory allocated to ifo structures *****************************************************************************/ -static vobu_admap_t ReadMap( ifo_t* p_ifo ) +void IfoDestroy( ifo_t * p_ifo ) { - vobu_admap_t map; - int i, i_max; - off_t i_start = p_ifo->i_pos; - -//fprintf( stderr, "VOBU ADMAP\n" ); + int i, j; + + FreeTitleSet( &p_ifo->vts ); - GETL( &map.i_ebyte ); - i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32); - map.pi_vobu_ssector = malloc( i_max *sizeof(u32) ); - for( i=0 ; ivmg.manager_inf.i_vobu_map_start_sector ) { - GETL( &map.pi_vobu_ssector[i] ); + FreeVobuMap( &p_ifo->vmg.vobu_map ); } - return map; -} - -/* - * Video Manager Information Processing. - * This is what is contained in video_ts.ifo. - */ - -/***************************************************************************** - * ReadVMGInfMat : Fills the Management Information structure. - *****************************************************************************/ -static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo ) -{ - vmgi_mat_t mat; - int i; -// off_t i_start = p_ifo->i_pos; - -//fprintf( stderr, "VMGI\n" ); - - GET( mat.psz_id , 12 ); - mat.psz_id[12] = '\0'; - GETL( &mat.i_lsector ); - FLUSH( 12 ); - GETL( &mat.i_i_lsector ); - FLUSH( 1 ); - GETC( &mat.i_spec_ver ); - GETL( &mat.i_cat ); - GETS( &mat.i_vol_nb ); - GETS( &mat.i_vol ); - GETC( &mat.i_disc_side ); - FLUSH( 19 ); - GETS( &mat.i_tts_nb ); - GET( mat.ps_provider_id, 32 ); - GETLL( &mat.i_pos_code ); - FLUSH( 24 ); - GETL( &mat.i_i_mat_ebyte ); - GETL( &mat.i_fp_pgc_sbyte ); - FLUSH( 56 ); - GETL( &mat.i_vobs_ssector ); - GETL( &mat.i_ptt_srpt_ssector ); - GETL( &mat.i_pgci_ut_ssector ); - GETL( &mat.i_ptl_mait_ssector ); - GETL( &mat.i_vts_atrt_ssector ); - GETL( &mat.i_txtdt_mg_ssector ); - GETL( &mat.i_c_adt_ssector ); - GETL( &mat.i_vobu_admap_ssector ); - FLUSH( 32 ); - GETS( &mat.i_video_atrt ); - FLUSH( 1 ); - GETC( &mat.i_audio_nb ); -//fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb ); - for( i=0 ; i < 8 ; i++ ) - { - GETLL( &mat.pi_audio_atrt[i] ); - } - FLUSH( 17 ); - GETC( &mat.i_subpic_nb ); -//fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb ); - for( i=0 ; i < mat.i_subpic_nb ; i++ ) - { - GET( &mat.pi_subpic_atrt[i], 6 ); - /* FIXME : take care of endianness */ + if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector ) + { + FreeCellInf( &p_ifo->vmg.cell_inf ); } - return mat; -} + if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector ) + { + free( p_ifo->vmg.vts_inf.p_vts_attr ); + free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte ); + } -/***************************************************************************** - * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure. - *****************************************************************************/ -static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo ) -{ - vmg_ptt_srpt_t ptr; - int i; -// off_t i_start = p_ifo->i_pos; + /* free parental information structures */ + if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector ) + { + for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ ) + { + for( j = 0 ; j < 8 ; j++ ) + { + free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] ); + } + } -//fprintf( stderr, "PTR\n" ); + free( p_ifo->vmg.parental_inf.p_parental_mask ); + free( p_ifo->vmg.parental_inf.p_parental_desc ); + } - GETS( &ptr.i_ttu_nb ); - FLUSH( 2 ); - GETL( &ptr.i_ebyte ); - /* Parsing of tts */ - ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) ); - if( ptr.p_tts == NULL ) + if( p_ifo->vmg.manager_inf.i_title_unit_start_sector ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return ptr; + FreeTitleUnit( &p_ifo->vmg.title_unit ); } - for( i=0 ; ivmg.manager_inf.i_title_inf_start_sector ) { - GETC( &ptr.p_tts[i].i_play_type ); - GETC( &ptr.p_tts[i].i_angle_nb ); - GETS( &ptr.p_tts[i].i_ptt_nb ); - GETS( &ptr.p_tts[i].i_parental_id ); - 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 ); + free( p_ifo->vmg.title_inf.p_attr ); } - return ptr; + FreeTitle( &p_ifo->vmg.title ); + + free( p_ifo ); + + return; } +/* + * Function common to Video Manager and Video Title set Processing + */ + /***************************************************************************** - * ReadParentalInf : Fills the Parental Management structure. + * ReadTitle : Fills the title structure. + ***************************************************************************** + * Titles are logical stream units that correspond to a whole inside the dvd. + * Several title can point to the same part of the physical DVD, and give + * map to different anglesfor instance. *****************************************************************************/ -static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo ) +static int ReadTitle( ifo_t * p_ifo, title_t * p_title, int i_block, int i_bytes ) { - vmg_ptl_mait_t par; - int i, j, k; - off_t i_start = p_ifo->i_pos; + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + u16 i_audio; + u32 i_spu; + int i; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes; -//fprintf( stderr, "PTL\n" ); + i_start = p_ifo->i_pos; - GETS( &par.i_country_nb ); - GETS( &par.i_vts_nb ); - GETL( &par.i_ebyte ); - par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) ); - if( par.p_ptl_desc == NULL ) + //fprintf( stderr, "PGC @ %d + %d\n", p_ifo->i_pos, i_bytes ); + + DumpBytes( p_ifo, p_buf, &p_tmp, 2); + p_title->i_chapter_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + p_title->i_cell_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb ); + p_title->i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp ); + p_title->i_prohibited_user_op = ReadDouble( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 8 ; i++ ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return par; + i_audio = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->pi_audio_status[i].i_foo = i_audio & 0xff; + i_audio >>= 8; + p_title->pi_audio_status[i].i_position = i_audio & 0x07; + i_audio >>= 7; + p_title->pi_audio_status[i].i_available = i_audio; } - for( i=0 ; ipi_spu_status[i].i_position_pan = i_spu & 0x1f; + i_spu >>= 8; + p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f; + i_spu >>= 8; + p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f; + i_spu >>= 8; + p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f; + i_spu >>= 7; + p_title->pi_spu_status[i].i_available = i_spu; } - par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) ); - if( par.p_ptl_mask == NULL ) + + p_title->i_next_title_num = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_prev_title_num = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_go_up_title_num = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_still_time = ReadByte( p_ifo, p_buf, &p_tmp ); + p_title->i_play_mode = ReadByte( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 16 ; i++ ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return par; + /* FIXME : We have to erase the extra bit */ + p_title->pi_yuv_color[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); } - for( i=0 ; ii_command_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_chapter_map_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_cell_play_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_cell_pos_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + + /* parsing of command_t */ + if( p_title->i_command_start_byte ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, i_start + - par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET ); - for( j=1 ; j<=8 ; j++ ) + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( p_title->i_command_start_byte + i_bytes ) ) + + ( (p_title->i_command_start_byte + i_bytes) & 0x7ff ); + + /* header */ + p_title->command.i_pre_command_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->command.i_post_command_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->command.i_cell_command_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + + /* pre-title commands */ + if( p_title->command.i_pre_command_nb ) { - par.p_ptl_mask[i].ppi_ptl_mask[j] = - malloc( par.i_vts_nb *sizeof(u16) ); - if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL ) + p_title->command.p_pre_command = + malloc( p_title->command.i_pre_command_nb + * sizeof(command_desc_t) ); + + if( p_title->command.p_pre_command == NULL ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return par; - } - for( k=0 ; kcommand.i_pre_command_nb ; i++ ) { - GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] ); + p_title->command.p_pre_command[i] = + ReadQuad( p_ifo, p_buf, &p_tmp ); } } - } + else + { + p_title->command.p_pre_command = NULL; + } - return par; -} + /* post-title commands */ + if( p_title->command.i_post_command_nb ) + { + p_title->command.p_post_command = + malloc( p_title->command.i_post_command_nb + * sizeof(command_desc_t) ); -/***************************************************************************** - * ReadVTSAttr : Fills the structure about VTS attributes. - *****************************************************************************/ -static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo ) -{ - vmg_vts_atrt_t atrt; - int i, j; - off_t i_start = p_ifo->i_pos; + if( p_title->command.p_post_command == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in ReadTitle" ); + return -1; + } + + for( i = 0 ; i < p_title->command.i_post_command_nb ; i++ ) + { + p_title->command.p_post_command[i] = + ReadQuad( p_ifo, p_buf, &p_tmp ); + } + } + else + { + p_title->command.p_post_command = NULL; + } -//fprintf( stderr, "VTS ATTR\n" ); + /* cell commands */ + if( p_title->command.i_cell_command_nb ) + { + p_title->command.p_cell_command = + malloc( p_title->command.i_cell_command_nb + * sizeof(command_desc_t) ); - GETS( &atrt.i_vts_nb ); - FLUSH( 2 ); - GETL( &atrt.i_ebyte ); - atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) ); - if( atrt.pi_vts_atrt_sbyte == NULL ) - { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return atrt; + if( p_title->command.p_cell_command == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in ReadTitle" ); + return -1; + } + + for( i = 0 ; i < p_title->command.i_cell_command_nb ; i++ ) + { + p_title->command.p_cell_command[i] = + ReadQuad( p_ifo, p_buf, &p_tmp ); + } + } + else + { + p_title->command.p_cell_command = NULL; + } } - for( i=0 ; ii_chapter_map_start_byte ) { - GETL( &atrt.pi_vts_atrt_sbyte[i] ); + p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, + OFF2LB( i_start + p_title->i_chapter_map_start_byte ), + DVDCSS_NOFLAGS ); + + p_title->chapter_map.pi_start_cell = + malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) ); + + if( p_title->chapter_map.pi_start_cell == NULL ) + { + intf_ErrMsg( "ifo error: out of memory in Read Title" ); + return -1; + } + + ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell, + p_title->i_chapter_nb ); } - atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) ); - if( atrt.p_vts_atrt == NULL ) + else { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return atrt; + p_title->chapter_map.pi_start_cell = NULL; } - for( i=0 ; ii_cell_play_start_byte ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, i_start + - atrt.pi_vts_atrt_sbyte[i], - SEEK_SET ); - GETL( &atrt.p_vts_atrt[i].i_ebyte ); - GETL( &atrt.p_vts_atrt[i].i_cat_app_type ); - GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt ); - FLUSH( 1 ); - GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb ); -//fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb ); - for( j=0 ; j<8 ; j++ ) + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) ) + + ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff ); + + p_title->p_cell_play = malloc( p_title->i_cell_nb + * sizeof(cell_play_t) ); + + if( p_title->p_cell_play == NULL ) { - GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] ); + intf_ErrMsg( "ifo error: out of memory in ReadTitle" ); + return -1; } - FLUSH( 17 ); - GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb ); -//fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb ); - for( j=0 ; j<28 ; j++ ) + + for( i = 0 ; i < p_title->i_cell_nb ; i++ ) { - GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 ); - /* FIXME : Fix endianness issue here */ +#define PLAY p_title->p_cell_play[i] + PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp ); + PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp ); + PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); +#undef PLAY } - FLUSH( 2 ); - GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt ); - FLUSH( 1 ); - GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb ); -//fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb ); - for( j=0 ; j<8 ; j++ ) + } + + /* Parsing of cell_pos_t */ + if( p_title->i_cell_pos_start_byte ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) ) + + ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff ); + + p_title->p_cell_pos = malloc( p_title->i_cell_nb + * sizeof(cell_pos_t) ); + + if( p_title->p_cell_pos == NULL ) { - GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] ); + intf_ErrMsg( "ifo error: out of memory" ); + return -1; } - FLUSH( 17 ); - GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb ); -//fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb ); - for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ ) + + for( i = 0 ; i < p_title->i_cell_nb ; i++ ) { - GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 ); - /* FIXME : Fix endianness issue here */ + p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp ); } - } + } - return atrt; + return 0; } - + /***************************************************************************** - * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure. + * FreeTitle: frees alla structure allocated by a call to ReadTitle *****************************************************************************/ -static vmg_t ReadVMG( ifo_t* p_ifo ) +static int FreeTitle( title_t * p_title ) { - vmg_t vmg; + if( p_title->i_command_start_byte ) + { + if( p_title->command.i_pre_command_nb ) + { + free( p_title->command.p_pre_command ); + } + + if( p_title->command.i_post_command_nb ) + { + free( p_title->command.p_post_command ); + } + + if( p_title->command.i_cell_command_nb ) + { + free( p_title->command.p_cell_command ); + } + } - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET); - vmg.mat = ReadVMGInfMat( p_ifo ); - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + - vmg.mat.i_fp_pgc_sbyte, SEEK_SET ); - vmg.pgc = ReadPGC( p_ifo ); - if( vmg.mat.i_ptt_srpt_ssector ) + if( p_title->i_chapter_map_start_byte ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + - vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE, - SEEK_SET ); - vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo ); + free( p_title->chapter_map.pi_start_cell ); } - if( vmg.mat.i_pgci_ut_ssector ) + + if( p_title->i_cell_play_start_byte ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + - vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE, - SEEK_SET ); - vmg.pgci_ut = ReadUnitTable( p_ifo ); + free( p_title->p_cell_play ); } - if( vmg.mat.i_ptl_mait_ssector ) + + if( p_title->i_cell_pos_start_byte ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + - vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE, - SEEK_SET ); - vmg.ptl_mait = ReadParentalInf( p_ifo ); + free( p_title->p_cell_pos ); } - if( vmg.mat.i_vts_atrt_ssector ) + + return 0; +} + +/***************************************************************************** + * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table + *****************************************************************************/ +static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf, + int i_block, int i_bytes ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + int i; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes; + + i_start = p_ifo->i_pos; + //fprintf( stderr, "Unit\n" ); + + p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + p_unit_inf->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + p_unit_inf->p_title = + malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) ); + if( p_unit_inf->p_title == NULL ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + - vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE, - SEEK_SET ); - vmg.vts_atrt = ReadVTSAttr( p_ifo ); + intf_ErrMsg( "ifo error: out of memory in ReadUnit" ); + return -1; } - if( vmg.mat.i_c_adt_ssector ) + + for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + - vmg.mat.i_c_adt_ssector *DVD_LB_SIZE, - SEEK_SET ); - vmg.c_adt = ReadCellInf( p_ifo ); +#define TITLE p_unit_inf->p_title[i] + TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp ); + TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category ); + TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp ); + TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); +#undef TITLE } - if( vmg.mat.i_vobu_admap_ssector ) + + for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + - vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE, - SEEK_SET ); - vmg.vobu_admap = ReadMap( p_ifo ); + //fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos ); + ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start + + OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ), + (p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff ); } - return vmg; -} -/* - * Video Title Set Information Processing. - * This is what is contained in vts_*.ifo. - */ + return 0; +} /***************************************************************************** - * ReadVTSInfMat : Fills the Title Set Information structure. - *****************************************************************************/ -static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo ) + * FreeUnitInf : frees a structure allocated by ReadUnit + *****************************************************************************/ +static int FreeUnitInf( unit_inf_t * p_unit_inf ) { - vtsi_mat_t mat; - int i; -// off_t i_start = p_ifo->i_pos; - -//fprintf( stderr, "VTSI\n" ); - - GET( mat.psz_id , 12 ); - mat.psz_id[12] = '\0'; - GETL( &mat.i_lsector ); - FLUSH( 12 ); - GETL( &mat.i_i_lsector ); - FLUSH( 1 ); - GETC( &mat.i_spec_ver ); - GETL( &mat.i_cat ); - FLUSH( 90 ); - GETL( &mat.i_mat_ebyte ); - FLUSH( 60 ); - GETL( &mat.i_m_vobs_ssector ); - GETL( &mat.i_tt_vobs_ssector ); - GETL( &mat.i_ptt_srpt_ssector ); - GETL( &mat.i_pgcit_ssector ); - GETL( &mat.i_m_pgci_ut_ssector ); - GETL( &mat.i_tmap_ti_ssector ); - GETL( &mat.i_m_c_adt_ssector ); - GETL( &mat.i_m_vobu_admap_ssector ); - GETL( &mat.i_c_adt_ssector ); - GETL( &mat.i_vobu_admap_ssector ); - FLUSH( 24 ); - GETS( &mat.i_m_video_atrt ); - FLUSH( 1 ); - GETC( &mat.i_m_audio_nb ); - for( i=0 ; i<8 ; i++ ) - { - GETLL( &mat.pi_m_audio_atrt[i] ); - } - FLUSH( 17 ); - GETC( &mat.i_m_subpic_nb ); - for( i=0 ; i<28 ; i++ ) - { - GET( &mat.pi_m_subpic_atrt[i], 6 ); - /* FIXME : take care of endianness */ - } - FLUSH( 2 ); - GETS( &mat.i_video_atrt ); - FLUSH( 1 ); - GETC( &mat.i_audio_nb ); -//fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb ); - for( i=0 ; i<8 ; i++ ) - { - GETLL( &mat.pi_audio_atrt[i] ); - } - FLUSH( 17 ); - GETC( &mat.i_subpic_nb ); -//fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb ); - for( i=0 ; ip_title != NULL ) { - GET( &mat.pi_subpic_atrt[i], 6 ); - /* FIXME : take care of endianness */ + for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ ) + { + FreeTitle( &p_unit_inf->p_title[i].title ); + } + + free( p_unit_inf->p_title ); } - return mat; + return 0; } + /***************************************************************************** - * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure. + * ReadTitleUnit: Fills the Title Unit structure. *****************************************************************************/ -static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo ) +static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit, + int i_block ) { - vts_ptt_srpt_t ptr; + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; int i; - off_t i_start = p_ifo->i_pos; + int i_start; -//fprintf( stderr, "PTR\n" ); + p_tmp = FillBuffer( p_ifo, p_buf, i_block ); + i_start = p_ifo->i_pos; + //fprintf( stderr, "Unit Table\n" ); - GETS( &ptr.i_ttu_nb ); - FLUSH( 2 ); - GETL( &ptr.i_ebyte ); - ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) ); - if( ptr.pi_ttu_sbyte == NULL ) + p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + p_title_unit->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte ); + + p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) ); + if( p_title_unit->p_unit == NULL ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return ptr; + intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" ); + return -1; } - for( i=0 ; ii_unit_nb ; i++ ) { - GETL( &ptr.pi_ttu_sbyte[i] ); + //ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 ); + p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + p_title_unit->p_unit[i].i_existence_mask = + ReadByte( p_ifo, p_buf, &p_tmp ); + p_title_unit->p_unit[i].i_unit_inf_start_byte = + ReadDouble( p_ifo, p_buf, &p_tmp ); } - /* Parsing of tts */ - ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) ); - if( ptr.p_ttu == NULL ) + + p_title_unit->p_unit_inf = + malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) ); + if( p_title_unit->p_unit_inf == NULL ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return ptr; + intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" ); + return -1; } - for( i=0 ; ii_unit_nb ; i++ ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, i_start + - ptr.pi_ttu_sbyte[i], SEEK_SET ); - GETS( &ptr.p_ttu[i].i_pgc_nb ); - GETS( &ptr.p_ttu[i].i_prg_nb ); + ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start + + OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ), + p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff ); } - return ptr; + return 0; } /***************************************************************************** - * ReadVTSTimeMap : Fills the time map table + * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit *****************************************************************************/ -static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo ) +static int FreeTitleUnit( title_unit_t * p_title_unit ) { - vts_tmap_ti_t tmap; - int i,j; -// off_t i_start = p_ifo->i_pos; - -//fprintf( stderr, "TMAP\n" ); + int i; - GETS( &tmap.i_nb ); - FLUSH( 2 ); - GETL( &tmap.i_ebyte ); - tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) ); - if( tmap.pi_sbyte == NULL ) - { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return tmap; - } - for( i=0 ; ip_unit_inf != NULL ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return tmap; - } - for( i=0 ; ib_error = 1; - return tmap; - } - for( j=0 ; ji_unit_nb ; i++ ) { - GETL( &tmap.p_tmap[i].pi_sector[j] ); + FreeUnitInf( &p_title_unit->p_unit_inf[i] ); } + + free( p_title_unit->p_unit_inf ); } - return tmap; + return 0; } - /***************************************************************************** - * ReadVTS : Parse vts*.ifo files to fill the Video Title Set structure. + * ReadCellInf : Fills the Cell Information structure. *****************************************************************************/ -static vts_t ReadVTS( ifo_t* p_ifo ) +static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block ) { - vts_t vts; + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + int i; - vts.i_pos = p_ifo->i_pos; + p_tmp = FillBuffer( p_ifo, p_buf, i_block ); + i_start = p_ifo->i_pos; + //fprintf( stderr, "CELL ADD\n" ); - vts.mat = ReadVTSInfMat( p_ifo ); - if( vts.mat.i_ptt_srpt_ssector ) - { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.ptt_srpt = ReadVTSTitlePointer( p_ifo ); - } - if( vts.mat.i_m_pgci_ut_ssector ) - { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.pgci_ut = ReadUnitTable( p_ifo ); - } - if( vts.mat.i_pgcit_ssector ) - { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_pgcit_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.pgci_ti = ReadUnit( p_ifo ); - } - if( vts.mat.i_tmap_ti_ssector ) - { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.tmap_ti = ReadVTSTimeMap( p_ifo ); - } - if( vts.mat.i_m_c_adt_ssector ) - { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.m_c_adt = ReadCellInf( p_ifo ); - } - if( vts.mat.i_m_vobu_admap_ssector ) - { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.m_vobu_admap = ReadMap( p_ifo ); - } - if( vts.mat.i_c_adt_ssector ) + p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + p_cell_inf->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t); + + //fprintf( stderr, "Cell inf: vob %d end %d cell %d\n", p_cell_inf->i_vob_nb, p_cell_inf->i_end_byte, p_cell_inf->i_cell_nb ); + + p_cell_inf->p_cell_map = + malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) ); + if( p_cell_inf->p_cell_map == NULL ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_c_adt_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.c_adt = ReadCellInf( p_ifo ); + intf_ErrMsg( "ifo error: out of memory in ReadCellInf" ); + return -1; } - if( vts.mat.i_vobu_admap_ssector ) + + for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ ) { - p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos + - vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE, - SEEK_SET ); - vts.vobu_admap = ReadMap( p_ifo ); +#define MAP p_cell_inf->p_cell_map[i] + MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp ); + MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MAP.i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + //fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(u32*)(p_tmp)), p_ifo->i_pos); + MAP.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); +#undef MAP } - - return vts; + + return 0; } -/* - * DVD Information Management - */ +/***************************************************************************** + * FreeCellInf : frees structures allocated by ReadCellInf + *****************************************************************************/ +static int FreeCellInf( cell_inf_t * p_cell_inf ) +{ + free( p_cell_inf->p_cell_map ); + + return 0; +} /***************************************************************************** - * IfoRead : Function that fills structure and calls specified functions - * to do it. + * ReadVobuMap : Fills the VOBU Map structure. *****************************************************************************/ -void IfoRead( ifo_t* p_ifo ) +static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block ) { - int i; - off_t i_off; + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + int i, i_max; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ); + i_start = p_ifo->i_pos; + //fprintf( stderr, "VOBU ADMAP\n" ); - /* Video Manager Initialization */ - intf_WarnMsg( 2, "ifo: initializing VMG" ); - p_ifo->vmg = ReadVMG( p_ifo ); + p_vobu_map->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos ) + / sizeof(u32); - /* Video Title Sets initialization */ - p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) ); - if( p_ifo->p_vts == NULL ) + p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(u32) ); + if( p_vobu_map->pi_vobu_start_sector == NULL ) { - intf_ErrMsg( "Out of memory" ); - p_ifo->b_error = 1; - return; + intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" ); + return -1; } - for( i=0 ; ivmg.mat.i_tts_nb ; i++ ) + for( i = 0 ; i < i_max ; i++ ) { + p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); + } - 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 - + p_ifo->i_off; - - p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET ); - - /* FIXME : I really don't know why udf find file - * does not give the exact beginning of file */ - - p_ifo->p_vts[i] = ReadVTS( p_ifo ); + return 0; +} - } +/***************************************************************************** + * FreeVobuMap: frees structures allocated by ReadVobuMap + *****************************************************************************/ +static int FreeVobuMap( vobu_map_t * p_vobu_map ) +{ + free( p_vobu_map->pi_vobu_start_sector ); - return; + return 0; } /* * IFO virtual machine : a set of commands that give the * interactive behaviour of the dvd */ -#if 1 +#if 0 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i])) #define OP_VAL_8(i) ((com.data.pi_8[i])) @@ -1765,3 +2093,96 @@ void CommandPrint( ifo_t ifo ) } #endif + +/***************************************************************************** + * ReadByte and so + *****************************************************************************/ +static u8* FillBuffer( ifo_t* p_ifo, u8* p_buf, int i_pos ) +{ + p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS ); + dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS ); + + return p_buf; +} + +static void ReadBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, + u8* pi_dest, int i_nb ) +{ + if( i_nb > DVD_LB_SIZE ) + { + intf_ErrMsg( "ifo error: excessive ReadBytes call (%i)", i_nb ); + } + + if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE ) + { + int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp ); + + /* Copy the bytes remaining in the current buffer */ + memcpy( pi_dest, *pp_tmp, i_spare ); + pi_dest += i_spare; + i_nb -= i_spare; + + /* Load the next buffer */ + *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); + } + + memcpy( pi_dest, *pp_tmp, i_nb ); + *pp_tmp += i_nb; + + return; +} + +static void DumpBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, int i_nb ) +{ + if( i_nb > DVD_LB_SIZE ) + { + intf_ErrMsg( "ifo error: excessive DumpBytes call (%i)", i_nb ); + } + + *pp_tmp += i_nb; + + if( *pp_tmp >= p_buf + DVD_LB_SIZE ) + { + /* If we went too far, load the next buffer */ + *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ) + + (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) ); + } + + return; +} + +#define ADDBYTE \ + if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \ + { \ + *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \ + } \ + i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++; + +static u8 ReadByte( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u8 i_ret = 0; + ADDBYTE; + return i_ret; +} + +static u16 ReadWord( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u16 i_ret = 0; + ADDBYTE; ADDBYTE; + return i_ret; +} + +static u32 ReadDouble( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u32 i_ret = 0; + ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; + return i_ret; +} + +static u64 ReadQuad( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u64 i_ret = 0; + ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; + return i_ret; +} +