1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.30 2001/06/03 12:47:21 sam Exp $
7 * Author: Stéphane Borel <stef@via.ecp.fr>
10 * - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
11 * - IFO structure documentation by Thomas Mirlacher, Björn Englund,
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
40 #elif defined( _MSC_VER ) && defined( _WIN32 )
56 #include "input_dvd.h"
59 #include "modules_export.h"
61 /*****************************************************************************
63 *****************************************************************************/
64 void CommandRead ( command_desc_t );
65 static int ReadTitle ( ifo_t * , title_t *, off_t );
66 static int FreeTitle ( title_t * );
67 static int ReadUnitInf ( ifo_t * , unit_inf_t *, off_t );
68 static int FreeUnitInf ( unit_inf_t * );
69 static int ReadTitleUnit ( ifo_t * , title_unit_t *, off_t );
70 static int FreeTitleUnit ( title_unit_t * );
71 static int ReadVobuMap ( ifo_t * , vobu_map_t *, off_t );
72 static int FreeVobuMap ( vobu_map_t * );
73 static int ReadCellInf ( ifo_t * , cell_inf_t *, off_t );
74 static int FreeCellInf ( cell_inf_t * );
75 static int FreeTitleSet ( vts_t * );
77 /*****************************************************************************
79 *****************************************************************************/
80 static __inline__ u8* FillBuffer( ifo_t* p_ifo, u8* pi_buffer, off_t i_pos )
86 memset( pi_buffer, 0, DVD_LB_SIZE );
88 p_ifo->i_pos = lseek( p_ifo->i_fd, i_pos, SEEK_SET );
89 read( p_ifo->i_fd, pi_buffer, DVD_LB_SIZE );
91 p_ifo->i_pos = SetFilePointer( (HANDLE) p_ifo->i_fd, i_pos, NULL, FILE_BEGIN );
92 ReadFile( (HANDLE) p_ifo->i_fd, pi_buffer, DVD_LB_SIZE, &tmp, NULL );
98 static __inline__ u8 ReadByte( ifo_t * p_ifo, u8* pi_buffer, u8** pp_current )
102 if( *pp_current > pi_buffer + DVD_LB_SIZE )
104 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
107 i_ret = *(*pp_current)++;
112 static __inline__ u16 ReadWord( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
116 if( *pp_current > pi_buffer + DVD_LB_SIZE - 2 )
118 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
121 i_ret = U16_AT(*pp_current);
127 static __inline__ u32 ReadDouble( ifo_t * p_ifo, u8* pi_buffer,
132 if( *pp_current > pi_buffer + DVD_LB_SIZE - 4 )
134 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE);
135 // intf_WarnMsg( 1, "new buffer in double @ %lld", p_ifo->i_pos );
138 i_ret = U32_AT(*pp_current);
144 static __inline__ u64 ReadQuad( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
148 if( *pp_current > pi_buffer + DVD_LB_SIZE - 8 )
150 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
153 i_ret = U64_AT(*pp_current);
159 static __inline__ void ReadBits( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current,
160 u8* pi_dest, int i_nb )
162 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
164 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
167 memcpy( pi_dest, *pp_current, i_nb );
173 static __inline__ void DumpBits( ifo_t* p_ifo, u8* pi_buffer,
174 u8** pp_current, int i_nb )
176 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
178 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
189 /*****************************************************************************
190 * IfoCreate : Creates an ifo structure and prepares for parsing directly
192 *****************************************************************************/
193 int IfoCreate( thread_dvd_data_t * p_dvd )
195 p_dvd->p_ifo = malloc( sizeof(ifo_t) );
196 if( p_dvd->p_ifo == NULL )
198 intf_ErrMsg( "ifo error: unable to allocate memory. aborting" );
202 /* if we are here the dvd device has already been opened */
203 p_dvd->p_ifo->i_fd = p_dvd->i_fd;
208 /*****************************************************************************
209 * IfoInit : Reads information from the management table.
210 *****************************************************************************/
211 int IfoInit( ifo_t * p_ifo )
213 u8 pi_buffer[DVD_LB_SIZE];
220 /* find the start sector of video information on the dvd */
221 i_lba = UDFFindFile( p_ifo->i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
223 p_ifo->i_off = (off_t)(i_lba) * DVD_LB_SIZE;
225 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off );
226 //i_start = p_ifo->i_pos;
228 * read the video manager information table
230 #define manager_inf p_ifo->vmg.manager_inf
231 //fprintf( stderr, "VMGI\n" );
233 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id, 12 );
234 manager_inf.psz_id[12] = '\0';
235 manager_inf.i_vmg_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
236 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
237 manager_inf.i_vmg_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
238 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
239 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
240 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
241 manager_inf.i_volume_nb = ReadWord( p_ifo, pi_buffer, &p_current );
242 manager_inf.i_volume = ReadWord( p_ifo, pi_buffer, &p_current );
243 manager_inf.i_disc_side = ReadByte( p_ifo, pi_buffer, &p_current );
244 DumpBits( p_ifo, pi_buffer, &p_current, 19 );
245 manager_inf.i_title_set_nb = ReadWord( p_ifo, pi_buffer, &p_current );
246 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.ps_provider_id, 32 );
247 manager_inf.i_pos_code = ReadQuad( p_ifo, pi_buffer, &p_current );
248 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
249 manager_inf.i_vmg_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
250 manager_inf.i_first_play_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
251 DumpBits( p_ifo, pi_buffer, &p_current, 56 );
252 manager_inf.i_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
253 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
254 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
255 manager_inf.i_parental_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
256 manager_inf.i_vts_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
257 manager_inf.i_text_data_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
258 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
259 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
260 DumpBits( p_ifo, pi_buffer, &p_current, 32 );
261 // GETS( &manager_inf.video_atrt );
262 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
263 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
264 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
265 //fprintf( stderr, "vmgi audio nb : %d\n", manager_inf.i_audio_nb );
266 for( i=0 ; i < 8 ; i++ )
268 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
270 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
271 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
272 //fprintf( stderr, "vmgi subpic nb : %d\n", manager_inf.i_spu_nb );
273 for( i=0 ; i < manager_inf.i_spu_nb ; i++ )
275 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
276 /* FIXME : take care of endianness */
280 * read first play title.
282 if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_off +
283 manager_inf.i_first_play_title_start_byte ) < 0 )
289 * fills the title information structure.
291 #define title_inf p_ifo->vmg.title_inf
292 if( manager_inf.i_title_inf_start_sector )
294 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
295 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
296 //fprintf( stderr, "title inf %lld\n", p_ifo->i_pos );
298 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
299 //fprintf( stderr, "title_inf: TTU nb %d\n", title_inf.i_title_nb );
300 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
301 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
303 /* parsing of title attributes */
304 title_inf.p_attr = malloc( title_inf.i_title_nb *sizeof(title_attr_t) );
305 if( title_inf.p_attr == NULL )
307 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
311 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
313 title_inf.p_attr[i].i_play_type = ReadByte( p_ifo, pi_buffer, &p_current );
314 title_inf.p_attr[i].i_angle_nb = ReadByte( p_ifo, pi_buffer, &p_current );
315 title_inf.p_attr[i].i_chapter_nb = ReadWord( p_ifo, pi_buffer, &p_current );
316 title_inf.p_attr[i].i_parental_id = ReadWord( p_ifo, pi_buffer, &p_current );
317 title_inf.p_attr[i].i_title_set_num = ReadByte( p_ifo, pi_buffer, &p_current );
318 title_inf.p_attr[i].i_title_num = ReadByte( p_ifo, pi_buffer, &p_current );
319 title_inf.p_attr[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
320 //fprintf( stderr, "title_inf: %d %d %d\n",title_inf.p_attr[i].i_chapter_nb ,title_inf.p_attr[i].i_title_set_num,title_inf.p_attr[i].i_title_num );
325 title_inf.p_attr = NULL;
330 * fills the title unit structure.
332 if( manager_inf.i_title_unit_start_sector )
334 if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_off +
335 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
342 * fills the structure about parental information.
344 #define parental p_ifo->vmg.parental_inf
345 if( manager_inf.i_parental_inf_start_sector )
347 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
348 manager_inf.i_parental_inf_start_sector *DVD_LB_SIZE );
349 i_start = p_ifo->i_pos;
351 //fprintf( stderr, "PTL\n" );
353 parental.i_country_nb = ReadWord( p_ifo, pi_buffer, &p_current );
354 parental.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );
355 parental.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
357 parental.p_parental_desc = malloc( parental.i_country_nb *
358 sizeof(parental_desc_t) );
359 if( parental.p_parental_desc == NULL )
361 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
365 for( i = 0 ; i < parental.i_country_nb ; i++ )
367 ReadBits( p_ifo, pi_buffer, &p_current,
368 parental.p_parental_desc[i].ps_country_code, 2 );
369 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
370 parental.p_parental_desc[i].i_parental_mask_start_byte =
371 ReadWord( p_ifo, pi_buffer, &p_current );
372 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
375 parental.p_parental_mask = malloc( parental.i_country_nb *
376 sizeof(parental_mask_t) );
377 if( parental.p_parental_mask == NULL )
379 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
383 for( i = 0 ; i < parental.i_country_nb ; i++ )
385 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
386 parental.p_parental_desc[i].i_parental_mask_start_byte );
387 for( j = 0 ; j < 8 ; j++ )
389 parental.p_parental_mask[i].ppi_mask[j] =
390 malloc( ( parental.i_vts_nb + 1 ) *sizeof(u16) );
391 if( parental.p_parental_mask[i].ppi_mask[j] == NULL )
393 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
396 for( k = 0 ; k < parental.i_vts_nb + 1 ; k++ )
398 parental.p_parental_mask[i].ppi_mask[j][k] =
399 ReadWord( p_ifo, pi_buffer, &p_current );
407 * information and attributes about for each vts.
409 #define vts_inf p_ifo->vmg.vts_inf
410 if( manager_inf.i_vts_inf_start_sector )
414 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
415 manager_inf.i_vts_inf_start_sector *DVD_LB_SIZE );
416 i_start = p_ifo->i_pos;
418 //fprintf( stderr, "VTS ATTR\n" );
420 vts_inf.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
421 //fprintf( stderr, "VTS ATTR Nb: %d\n", vts_inf.i_vts_nb );
422 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
423 vts_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
424 vts_inf.pi_vts_attr_start_byte =
425 malloc( vts_inf.i_vts_nb *sizeof(u32) );
426 if( vts_inf.pi_vts_attr_start_byte == NULL )
428 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
432 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
434 vts_inf.pi_vts_attr_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
437 vts_inf.p_vts_attr = malloc( vts_inf.i_vts_nb *sizeof(vts_attr_t) );
438 if( vts_inf.p_vts_attr == NULL )
440 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
444 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
446 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
447 vts_inf.pi_vts_attr_start_byte[i] );
448 vts_inf.p_vts_attr[i].i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
449 vts_inf.p_vts_attr[i].i_cat_app_type = ReadDouble( p_ifo, pi_buffer, &p_current );
450 // GETS( &vts_inf.p_vts_attr[i].vts_menu_video_attr );
451 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
452 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
453 vts_inf.p_vts_attr[i].i_vts_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
454 //fprintf( stderr, "m audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_audio_nb );
455 for( j = 0 ; j < 8 ; j++ )
457 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
459 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
460 vts_inf.p_vts_attr[i].i_vts_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
461 //fprintf( stderr, "m subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_spu_nb );
462 for( j = 0 ; j < 28 ; j++ )
464 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
465 /* FIXME : Fix endianness issue here */
467 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
468 // GETS( &vts_inf.p_vts_attr[i].vtstt_video_vts_inf );
469 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
470 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
471 vts_inf.p_vts_attr[i].i_vts_title_audio_nb =
472 ReadDouble( p_ifo, pi_buffer, &p_current );
473 //fprintf( stderr, "tt audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_audio_nb );
474 for( j = 0 ; j < 8 ; j++ )
476 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
478 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
479 vts_inf.p_vts_attr[i].i_vts_title_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
480 //fprintf( stderr, "tt subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_spu_nb );
481 for( j=0 ; j<28/*vts_inf.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
483 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
484 /* FIXME : Fix endianness issue here */
493 if( manager_inf.i_cell_inf_start_sector )
495 if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_off +
496 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
503 * global vob unit map.
505 if( manager_inf.i_vobu_map_start_sector )
507 if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_off +
508 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
515 p_ifo->vts.b_initialized = 0;
517 intf_WarnMsg( 2, "ifo info: vmg initialized" );
522 /*****************************************************************************
523 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
524 *****************************************************************************/
525 int IfoTitleSet( ifo_t * p_ifo )
527 u8 pi_buffer[DVD_LB_SIZE];
535 if( p_ifo->vts.b_initialized )
537 FreeTitleSet( &p_ifo->vts );
541 (off_t)( p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_start_sector )
545 //fprintf(stderr, "offset: %lld\n" , i_off );
547 p_current = FillBuffer( p_ifo, pi_buffer, i_off );
548 //i_start = p_ifo->i_pos;
549 p_ifo->vts.i_pos = p_ifo->i_pos;
551 #define manager_inf p_ifo->vts.manager_inf
553 * reads manager information
555 //fprintf( stderr, "VTSI\n" );
557 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id , 12 );
558 manager_inf.psz_id[12] = '\0';
559 manager_inf.i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
560 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
561 manager_inf.i_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
562 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
563 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
564 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
565 DumpBits( p_ifo, pi_buffer, &p_current, 90 );
566 manager_inf.i_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
567 DumpBits( p_ifo, pi_buffer, &p_current, 60 );
568 manager_inf.i_menu_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
569 manager_inf.i_title_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
570 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
571 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
572 manager_inf.i_menu_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
573 manager_inf.i_time_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
574 manager_inf.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
575 manager_inf.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
576 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
577 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
578 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
579 // GETS( &manager_inf.m_video_atrt );
580 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
581 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
582 manager_inf.i_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
583 for( i = 0 ; i < 8 ; i++ )
585 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
587 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
588 manager_inf.i_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
589 for( i = 0 ; i < 28 ; i++ )
591 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
592 /* FIXME : take care of endianness */
594 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
596 i_short = ReadWord( p_ifo, pi_buffer, &p_current );
598 manager_inf.video_attr.i_mode = i_short & 0x1;
600 manager_inf.video_attr.i_letterboxed = i_short & 0x1;
602 manager_inf.video_attr.i_source_res = i_short & 0x3;
604 manager_inf.video_attr.i_line21_2 = i_short & 0x1;
606 manager_inf.video_attr.i_line21_1 = i_short & 0x1;
608 manager_inf.video_attr.i_perm_displ = i_short & 0x3;
610 manager_inf.video_attr.i_ratio = i_short & 0x3;
612 manager_inf.video_attr.i_system = i_short & 0x3;
614 manager_inf.video_attr.i_compression = i_short & 0x3;
616 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
617 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
618 //fprintf( stderr, "vtsi audio nb : %d\n", manager_inf.i_audio_nb );
619 for( i = 0 ; i < 8 ; i++ )
621 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
622 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
624 manager_inf.p_audio_attr[i].i_bar = i_temp & 0xff;
626 manager_inf.p_audio_attr[i].i_caption = i_temp & 0xff;
628 manager_inf.p_audio_attr[i].i_foo = i_temp & 0xff;
630 manager_inf.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
632 manager_inf.p_audio_attr[i].i_num_channels = i_temp & 0x7;
634 manager_inf.p_audio_attr[i].i_test = i_temp & 0x1;
636 manager_inf.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
638 manager_inf.p_audio_attr[i].i_quantization = i_temp & 0x3;
640 manager_inf.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
642 manager_inf.p_audio_attr[i].i_type = i_temp & 0x3;
644 manager_inf.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
646 manager_inf.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
648 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
649 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
650 //fprintf( stderr, "vtsi subpic nb : %d\n", manager_inf.i_spu_nb );
651 for( i=0 ; i<manager_inf.i_spu_nb ; i++ )
653 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
654 i_temp = hton64( i_temp ) >> 16;
655 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
656 manager_inf.p_spu_attr[i].i_caption = i_temp & 0xff;
658 manager_inf.p_spu_attr[i].i_foo = i_temp & 0xff;
660 manager_inf.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
662 manager_inf.p_spu_attr[i].i_prefix = i_temp & 0xffff;
666 * reads title information: set of pointers to title
668 #define title_inf p_ifo->vts.title_inf
669 if( manager_inf.i_title_inf_start_sector )
671 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
672 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
674 i_start = p_ifo->i_pos;
676 //fprintf( stderr, "VTS PTR\n" );
678 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
679 //fprintf( stderr, "VTS title_inf nb: %d\n", title_inf.i_title_nb );
680 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
681 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
683 title_inf.pi_start_byte = malloc( title_inf.i_title_nb *sizeof(u32) );
684 if( title_inf.pi_start_byte == NULL )
686 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
690 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
692 title_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
696 title_inf.p_title_start = malloc( title_inf.i_title_nb
697 *sizeof(title_start_t) );
698 if( title_inf.p_title_start == NULL )
700 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
704 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
706 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
707 title_inf.pi_start_byte[i] );
709 title_inf.p_title_start[i].i_title_id =
710 ReadWord( p_ifo, pi_buffer, &p_current );
711 title_inf.p_title_start[i].i_chapter = ReadWord( p_ifo, pi_buffer, &p_current );
712 //fprintf( stderr, "VTS %d title_inf Pgc: %d Prg: %d\n", i,title_inf.p_title_start[i].i_program_chain_num, title_inf.p_title_start[i].i_program_num );
718 * menu unit information
720 if( manager_inf.i_menu_unit_start_sector )
722 if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
723 manager_inf.i_menu_unit_start_sector *DVD_LB_SIZE ) < 0 )
730 * title unit information
732 if( manager_inf.i_title_unit_start_sector )
734 if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
735 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
742 * time map inforamtion
744 #define time_inf p_ifo->vts.time_inf
745 if( manager_inf.i_time_inf_start_sector )
747 u8 pi_buffer[DVD_LB_SIZE];
749 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
750 manager_inf.i_time_inf_start_sector *DVD_LB_SIZE );
752 //fprintf( stderr, "TMAP\n" );
754 time_inf.i_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
755 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
756 time_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
758 time_inf.pi_start_byte = malloc( time_inf.i_nb *sizeof(u32) );
759 if( time_inf.pi_start_byte == NULL )
761 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
765 for( i = 0 ; i < time_inf.i_nb ; i++ )
767 time_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
770 time_inf.p_time_map = malloc( time_inf.i_nb *sizeof(time_map_t) );
771 if( time_inf.p_time_map == NULL )
773 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
777 for( i = 0 ; i < time_inf.i_nb ; i++ )
779 time_inf.p_time_map[i].i_time_unit = ReadByte( p_ifo, pi_buffer, &p_current );
780 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
781 time_inf.p_time_map[i].i_entry_nb = ReadWord( p_ifo, pi_buffer, &p_current );
783 time_inf.p_time_map[i].pi_sector =
784 malloc( time_inf.p_time_map[i].i_entry_nb *sizeof(u32) );
785 if( time_inf.p_time_map[i].pi_sector == NULL )
787 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
791 for( j = 0 ; j < time_inf.p_time_map[i].i_entry_nb ; j++ )
793 time_inf.p_time_map[i].pi_sector[j] = ReadDouble( p_ifo, pi_buffer, &p_current );
799 if( manager_inf.i_menu_cell_inf_start_sector )
801 if( ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
802 manager_inf.i_menu_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
808 if( manager_inf.i_menu_vobu_map_start_sector )
810 if( ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
811 manager_inf.i_menu_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
817 if( manager_inf.i_cell_inf_start_sector )
819 if( ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
820 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) )
826 if( manager_inf.i_vobu_map_start_sector )
828 if( ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
829 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) )
836 intf_WarnMsg( 2, "ifo info: vts %d initialized",
837 p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_title_set_num );
839 p_ifo->vts.b_initialized = 1;
844 /*****************************************************************************
845 * FreeTitleSet : free all structures allocated by IfoTitleSet
846 *****************************************************************************/
847 static int FreeTitleSet( vts_t * p_vts )
851 if( p_vts->manager_inf.i_vobu_map_start_sector )
853 FreeVobuMap( &p_vts->vobu_map );
856 if( p_vts->manager_inf.i_cell_inf_start_sector )
858 FreeCellInf( &p_vts->cell_inf );
861 if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
863 FreeVobuMap( &p_vts->menu_vobu_map );
866 if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
868 FreeCellInf( &p_vts->menu_cell_inf );
871 if( p_vts->manager_inf.i_time_inf_start_sector )
873 for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
875 free( p_vts->time_inf.p_time_map[i].pi_sector );
878 free( p_vts->time_inf.p_time_map );
879 free( p_vts->time_inf.pi_start_byte );
882 if( p_vts->manager_inf.i_title_unit_start_sector )
884 FreeUnitInf( &p_vts->title_unit );
887 if( p_vts->manager_inf.i_menu_unit_start_sector )
889 FreeTitleUnit( &p_vts->menu_unit );
892 if( p_vts->manager_inf.i_title_inf_start_sector )
894 free( p_vts->title_inf.pi_start_byte );
895 free( p_vts->title_inf.p_title_start );
898 p_vts->b_initialized = 0;
903 /*****************************************************************************
904 * IfoDestroy : Frees all the memory allocated to ifo structures
905 *****************************************************************************/
906 void IfoDestroy( ifo_t * p_ifo )
910 FreeTitleSet( &p_ifo->vts );
912 if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
914 FreeVobuMap( &p_ifo->vmg.vobu_map );
917 if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
919 FreeCellInf( &p_ifo->vmg.cell_inf );
922 if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
924 free( p_ifo->vmg.vts_inf.p_vts_attr );
925 free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
928 /* free parental information structures */
929 if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
931 for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
933 for( j = 0 ; j < 8 ; j++ )
935 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
939 free( p_ifo->vmg.parental_inf.p_parental_mask );
940 free( p_ifo->vmg.parental_inf.p_parental_desc );
943 if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
945 FreeTitleUnit( &p_ifo->vmg.title_unit );
948 if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
950 free( p_ifo->vmg.title_inf.p_attr );
953 FreeTitle( &p_ifo->vmg.title );
960 * Function common to Video Manager and Video Title set Processing
963 /*****************************************************************************
964 * ReadTitle : Fills the title structure.
965 *****************************************************************************
966 * Titles are logical stream units that correspond to a whole inside the dvd.
967 * Several title can point to the same part of the physical DVD, and give
968 * map to different anglesfor instance.
969 *****************************************************************************/
970 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, off_t i_pos )
972 u8 pi_buffer[DVD_LB_SIZE];
979 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
981 i_start = p_ifo->i_pos;
983 //fprintf( stderr, "PGC @ %lld\n",p_ifo->i_pos );
985 DumpBits( p_ifo, pi_buffer, &p_current, 2);
986 p_title->i_chapter_nb = ReadByte( p_ifo, pi_buffer, &p_current );
987 p_title->i_cell_nb = ReadByte( p_ifo, pi_buffer, &p_current );
988 //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb );
989 p_title->i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
990 p_title->i_prohibited_user_op = ReadDouble( p_ifo, pi_buffer, &p_current );
991 for( i = 0 ; i < 8 ; i++ )
993 i_audio = ReadWord( p_ifo, pi_buffer, &p_current );
994 p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
996 p_title->pi_audio_status[i].i_position = i_audio & 0x07;
998 p_title->pi_audio_status[i].i_available = i_audio;
1000 for( i = 0 ; i < 32 ; i++ )
1002 i_spu = ReadDouble( p_ifo, pi_buffer, &p_current );
1003 p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
1005 p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
1007 p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
1009 p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
1011 p_title->pi_spu_status[i].i_available = i_spu;
1013 p_title->i_next_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1014 p_title->i_prev_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1015 p_title->i_go_up_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1016 //fprintf( stderr, "title: Prev: %d Next: %d Up: %d\n",pgc.i_prev_pgc_nb ,pgc.i_next_pgc_nb, pgc.i_goup_pgc_nb );
1017 p_title->i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1018 p_title->i_play_mode = ReadByte( p_ifo, pi_buffer, &p_current );
1019 for( i = 0 ; i < 16 ; i++ )
1021 p_title->pi_yuv_color[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1022 /* FIXME : We have to erase the extra bit */
1024 p_title->i_command_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1025 p_title->i_chapter_map_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1026 p_title->i_cell_play_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1027 p_title->i_cell_pos_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1029 /* parsing of command_t */
1030 if( p_title->i_command_start_byte )
1032 p_current = FillBuffer( p_ifo, pi_buffer,
1033 i_start + p_title->i_command_start_byte );
1036 p_title->command.i_pre_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1037 p_title->command.i_post_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1038 p_title->command.i_cell_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1039 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1041 /* pre-title commands */
1042 if( p_title->command.i_pre_command_nb )
1044 p_title->command.p_pre_command =
1045 malloc( p_title->command.i_pre_command_nb
1046 *sizeof(command_desc_t) );
1048 if( p_title->command.p_pre_command == NULL )
1050 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1054 for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
1056 p_title->command.p_pre_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1061 p_title->command.p_pre_command = NULL;
1064 /* post-title commands */
1065 if( p_title->command.i_post_command_nb )
1067 p_title->command.p_post_command =
1068 malloc( p_title->command.i_post_command_nb
1069 *sizeof(command_desc_t) );
1071 if( p_title->command.p_post_command == NULL )
1073 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1077 for( i=0 ; i<p_title->command.i_post_command_nb ; i++ )
1079 p_title->command.p_post_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1084 p_title->command.p_post_command = NULL;
1088 if( p_title->command.i_cell_command_nb )
1090 p_title->command.p_cell_command =
1091 malloc( p_title->command.i_cell_command_nb
1092 *sizeof(command_desc_t) );
1094 if( p_title->command.p_cell_command == NULL )
1096 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1100 for( i=0 ; i<p_title->command.i_cell_command_nb ; i++ )
1102 p_title->command.p_cell_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1107 p_title->command.p_cell_command = NULL;
1111 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1112 if( p_title->i_chapter_map_start_byte )
1114 #if !defined( WIN32 )
1115 p_ifo->i_pos = lseek( p_ifo->i_fd,
1116 i_start + p_title->i_chapter_map_start_byte,
1119 p_ifo->i_pos = SetFilePointer( (HANDLE) p_ifo->i_fd,
1120 i_start + p_title->i_chapter_map_start_byte,
1124 p_title->chapter_map.pi_start_cell =
1125 malloc( p_title->i_chapter_nb *sizeof(chapter_map_t) );
1127 if( p_title->chapter_map.pi_start_cell == NULL )
1129 intf_ErrMsg( "ifo error: out of memory in Read Title" );
1133 ReadBits( p_ifo, pi_buffer, &p_current, p_title->chapter_map.pi_start_cell,
1134 p_title->i_chapter_nb );
1138 p_title->chapter_map.pi_start_cell = NULL;
1141 /* parsing of cell_play_t */
1142 if( p_title->i_cell_play_start_byte )
1144 p_current = FillBuffer( p_ifo, pi_buffer,
1145 i_start + p_title->i_cell_play_start_byte );
1147 p_title->p_cell_play = malloc( p_title->i_cell_nb
1148 *sizeof(cell_play_t) );
1150 if( p_title->p_cell_play == NULL )
1152 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1156 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1158 p_title->p_cell_play[i].i_category = ReadWord( p_ifo, pi_buffer, &p_current );
1159 p_title->p_cell_play[i].i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1160 p_title->p_cell_play[i].i_command_nb = ReadByte( p_ifo, pi_buffer, &p_current );
1161 p_title->p_cell_play[i].i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
1162 p_title->p_cell_play[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1163 p_title->p_cell_play[i].i_first_ilvu_vobu_esector =
1164 ReadDouble( p_ifo, pi_buffer, &p_current );
1165 p_title->p_cell_play[i].i_last_vobu_start_sector =
1166 ReadDouble( p_ifo, pi_buffer, &p_current );
1167 p_title->p_cell_play[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1171 /* Parsing of cell_pos_t */
1172 if( p_title->i_cell_pos_start_byte )
1174 p_current = FillBuffer( p_ifo, pi_buffer,
1175 i_start + p_title->i_cell_pos_start_byte );
1177 p_title->p_cell_pos = malloc( p_title->i_cell_nb
1178 *sizeof(cell_pos_t) );
1180 if( p_title->p_cell_pos == NULL )
1182 intf_ErrMsg( "ifo error: out of memory" );
1186 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1188 p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1189 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1190 p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1197 /*****************************************************************************
1198 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1199 *****************************************************************************/
1200 static int FreeTitle( title_t * p_title )
1202 if( p_title->i_command_start_byte )
1204 if( p_title->command.i_pre_command_nb )
1206 free( p_title->command.p_pre_command );
1209 if( p_title->command.i_post_command_nb )
1211 free( p_title->command.p_post_command );
1214 if( p_title->command.i_cell_command_nb )
1216 free( p_title->command.p_cell_command );
1219 if( p_title->i_chapter_map_start_byte )
1221 free( p_title->chapter_map.pi_start_cell );
1224 if( p_title->i_cell_play_start_byte )
1226 free( p_title->p_cell_play );
1229 if( p_title->i_cell_pos_start_byte )
1231 free( p_title->p_cell_pos );
1238 /*****************************************************************************
1239 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1240 *****************************************************************************/
1241 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf, off_t i_pos )
1243 u8 pi_buffer[DVD_LB_SIZE];
1248 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1250 i_start = p_ifo->i_pos;
1251 //fprintf( stderr, "Unit\n" );
1253 p_unit_inf->i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1254 //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb );
1255 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1256 p_unit_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1258 p_unit_inf->p_title =
1259 malloc( p_unit_inf->i_title_nb *sizeof(unit_title_t) );
1260 if( p_unit_inf->p_title == NULL )
1262 intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1266 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1268 p_unit_inf->p_title[i].i_category_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1269 p_unit_inf->p_title[i].i_category = ReadByte( p_ifo, pi_buffer, &p_current );
1270 //fprintf( stderr, "cat mask %d: %x cat %x\n", i, p_unit_inf->p_title[i].i_category_mask, p_unit_inf->p_title[i].i_category );
1271 p_unit_inf->p_title[i].i_parental_mask = ReadWord( p_ifo, pi_buffer, &p_current );
1272 p_unit_inf->p_title[i].i_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1275 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1277 //fprintf( stderr, "Unit: PGC %d @ %lld\n", i, p_ifo->i_pos );
1278 ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1279 p_unit_inf->p_title[i].i_title_start_byte );
1285 /*****************************************************************************
1286 * FreeUnitInf : frees a structure allocated by ReadUnit
1287 *****************************************************************************/
1288 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1290 if( p_unit_inf->p_title != NULL )
1292 free( p_unit_inf->p_title );
1299 /*****************************************************************************
1300 * ReadTitleUnit: Fills the Title Unit structure.
1301 *****************************************************************************/
1302 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1305 u8 pi_buffer[DVD_LB_SIZE];
1310 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1311 i_start = p_ifo->i_pos;
1312 //fprintf( stderr, "Unit Table\n" );
1314 p_title_unit->i_unit_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1315 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1316 p_title_unit->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1318 //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1320 p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb *sizeof(unit_t) );
1321 if( p_title_unit->p_unit == NULL )
1323 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1327 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1329 //ReadBits( p_ifo, pi_buffer, &p_current, p_title_unit->p_unit[i].ps_lang_code, 2 );
1330 p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, pi_buffer, &p_current );
1331 //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code );
1332 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1333 p_title_unit->p_unit[i].i_existence_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1334 p_title_unit->p_unit[i].i_unit_inf_start_byte =
1335 ReadDouble( p_ifo, pi_buffer, &p_current );
1338 p_title_unit->p_unit_inf =
1339 malloc( p_title_unit->i_unit_nb *sizeof(unit_inf_t) );
1340 if( p_title_unit->p_unit_inf == NULL )
1342 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1346 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1348 ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1349 p_title_unit->p_unit[i].i_unit_inf_start_byte );
1355 /*****************************************************************************
1356 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1357 *****************************************************************************/
1358 static int FreeTitleUnit( title_unit_t * p_title_unit )
1362 if( p_title_unit->p_unit_inf != NULL )
1364 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1366 FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1369 free( p_title_unit->p_unit_inf );
1375 /*****************************************************************************
1376 * ReadCellInf : Fills the Cell Information structure.
1377 *****************************************************************************/
1378 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, off_t i_pos )
1380 u8 pi_buffer[DVD_LB_SIZE];
1385 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1386 i_start = p_ifo->i_pos;
1387 //fprintf( stderr, "CELL ADD\n" );
1389 p_cell_inf->i_vob_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1390 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1391 p_cell_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1393 p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t);
1395 //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 );
1397 p_cell_inf->p_cell_map =
1398 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1399 if( p_cell_inf->p_cell_map == NULL )
1401 intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1405 for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1407 p_cell_inf->p_cell_map[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1408 p_cell_inf->p_cell_map[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1409 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1410 p_cell_inf->p_cell_map[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1411 // fprintf(stderr, "sector[%d] %d (%lld)\n", i,ntohl(*(u32*)(p_current)), p_ifo->i_pos);
1412 p_cell_inf->p_cell_map[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1418 /*****************************************************************************
1419 * FreeCellInf : frees structures allocated by ReadCellInf
1420 *****************************************************************************/
1421 static int FreeCellInf( cell_inf_t * p_cell_inf )
1423 free( p_cell_inf->p_cell_map );
1428 /*****************************************************************************
1429 * ReadVobuMap : Fills the VOBU Map structure.
1430 *****************************************************************************/
1431 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, off_t i_pos )
1433 u8 pi_buffer[DVD_LB_SIZE];
1438 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1439 i_start = p_ifo->i_pos;
1440 //fprintf( stderr, "VOBU ADMAP\n" );
1442 p_vobu_map->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1443 i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos )
1446 p_vobu_map->pi_vobu_start_sector = malloc( i_max *sizeof(u32) );
1447 if( p_vobu_map->pi_vobu_start_sector == NULL )
1449 intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1453 for( i = 0 ; i < i_max ; i++ )
1455 p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1461 /*****************************************************************************
1462 * FreeVobuMap: frees structures allocated by ReadVobuMap
1463 *****************************************************************************/
1464 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1466 free( p_vobu_map->pi_vobu_start_sector );
1472 * IFO virtual machine : a set of commands that give the
1473 * interactive behaviour of the dvd
1477 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1478 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1480 static char ifo_reg[][80]=
1482 "Menu_Language_Code",
1484 "SubPicture_Stream_#",
1490 "Highlighted_Button_#",
1493 "Karaoke_audio_mixing_mode",
1494 "Parental_mgmt_country_code",
1498 "Audio_language_code_setting",
1499 "Audio_language_extension_code",
1500 "SPU_language_code_setting",
1501 "SPU_language_extension_code",
1502 "?Player_Regional_Code",
1508 static char * IfoMath( char val )
1510 static char math_op[][10] =
1530 return (char *) math_op[val & 0x0f];
1534 char ifo_cmp[][10] =
1546 char ifo_parental[][10] =
1558 char ifo_menu_id[][80] =
1570 char * IfoMenuName( char index )
1572 return ifo_menu_id[index&0x07];
1575 static void IfoRegister( u16 i_data, u8 i_direct)
1579 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1581 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1585 printf("0x%02x", i_data);
1600 printf("s[%s]", ifo_reg[i_data]);
1613 printf("r[0x%02x]", i_data);
1619 static void IfoAdvanced( u8 *pi_code )
1621 u8 i_cmd = pi_code[0];
1627 printf( " Highlight button %d; ", pi_code[1]>>2 );
1632 printf( " Illegal " );
1637 printf( "ReSuME %d", pi_code[7] );
1639 else if( ( i_cmd & 0x06) == 0x02 )
1641 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1645 printf( "advanced (0x%02x) ", i_cmd );
1650 static void IfoJmp( ifo_command_t com )
1655 switch( com.i_sub_cmd )
1661 printf( "VTS 0x%02x", OP_VAL_8(3) );
1664 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1667 printf( "This VTS Title 0x%02x Part 0x%04x",
1669 OP_VAL_8(0)<<8|OP_VAL_8(1));
1673 printf ("in SystemSpace ");
1674 switch (OP_VAL_8(3)>>4) {
1676 printf ("to play first PGC");
1679 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1683 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1686 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1689 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1692 switch( OP_VAL_8(3)>>6 )
1695 printf( "to play first PGC" );
1698 printf( "to VMG title menu (?)" );
1701 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1704 IfoMenuName( OP_VAL_8(3)&0xF ) );
1707 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1714 switch(OP_VAL_8(3)>>4) {
1716 printf ("system first pgc");
1719 printf ("system title menu");
1722 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1725 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1728 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1731 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1735 // OP_VAL_8(2) is number of cell
1736 // it is processed BEFORE switch
1737 // under some conditions, it is ignored
1738 // I don't understand exactly what it means
1739 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1741 switch( OP_VAL_8(3)>>6 )
1744 printf( "to FP PGC" );
1747 printf( "to VMG root menu (?)" );
1750 printf( "to VTS menu \"%s\" (?)",
1751 IfoMenuName(OP_VAL_8(3)&0xF) );
1754 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1762 static void IfoLnk( ifo_command_t com )
1764 u16 i_button=OP_VAL_8(4)>>2;
1768 switch( com.i_sub_cmd )
1771 IfoAdvanced( &OP_VAL_8(4) );
1775 printf( "PGC 0x%02x", OP_VAL_16(2) );
1779 printf( "PTT 0x%02x", OP_VAL_16(2) );
1783 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1787 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1795 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1800 void IfoSetSystem( ifo_command_t com )
1807 for( i=1; i<=3; i++ )
1809 if( OP_VAL_8(i)&0x80 )
1813 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1817 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1823 if(OP_VAL_8(1]&0x80)
1824 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1825 if(OP_VAL_8(2)&0x80)
1826 //DENT: lwhat about 0x7f here ???
1827 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1828 if(OP_VAL_8(3)&0x80)
1829 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1831 if(OP_VAL_8(1)&0x80)
1832 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1833 if(OP_VAL_8(2)&0x80)
1834 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1835 if(OP_VAL_8(3)&0x80)
1836 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1844 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1848 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1851 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1852 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1857 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1861 printf ("r[r[0x%02x]] = r[0x%02x]",
1862 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1866 //actually only bits 00011100 00011100 are set
1869 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1873 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1878 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1879 //but it is way too ugly
1882 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1886 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1894 static void IfoSet( ifo_command_t com )
1896 IfoRegister( OP_VAL_16(0), 0 );
1897 printf( " %s ", IfoMath( com.i_cmd ) );
1898 IfoRegister( OP_VAL_16(1), com.i_direct );
1901 /*****************************************************************************
1902 * CommandRead : translates the command strings in ifo into command
1904 *****************************************************************************/
1905 void CommandRead( ifo_command_t com )
1907 u8* pi_code = (u8*)(&com);
1909 switch( com.i_type )
1922 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1923 ifo_cmp[com.i_cmp]);
1924 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1929 switch( com.i_sub_cmd )
1932 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1936 printf( "stop VM" );
1940 printf( "Set Parental Level To %s and goto Line 0x%02x",
1941 ifo_parental[OP_VAL_8(4)&0x7],
1946 printf( "Illegal" );
1965 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1966 ifo_cmp[com.i_cmp] );
1967 IfoRegister( OP_VAL_8(5), 0 );
1978 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1979 ifo_cmp[com.i_cmp] );
1980 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1994 IfoSetSystem( com );
1996 else if( com.i_cmp && !com.i_sub_cmd )
1998 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1999 IfoRegister( OP_VAL_8(5), 0 );
2001 IfoSetSystem( com );
2003 else if( !com.i_cmp && com.i_sub_cmd )
2006 IfoSetSystem( com );
2022 else if( com.i_cmp && !com.i_sub_cmd )
2024 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
2025 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
2029 else if( !com.i_cmp && com.i_sub_cmd )
2043 * math command on r[opcode[1]] and
2044 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
2045 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
2047 * boolean operation cmp on r[opcode[1]] and
2048 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
2049 * on true result, buttons(c[6], c[7]) is called
2050 * problem is 'what is buttons()'
2053 printf( "r[0x%X] ", pi_code[1] );
2054 printf( " %s ", IfoMath( com.i_cmd ) );
2055 if( com.i_cmd == 2 )
2057 printf( "r[0x%X] ", OP_VAL_8(1) );
2061 IfoRegister( OP_VAL_16(0), com.i_direct );
2065 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
2066 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
2067 printf( " ) then {" );
2068 IfoAdvanced( &OP_VAL_8(4) );
2073 * opposite to case 4: boolean, math and buttons.
2079 if( !com.i_direct && com.i_dir_cmp )
2081 printf( "0x%X", OP_VAL_16(1) );
2085 IfoRegister( OP_VAL_8(3), 0 );
2086 if( OP_VAL_8(3)&0x80 )
2088 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2092 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2093 // 0x1F is either not a mistake,
2094 // or Microsoft programmer's mistake!!!
2098 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2099 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2100 printf( " ) then {" );
2101 printf( "r[0x%X] ", pi_code[1] & 0xF );
2102 printf( " %s ", IfoMath( com.i_cmd ) );
2104 if( com.i_cmd == 0x02 ) // swap
2106 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2112 printf( "0x%X", OP_VAL_16(0) );
2116 if( OP_VAL_8(0) & 0x80 )
2118 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2122 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2128 IfoAdvanced( &OP_VAL_8(4) );
2134 printf( "Unknown Command\n" );
2141 /*****************************************************************************
2142 * CommandPrint : print in clear text (I hope so !) what a command does
2143 *****************************************************************************/
2144 void CommandPrint( ifo_t ifo )