1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.31 2001/06/07 15:27:44 sam Exp $
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * German Tischler <tanis@gaspode.franken.de>
11 * - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
12 * - IFO structure documentation by Thomas Mirlacher, Björn Englund,
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
28 *****************************************************************************/
30 /*****************************************************************************
32 *****************************************************************************/
41 #elif defined( _MSC_VER ) && defined( _WIN32 )
57 #include "input_dvd.h"
60 #include "modules_export.h"
62 /*****************************************************************************
64 *****************************************************************************/
65 void CommandRead ( command_desc_t );
66 static int ReadTitle ( ifo_t * , title_t *, off_t );
67 static int FreeTitle ( title_t * );
68 static int ReadUnitInf ( ifo_t * , unit_inf_t *, off_t );
69 static int FreeUnitInf ( unit_inf_t * );
70 static int ReadTitleUnit ( ifo_t * , title_unit_t *, off_t );
71 static int FreeTitleUnit ( title_unit_t * );
72 static int ReadVobuMap ( ifo_t * , vobu_map_t *, off_t );
73 static int FreeVobuMap ( vobu_map_t * );
74 static int ReadCellInf ( ifo_t * , cell_inf_t *, off_t );
75 static int FreeCellInf ( cell_inf_t * );
76 static int FreeTitleSet ( vts_t * );
78 /*****************************************************************************
80 *****************************************************************************/
81 static __inline__ u8* FillBuffer( ifo_t* p_ifo, u8* pi_buffer, off_t i_pos )
87 memset( pi_buffer, 0, DVD_LB_SIZE );
90 p_ifo->i_pos = SetFilePointer( (HANDLE) p_ifo->i_fd, i_pos,
92 ReadFile( (HANDLE) p_ifo->i_fd, pi_buffer, DVD_LB_SIZE, &tmp, NULL );
94 #elif defined(__FreeBSD__)
95 if ( i_pos & ( DVD_LB_SIZE - 1 ) )
97 off_t i_relpos = i_pos & ( DVD_LB_SIZE - 1 );
98 off_t i_newpos = i_pos & ~( DVD_LB_SIZE - 1 );
100 if ( lseek(p_ifo->i_fd, i_newpos, SEEK_SET) == -1 )
102 intf_WarnMsg( 2, "input warning: seek failure" );
107 if ( read(p_ifo->i_fd, p_ifo->p_remap, DVD_LB_SIZE) == -1 )
109 intf_WarnMsg( 2, "input warning: first chunk read failure" );
114 if ( lseek(p_ifo->i_fd, i_newpos + DVD_LB_SIZE, SEEK_SET) == -1 )
116 intf_WarnMsg( 2, "input warning: seek failure" );
121 if ( read(p_ifo->i_fd, (p_ifo->p_remap + DVD_LB_SIZE),
124 intf_WarnMsg( 2, "input warning: second chunk read failure" );
129 memcpy( pi_buffer, p_ifo->p_remap + i_relpos,
130 ( DVD_LB_SIZE - i_relpos ) );
132 memcpy( pi_buffer + ( DVD_LB_SIZE - i_relpos ),
133 ( p_ifo->p_remap + DVD_LB_SIZE ), i_relpos );
135 p_ifo->i_pos = i_pos;
139 p_ifo->i_pos = lseek( p_ifo->i_fd, i_pos, SEEK_SET );
140 read( p_ifo->i_fd, pi_buffer, DVD_LB_SIZE );
144 p_ifo->i_pos = lseek( p_ifo->i_fd, i_pos, SEEK_SET );
145 read( p_ifo->i_fd, pi_buffer, DVD_LB_SIZE );
152 static __inline__ u8 ReadByte( ifo_t * p_ifo, u8* pi_buffer, u8** pp_current )
156 if( *pp_current > pi_buffer + DVD_LB_SIZE )
158 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
161 i_ret = *(*pp_current)++;
166 static __inline__ u16 ReadWord( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
170 if( *pp_current > pi_buffer + DVD_LB_SIZE - 2 )
172 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
175 i_ret = U16_AT(*pp_current);
181 static __inline__ u32 ReadDouble( ifo_t * p_ifo, u8* pi_buffer,
186 if( *pp_current > pi_buffer + DVD_LB_SIZE - 4 )
188 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE);
189 // intf_WarnMsg( 1, "new buffer in double @ %lld", p_ifo->i_pos );
192 i_ret = U32_AT(*pp_current);
198 static __inline__ u64 ReadQuad( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
202 if( *pp_current > pi_buffer + DVD_LB_SIZE - 8 )
204 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
207 i_ret = U64_AT(*pp_current);
213 static __inline__ void ReadBits( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current,
214 u8* pi_dest, int i_nb )
216 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
218 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
221 memcpy( pi_dest, *pp_current, i_nb );
227 static __inline__ void DumpBits( ifo_t* p_ifo, u8* pi_buffer,
228 u8** pp_current, int i_nb )
230 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
232 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
243 /*****************************************************************************
244 * IfoCreate : Creates an ifo structure and prepares for parsing directly
246 *****************************************************************************/
247 int IfoCreate( thread_dvd_data_t * p_dvd )
249 p_dvd->p_ifo = malloc( sizeof(ifo_t) );
250 if( p_dvd->p_ifo == NULL )
252 intf_ErrMsg( "ifo error: unable to allocate memory. aborting" );
256 /* if we are here the dvd device has already been opened */
257 p_dvd->p_ifo->i_fd = p_dvd->i_fd;
262 /*****************************************************************************
263 * IfoInit : Reads information from the management table.
264 *****************************************************************************/
265 int IfoInit( ifo_t * p_ifo )
267 u8 pi_buffer[DVD_LB_SIZE];
274 /* find the start sector of video information on the dvd */
275 i_lba = UDFFindFile( p_ifo->i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
277 p_ifo->i_off = (off_t)(i_lba) * DVD_LB_SIZE;
279 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off );
280 //i_start = p_ifo->i_pos;
282 * read the video manager information table
284 #define manager_inf p_ifo->vmg.manager_inf
285 //fprintf( stderr, "VMGI\n" );
287 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id, 12 );
288 manager_inf.psz_id[12] = '\0';
289 manager_inf.i_vmg_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
290 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
291 manager_inf.i_vmg_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
292 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
293 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
294 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
295 manager_inf.i_volume_nb = ReadWord( p_ifo, pi_buffer, &p_current );
296 manager_inf.i_volume = ReadWord( p_ifo, pi_buffer, &p_current );
297 manager_inf.i_disc_side = ReadByte( p_ifo, pi_buffer, &p_current );
298 DumpBits( p_ifo, pi_buffer, &p_current, 19 );
299 manager_inf.i_title_set_nb = ReadWord( p_ifo, pi_buffer, &p_current );
300 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.ps_provider_id, 32 );
301 manager_inf.i_pos_code = ReadQuad( p_ifo, pi_buffer, &p_current );
302 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
303 manager_inf.i_vmg_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
304 manager_inf.i_first_play_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
305 DumpBits( p_ifo, pi_buffer, &p_current, 56 );
306 manager_inf.i_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
307 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
308 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
309 manager_inf.i_parental_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
310 manager_inf.i_vts_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
311 manager_inf.i_text_data_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
312 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
313 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
314 DumpBits( p_ifo, pi_buffer, &p_current, 32 );
315 // GETS( &manager_inf.video_atrt );
316 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
317 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
318 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
319 //fprintf( stderr, "vmgi audio nb : %d\n", manager_inf.i_audio_nb );
320 for( i=0 ; i < 8 ; i++ )
322 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
324 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
325 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
326 //fprintf( stderr, "vmgi subpic nb : %d\n", manager_inf.i_spu_nb );
327 for( i=0 ; i < manager_inf.i_spu_nb ; i++ )
329 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
330 /* FIXME : take care of endianness */
334 * read first play title.
336 if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_off +
337 manager_inf.i_first_play_title_start_byte ) < 0 )
343 * fills the title information structure.
345 #define title_inf p_ifo->vmg.title_inf
346 if( manager_inf.i_title_inf_start_sector )
348 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
349 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
350 //fprintf( stderr, "title inf %lld\n", p_ifo->i_pos );
352 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
353 //fprintf( stderr, "title_inf: TTU nb %d\n", title_inf.i_title_nb );
354 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
355 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
357 /* parsing of title attributes */
358 title_inf.p_attr = malloc( title_inf.i_title_nb *sizeof(title_attr_t) );
359 if( title_inf.p_attr == NULL )
361 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
365 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
367 title_inf.p_attr[i].i_play_type = ReadByte( p_ifo, pi_buffer, &p_current );
368 title_inf.p_attr[i].i_angle_nb = ReadByte( p_ifo, pi_buffer, &p_current );
369 title_inf.p_attr[i].i_chapter_nb = ReadWord( p_ifo, pi_buffer, &p_current );
370 title_inf.p_attr[i].i_parental_id = ReadWord( p_ifo, pi_buffer, &p_current );
371 title_inf.p_attr[i].i_title_set_num = ReadByte( p_ifo, pi_buffer, &p_current );
372 title_inf.p_attr[i].i_title_num = ReadByte( p_ifo, pi_buffer, &p_current );
373 title_inf.p_attr[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
374 //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 );
379 title_inf.p_attr = NULL;
384 * fills the title unit structure.
386 if( manager_inf.i_title_unit_start_sector )
388 if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_off +
389 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
396 * fills the structure about parental information.
398 #define parental p_ifo->vmg.parental_inf
399 if( manager_inf.i_parental_inf_start_sector )
401 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
402 manager_inf.i_parental_inf_start_sector *DVD_LB_SIZE );
403 i_start = p_ifo->i_pos;
405 //fprintf( stderr, "PTL\n" );
407 parental.i_country_nb = ReadWord( p_ifo, pi_buffer, &p_current );
408 parental.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );
409 parental.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
411 parental.p_parental_desc = malloc( parental.i_country_nb *
412 sizeof(parental_desc_t) );
413 if( parental.p_parental_desc == NULL )
415 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
419 for( i = 0 ; i < parental.i_country_nb ; i++ )
421 ReadBits( p_ifo, pi_buffer, &p_current,
422 parental.p_parental_desc[i].ps_country_code, 2 );
423 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
424 parental.p_parental_desc[i].i_parental_mask_start_byte =
425 ReadWord( p_ifo, pi_buffer, &p_current );
426 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
429 parental.p_parental_mask = malloc( parental.i_country_nb *
430 sizeof(parental_mask_t) );
431 if( parental.p_parental_mask == NULL )
433 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
437 for( i = 0 ; i < parental.i_country_nb ; i++ )
439 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
440 parental.p_parental_desc[i].i_parental_mask_start_byte );
441 for( j = 0 ; j < 8 ; j++ )
443 parental.p_parental_mask[i].ppi_mask[j] =
444 malloc( ( parental.i_vts_nb + 1 ) *sizeof(u16) );
445 if( parental.p_parental_mask[i].ppi_mask[j] == NULL )
447 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
450 for( k = 0 ; k < parental.i_vts_nb + 1 ; k++ )
452 parental.p_parental_mask[i].ppi_mask[j][k] =
453 ReadWord( p_ifo, pi_buffer, &p_current );
461 * information and attributes about for each vts.
463 #define vts_inf p_ifo->vmg.vts_inf
464 if( manager_inf.i_vts_inf_start_sector )
468 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
469 manager_inf.i_vts_inf_start_sector *DVD_LB_SIZE );
470 i_start = p_ifo->i_pos;
472 //fprintf( stderr, "VTS ATTR\n" );
474 vts_inf.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
475 //fprintf( stderr, "VTS ATTR Nb: %d\n", vts_inf.i_vts_nb );
476 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
477 vts_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
478 vts_inf.pi_vts_attr_start_byte =
479 malloc( vts_inf.i_vts_nb *sizeof(u32) );
480 if( vts_inf.pi_vts_attr_start_byte == NULL )
482 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
486 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
488 vts_inf.pi_vts_attr_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
491 vts_inf.p_vts_attr = malloc( vts_inf.i_vts_nb *sizeof(vts_attr_t) );
492 if( vts_inf.p_vts_attr == NULL )
494 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
498 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
500 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
501 vts_inf.pi_vts_attr_start_byte[i] );
502 vts_inf.p_vts_attr[i].i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
503 vts_inf.p_vts_attr[i].i_cat_app_type = ReadDouble( p_ifo, pi_buffer, &p_current );
504 // GETS( &vts_inf.p_vts_attr[i].vts_menu_video_attr );
505 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
506 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
507 vts_inf.p_vts_attr[i].i_vts_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
508 //fprintf( stderr, "m audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_audio_nb );
509 for( j = 0 ; j < 8 ; j++ )
511 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
513 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
514 vts_inf.p_vts_attr[i].i_vts_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
515 //fprintf( stderr, "m subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_spu_nb );
516 for( j = 0 ; j < 28 ; j++ )
518 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
519 /* FIXME : Fix endianness issue here */
521 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
522 // GETS( &vts_inf.p_vts_attr[i].vtstt_video_vts_inf );
523 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
524 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
525 vts_inf.p_vts_attr[i].i_vts_title_audio_nb =
526 ReadDouble( p_ifo, pi_buffer, &p_current );
527 //fprintf( stderr, "tt audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_audio_nb );
528 for( j = 0 ; j < 8 ; j++ )
530 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
532 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
533 vts_inf.p_vts_attr[i].i_vts_title_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
534 //fprintf( stderr, "tt subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_spu_nb );
535 for( j=0 ; j<28/*vts_inf.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
537 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
538 /* FIXME : Fix endianness issue here */
547 if( manager_inf.i_cell_inf_start_sector )
549 if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_off +
550 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
557 * global vob unit map.
559 if( manager_inf.i_vobu_map_start_sector )
561 if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_off +
562 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
569 p_ifo->vts.b_initialized = 0;
571 intf_WarnMsg( 2, "ifo info: vmg initialized" );
576 /*****************************************************************************
577 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
578 *****************************************************************************/
579 int IfoTitleSet( ifo_t * p_ifo )
581 u8 pi_buffer[DVD_LB_SIZE];
589 if( p_ifo->vts.b_initialized )
591 FreeTitleSet( &p_ifo->vts );
595 (off_t)( p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_start_sector )
599 //fprintf(stderr, "offset: %lld\n" , i_off );
601 p_current = FillBuffer( p_ifo, pi_buffer, i_off );
602 //i_start = p_ifo->i_pos;
603 p_ifo->vts.i_pos = p_ifo->i_pos;
605 #define manager_inf p_ifo->vts.manager_inf
607 * reads manager information
609 //fprintf( stderr, "VTSI\n" );
611 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id , 12 );
612 manager_inf.psz_id[12] = '\0';
613 manager_inf.i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
614 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
615 manager_inf.i_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
616 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
617 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
618 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
619 DumpBits( p_ifo, pi_buffer, &p_current, 90 );
620 manager_inf.i_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
621 DumpBits( p_ifo, pi_buffer, &p_current, 60 );
622 manager_inf.i_menu_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
623 manager_inf.i_title_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
624 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
625 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
626 manager_inf.i_menu_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
627 manager_inf.i_time_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
628 manager_inf.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
629 manager_inf.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
630 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
631 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
632 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
633 // GETS( &manager_inf.m_video_atrt );
634 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
635 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
636 manager_inf.i_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
637 for( i = 0 ; i < 8 ; i++ )
639 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
641 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
642 manager_inf.i_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
643 for( i = 0 ; i < 28 ; i++ )
645 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
646 /* FIXME : take care of endianness */
648 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
650 i_short = ReadWord( p_ifo, pi_buffer, &p_current );
652 manager_inf.video_attr.i_mode = i_short & 0x1;
654 manager_inf.video_attr.i_letterboxed = i_short & 0x1;
656 manager_inf.video_attr.i_source_res = i_short & 0x3;
658 manager_inf.video_attr.i_line21_2 = i_short & 0x1;
660 manager_inf.video_attr.i_line21_1 = i_short & 0x1;
662 manager_inf.video_attr.i_perm_displ = i_short & 0x3;
664 manager_inf.video_attr.i_ratio = i_short & 0x3;
666 manager_inf.video_attr.i_system = i_short & 0x3;
668 manager_inf.video_attr.i_compression = i_short & 0x3;
670 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
671 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
672 //fprintf( stderr, "vtsi audio nb : %d\n", manager_inf.i_audio_nb );
673 for( i = 0 ; i < 8 ; i++ )
675 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
676 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
678 manager_inf.p_audio_attr[i].i_bar = i_temp & 0xff;
680 manager_inf.p_audio_attr[i].i_caption = i_temp & 0xff;
682 manager_inf.p_audio_attr[i].i_foo = i_temp & 0xff;
684 manager_inf.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
686 manager_inf.p_audio_attr[i].i_num_channels = i_temp & 0x7;
688 manager_inf.p_audio_attr[i].i_test = i_temp & 0x1;
690 manager_inf.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
692 manager_inf.p_audio_attr[i].i_quantization = i_temp & 0x3;
694 manager_inf.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
696 manager_inf.p_audio_attr[i].i_type = i_temp & 0x3;
698 manager_inf.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
700 manager_inf.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
702 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
703 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
704 //fprintf( stderr, "vtsi subpic nb : %d\n", manager_inf.i_spu_nb );
705 for( i=0 ; i<manager_inf.i_spu_nb ; i++ )
707 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
708 i_temp = hton64( i_temp ) >> 16;
709 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
710 manager_inf.p_spu_attr[i].i_caption = i_temp & 0xff;
712 manager_inf.p_spu_attr[i].i_foo = i_temp & 0xff;
714 manager_inf.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
716 manager_inf.p_spu_attr[i].i_prefix = i_temp & 0xffff;
720 * reads title information: set of pointers to title
722 #define title_inf p_ifo->vts.title_inf
723 if( manager_inf.i_title_inf_start_sector )
725 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
726 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
728 i_start = p_ifo->i_pos;
730 //fprintf( stderr, "VTS PTR\n" );
732 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
733 //fprintf( stderr, "VTS title_inf nb: %d\n", title_inf.i_title_nb );
734 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
735 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
737 title_inf.pi_start_byte = malloc( title_inf.i_title_nb *sizeof(u32) );
738 if( title_inf.pi_start_byte == NULL )
740 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
744 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
746 title_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
750 title_inf.p_title_start = malloc( title_inf.i_title_nb
751 *sizeof(title_start_t) );
752 if( title_inf.p_title_start == NULL )
754 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
758 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
760 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
761 title_inf.pi_start_byte[i] );
763 title_inf.p_title_start[i].i_title_id =
764 ReadWord( p_ifo, pi_buffer, &p_current );
765 title_inf.p_title_start[i].i_chapter = ReadWord( p_ifo, pi_buffer, &p_current );
766 //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 );
772 * menu unit information
774 if( manager_inf.i_menu_unit_start_sector )
776 if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
777 manager_inf.i_menu_unit_start_sector *DVD_LB_SIZE ) < 0 )
784 * title unit information
786 if( manager_inf.i_title_unit_start_sector )
788 if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
789 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
796 * time map inforamtion
798 #define time_inf p_ifo->vts.time_inf
799 if( manager_inf.i_time_inf_start_sector )
801 u8 pi_buffer[DVD_LB_SIZE];
803 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
804 manager_inf.i_time_inf_start_sector *DVD_LB_SIZE );
806 //fprintf( stderr, "TMAP\n" );
808 time_inf.i_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
809 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
810 time_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
812 time_inf.pi_start_byte = malloc( time_inf.i_nb *sizeof(u32) );
813 if( time_inf.pi_start_byte == NULL )
815 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
819 for( i = 0 ; i < time_inf.i_nb ; i++ )
821 time_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
824 time_inf.p_time_map = malloc( time_inf.i_nb *sizeof(time_map_t) );
825 if( time_inf.p_time_map == NULL )
827 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
831 for( i = 0 ; i < time_inf.i_nb ; i++ )
833 time_inf.p_time_map[i].i_time_unit = ReadByte( p_ifo, pi_buffer, &p_current );
834 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
835 time_inf.p_time_map[i].i_entry_nb = ReadWord( p_ifo, pi_buffer, &p_current );
837 time_inf.p_time_map[i].pi_sector =
838 malloc( time_inf.p_time_map[i].i_entry_nb *sizeof(u32) );
839 if( time_inf.p_time_map[i].pi_sector == NULL )
841 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
845 for( j = 0 ; j < time_inf.p_time_map[i].i_entry_nb ; j++ )
847 time_inf.p_time_map[i].pi_sector[j] = ReadDouble( p_ifo, pi_buffer, &p_current );
853 if( manager_inf.i_menu_cell_inf_start_sector )
855 if( ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
856 manager_inf.i_menu_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
862 if( manager_inf.i_menu_vobu_map_start_sector )
864 if( ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
865 manager_inf.i_menu_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
871 if( manager_inf.i_cell_inf_start_sector )
873 if( ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
874 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) )
880 if( manager_inf.i_vobu_map_start_sector )
882 if( ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
883 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) )
890 intf_WarnMsg( 2, "ifo info: vts %d initialized",
891 p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_title_set_num );
893 p_ifo->vts.b_initialized = 1;
898 /*****************************************************************************
899 * FreeTitleSet : free all structures allocated by IfoTitleSet
900 *****************************************************************************/
901 static int FreeTitleSet( vts_t * p_vts )
905 if( p_vts->manager_inf.i_vobu_map_start_sector )
907 FreeVobuMap( &p_vts->vobu_map );
910 if( p_vts->manager_inf.i_cell_inf_start_sector )
912 FreeCellInf( &p_vts->cell_inf );
915 if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
917 FreeVobuMap( &p_vts->menu_vobu_map );
920 if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
922 FreeCellInf( &p_vts->menu_cell_inf );
925 if( p_vts->manager_inf.i_time_inf_start_sector )
927 for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
929 free( p_vts->time_inf.p_time_map[i].pi_sector );
932 free( p_vts->time_inf.p_time_map );
933 free( p_vts->time_inf.pi_start_byte );
936 if( p_vts->manager_inf.i_title_unit_start_sector )
938 FreeUnitInf( &p_vts->title_unit );
941 if( p_vts->manager_inf.i_menu_unit_start_sector )
943 FreeTitleUnit( &p_vts->menu_unit );
946 if( p_vts->manager_inf.i_title_inf_start_sector )
948 free( p_vts->title_inf.pi_start_byte );
949 free( p_vts->title_inf.p_title_start );
952 p_vts->b_initialized = 0;
957 /*****************************************************************************
958 * IfoDestroy : Frees all the memory allocated to ifo structures
959 *****************************************************************************/
960 void IfoDestroy( ifo_t * p_ifo )
964 FreeTitleSet( &p_ifo->vts );
966 if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
968 FreeVobuMap( &p_ifo->vmg.vobu_map );
971 if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
973 FreeCellInf( &p_ifo->vmg.cell_inf );
976 if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
978 free( p_ifo->vmg.vts_inf.p_vts_attr );
979 free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
982 /* free parental information structures */
983 if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
985 for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
987 for( j = 0 ; j < 8 ; j++ )
989 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
993 free( p_ifo->vmg.parental_inf.p_parental_mask );
994 free( p_ifo->vmg.parental_inf.p_parental_desc );
997 if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
999 FreeTitleUnit( &p_ifo->vmg.title_unit );
1002 if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
1004 free( p_ifo->vmg.title_inf.p_attr );
1007 FreeTitle( &p_ifo->vmg.title );
1014 * Function common to Video Manager and Video Title set Processing
1017 /*****************************************************************************
1018 * ReadTitle : Fills the title structure.
1019 *****************************************************************************
1020 * Titles are logical stream units that correspond to a whole inside the dvd.
1021 * Several title can point to the same part of the physical DVD, and give
1022 * map to different anglesfor instance.
1023 *****************************************************************************/
1024 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, off_t i_pos )
1026 u8 pi_buffer[DVD_LB_SIZE];
1033 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1035 i_start = p_ifo->i_pos;
1037 //fprintf( stderr, "PGC @ %lld\n",p_ifo->i_pos );
1039 DumpBits( p_ifo, pi_buffer, &p_current, 2);
1040 p_title->i_chapter_nb = ReadByte( p_ifo, pi_buffer, &p_current );
1041 p_title->i_cell_nb = ReadByte( p_ifo, pi_buffer, &p_current );
1042 //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb );
1043 p_title->i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
1044 p_title->i_prohibited_user_op = ReadDouble( p_ifo, pi_buffer, &p_current );
1045 for( i = 0 ; i < 8 ; i++ )
1047 i_audio = ReadWord( p_ifo, pi_buffer, &p_current );
1048 p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
1050 p_title->pi_audio_status[i].i_position = i_audio & 0x07;
1052 p_title->pi_audio_status[i].i_available = i_audio;
1054 for( i = 0 ; i < 32 ; i++ )
1056 i_spu = ReadDouble( p_ifo, pi_buffer, &p_current );
1057 p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
1059 p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
1061 p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
1063 p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
1065 p_title->pi_spu_status[i].i_available = i_spu;
1067 p_title->i_next_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1068 p_title->i_prev_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1069 p_title->i_go_up_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1070 //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 );
1071 p_title->i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1072 p_title->i_play_mode = ReadByte( p_ifo, pi_buffer, &p_current );
1073 for( i = 0 ; i < 16 ; i++ )
1075 p_title->pi_yuv_color[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1076 /* FIXME : We have to erase the extra bit */
1078 p_title->i_command_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1079 p_title->i_chapter_map_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1080 p_title->i_cell_play_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1081 p_title->i_cell_pos_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1083 /* parsing of command_t */
1084 if( p_title->i_command_start_byte )
1086 p_current = FillBuffer( p_ifo, pi_buffer,
1087 i_start + p_title->i_command_start_byte );
1090 p_title->command.i_pre_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1091 p_title->command.i_post_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1092 p_title->command.i_cell_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1093 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1095 /* pre-title commands */
1096 if( p_title->command.i_pre_command_nb )
1098 p_title->command.p_pre_command =
1099 malloc( p_title->command.i_pre_command_nb
1100 *sizeof(command_desc_t) );
1102 if( p_title->command.p_pre_command == NULL )
1104 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1108 for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
1110 p_title->command.p_pre_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1115 p_title->command.p_pre_command = NULL;
1118 /* post-title commands */
1119 if( p_title->command.i_post_command_nb )
1121 p_title->command.p_post_command =
1122 malloc( p_title->command.i_post_command_nb
1123 *sizeof(command_desc_t) );
1125 if( p_title->command.p_post_command == NULL )
1127 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1131 for( i=0 ; i<p_title->command.i_post_command_nb ; i++ )
1133 p_title->command.p_post_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1138 p_title->command.p_post_command = NULL;
1142 if( p_title->command.i_cell_command_nb )
1144 p_title->command.p_cell_command =
1145 malloc( p_title->command.i_cell_command_nb
1146 *sizeof(command_desc_t) );
1148 if( p_title->command.p_cell_command == NULL )
1150 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1154 for( i=0 ; i<p_title->command.i_cell_command_nb ; i++ )
1156 p_title->command.p_cell_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1161 p_title->command.p_cell_command = NULL;
1165 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1166 if( p_title->i_chapter_map_start_byte )
1168 #if !defined( WIN32 )
1169 p_ifo->i_pos = lseek( p_ifo->i_fd,
1170 i_start + p_title->i_chapter_map_start_byte,
1173 p_ifo->i_pos = SetFilePointer( (HANDLE) p_ifo->i_fd,
1174 i_start + p_title->i_chapter_map_start_byte,
1178 p_title->chapter_map.pi_start_cell =
1179 malloc( p_title->i_chapter_nb *sizeof(chapter_map_t) );
1181 if( p_title->chapter_map.pi_start_cell == NULL )
1183 intf_ErrMsg( "ifo error: out of memory in Read Title" );
1187 ReadBits( p_ifo, pi_buffer, &p_current, p_title->chapter_map.pi_start_cell,
1188 p_title->i_chapter_nb );
1192 p_title->chapter_map.pi_start_cell = NULL;
1195 /* parsing of cell_play_t */
1196 if( p_title->i_cell_play_start_byte )
1198 p_current = FillBuffer( p_ifo, pi_buffer,
1199 i_start + p_title->i_cell_play_start_byte );
1201 p_title->p_cell_play = malloc( p_title->i_cell_nb
1202 *sizeof(cell_play_t) );
1204 if( p_title->p_cell_play == NULL )
1206 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1210 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1212 p_title->p_cell_play[i].i_category = ReadWord( p_ifo, pi_buffer, &p_current );
1213 p_title->p_cell_play[i].i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1214 p_title->p_cell_play[i].i_command_nb = ReadByte( p_ifo, pi_buffer, &p_current );
1215 p_title->p_cell_play[i].i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
1216 p_title->p_cell_play[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1217 p_title->p_cell_play[i].i_first_ilvu_vobu_esector =
1218 ReadDouble( p_ifo, pi_buffer, &p_current );
1219 p_title->p_cell_play[i].i_last_vobu_start_sector =
1220 ReadDouble( p_ifo, pi_buffer, &p_current );
1221 p_title->p_cell_play[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1225 /* Parsing of cell_pos_t */
1226 if( p_title->i_cell_pos_start_byte )
1228 p_current = FillBuffer( p_ifo, pi_buffer,
1229 i_start + p_title->i_cell_pos_start_byte );
1231 p_title->p_cell_pos = malloc( p_title->i_cell_nb
1232 *sizeof(cell_pos_t) );
1234 if( p_title->p_cell_pos == NULL )
1236 intf_ErrMsg( "ifo error: out of memory" );
1240 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1242 p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1243 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1244 p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1251 /*****************************************************************************
1252 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1253 *****************************************************************************/
1254 static int FreeTitle( title_t * p_title )
1256 if( p_title->i_command_start_byte )
1258 if( p_title->command.i_pre_command_nb )
1260 free( p_title->command.p_pre_command );
1263 if( p_title->command.i_post_command_nb )
1265 free( p_title->command.p_post_command );
1268 if( p_title->command.i_cell_command_nb )
1270 free( p_title->command.p_cell_command );
1273 if( p_title->i_chapter_map_start_byte )
1275 free( p_title->chapter_map.pi_start_cell );
1278 if( p_title->i_cell_play_start_byte )
1280 free( p_title->p_cell_play );
1283 if( p_title->i_cell_pos_start_byte )
1285 free( p_title->p_cell_pos );
1292 /*****************************************************************************
1293 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1294 *****************************************************************************/
1295 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf, off_t i_pos )
1297 u8 pi_buffer[DVD_LB_SIZE];
1302 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1304 i_start = p_ifo->i_pos;
1305 //fprintf( stderr, "Unit\n" );
1307 p_unit_inf->i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1308 //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb );
1309 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1310 p_unit_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1312 p_unit_inf->p_title =
1313 malloc( p_unit_inf->i_title_nb *sizeof(unit_title_t) );
1314 if( p_unit_inf->p_title == NULL )
1316 intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1320 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1322 p_unit_inf->p_title[i].i_category_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1323 p_unit_inf->p_title[i].i_category = ReadByte( p_ifo, pi_buffer, &p_current );
1324 //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 );
1325 p_unit_inf->p_title[i].i_parental_mask = ReadWord( p_ifo, pi_buffer, &p_current );
1326 p_unit_inf->p_title[i].i_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1329 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1331 //fprintf( stderr, "Unit: PGC %d @ %lld\n", i, p_ifo->i_pos );
1332 ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1333 p_unit_inf->p_title[i].i_title_start_byte );
1339 /*****************************************************************************
1340 * FreeUnitInf : frees a structure allocated by ReadUnit
1341 *****************************************************************************/
1342 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1344 if( p_unit_inf->p_title != NULL )
1346 free( p_unit_inf->p_title );
1353 /*****************************************************************************
1354 * ReadTitleUnit: Fills the Title Unit structure.
1355 *****************************************************************************/
1356 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1359 u8 pi_buffer[DVD_LB_SIZE];
1364 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1365 i_start = p_ifo->i_pos;
1366 //fprintf( stderr, "Unit Table\n" );
1368 p_title_unit->i_unit_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1369 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1370 p_title_unit->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1372 //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1374 p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb *sizeof(unit_t) );
1375 if( p_title_unit->p_unit == NULL )
1377 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1381 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1383 //ReadBits( p_ifo, pi_buffer, &p_current, p_title_unit->p_unit[i].ps_lang_code, 2 );
1384 p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, pi_buffer, &p_current );
1385 //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code );
1386 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1387 p_title_unit->p_unit[i].i_existence_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1388 p_title_unit->p_unit[i].i_unit_inf_start_byte =
1389 ReadDouble( p_ifo, pi_buffer, &p_current );
1392 p_title_unit->p_unit_inf =
1393 malloc( p_title_unit->i_unit_nb *sizeof(unit_inf_t) );
1394 if( p_title_unit->p_unit_inf == NULL )
1396 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1400 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1402 ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1403 p_title_unit->p_unit[i].i_unit_inf_start_byte );
1409 /*****************************************************************************
1410 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1411 *****************************************************************************/
1412 static int FreeTitleUnit( title_unit_t * p_title_unit )
1416 if( p_title_unit->p_unit_inf != NULL )
1418 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1420 FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1423 free( p_title_unit->p_unit_inf );
1429 /*****************************************************************************
1430 * ReadCellInf : Fills the Cell Information structure.
1431 *****************************************************************************/
1432 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, off_t i_pos )
1434 u8 pi_buffer[DVD_LB_SIZE];
1439 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1440 i_start = p_ifo->i_pos;
1441 //fprintf( stderr, "CELL ADD\n" );
1443 p_cell_inf->i_vob_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1444 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1445 p_cell_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1447 p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t);
1449 //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 );
1451 p_cell_inf->p_cell_map =
1452 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1453 if( p_cell_inf->p_cell_map == NULL )
1455 intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1459 for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1461 p_cell_inf->p_cell_map[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1462 p_cell_inf->p_cell_map[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1463 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1464 p_cell_inf->p_cell_map[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1465 // fprintf(stderr, "sector[%d] %d (%lld)\n", i,ntohl(*(u32*)(p_current)), p_ifo->i_pos);
1466 p_cell_inf->p_cell_map[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1472 /*****************************************************************************
1473 * FreeCellInf : frees structures allocated by ReadCellInf
1474 *****************************************************************************/
1475 static int FreeCellInf( cell_inf_t * p_cell_inf )
1477 free( p_cell_inf->p_cell_map );
1482 /*****************************************************************************
1483 * ReadVobuMap : Fills the VOBU Map structure.
1484 *****************************************************************************/
1485 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, off_t i_pos )
1487 u8 pi_buffer[DVD_LB_SIZE];
1492 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1493 i_start = p_ifo->i_pos;
1494 //fprintf( stderr, "VOBU ADMAP\n" );
1496 p_vobu_map->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1497 i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos )
1500 p_vobu_map->pi_vobu_start_sector = malloc( i_max *sizeof(u32) );
1501 if( p_vobu_map->pi_vobu_start_sector == NULL )
1503 intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1507 for( i = 0 ; i < i_max ; i++ )
1509 p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1515 /*****************************************************************************
1516 * FreeVobuMap: frees structures allocated by ReadVobuMap
1517 *****************************************************************************/
1518 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1520 free( p_vobu_map->pi_vobu_start_sector );
1526 * IFO virtual machine : a set of commands that give the
1527 * interactive behaviour of the dvd
1531 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1532 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1534 static char ifo_reg[][80]=
1536 "Menu_Language_Code",
1538 "SubPicture_Stream_#",
1544 "Highlighted_Button_#",
1547 "Karaoke_audio_mixing_mode",
1548 "Parental_mgmt_country_code",
1552 "Audio_language_code_setting",
1553 "Audio_language_extension_code",
1554 "SPU_language_code_setting",
1555 "SPU_language_extension_code",
1556 "?Player_Regional_Code",
1562 static char * IfoMath( char val )
1564 static char math_op[][10] =
1584 return (char *) math_op[val & 0x0f];
1588 char ifo_cmp[][10] =
1600 char ifo_parental[][10] =
1612 char ifo_menu_id[][80] =
1624 char * IfoMenuName( char index )
1626 return ifo_menu_id[index&0x07];
1629 static void IfoRegister( u16 i_data, u8 i_direct)
1633 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1635 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1639 printf("0x%02x", i_data);
1654 printf("s[%s]", ifo_reg[i_data]);
1667 printf("r[0x%02x]", i_data);
1673 static void IfoAdvanced( u8 *pi_code )
1675 u8 i_cmd = pi_code[0];
1681 printf( " Highlight button %d; ", pi_code[1]>>2 );
1686 printf( " Illegal " );
1691 printf( "ReSuME %d", pi_code[7] );
1693 else if( ( i_cmd & 0x06) == 0x02 )
1695 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1699 printf( "advanced (0x%02x) ", i_cmd );
1704 static void IfoJmp( ifo_command_t com )
1709 switch( com.i_sub_cmd )
1715 printf( "VTS 0x%02x", OP_VAL_8(3) );
1718 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1721 printf( "This VTS Title 0x%02x Part 0x%04x",
1723 OP_VAL_8(0)<<8|OP_VAL_8(1));
1727 printf ("in SystemSpace ");
1728 switch (OP_VAL_8(3)>>4) {
1730 printf ("to play first PGC");
1733 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1737 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1740 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1743 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1746 switch( OP_VAL_8(3)>>6 )
1749 printf( "to play first PGC" );
1752 printf( "to VMG title menu (?)" );
1755 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1758 IfoMenuName( OP_VAL_8(3)&0xF ) );
1761 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1768 switch(OP_VAL_8(3)>>4) {
1770 printf ("system first pgc");
1773 printf ("system title menu");
1776 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1779 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1782 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1785 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1789 // OP_VAL_8(2) is number of cell
1790 // it is processed BEFORE switch
1791 // under some conditions, it is ignored
1792 // I don't understand exactly what it means
1793 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1795 switch( OP_VAL_8(3)>>6 )
1798 printf( "to FP PGC" );
1801 printf( "to VMG root menu (?)" );
1804 printf( "to VTS menu \"%s\" (?)",
1805 IfoMenuName(OP_VAL_8(3)&0xF) );
1808 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1816 static void IfoLnk( ifo_command_t com )
1818 u16 i_button=OP_VAL_8(4)>>2;
1822 switch( com.i_sub_cmd )
1825 IfoAdvanced( &OP_VAL_8(4) );
1829 printf( "PGC 0x%02x", OP_VAL_16(2) );
1833 printf( "PTT 0x%02x", OP_VAL_16(2) );
1837 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1841 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1849 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1854 void IfoSetSystem( ifo_command_t com )
1861 for( i=1; i<=3; i++ )
1863 if( OP_VAL_8(i)&0x80 )
1867 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1871 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1877 if(OP_VAL_8(1]&0x80)
1878 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1879 if(OP_VAL_8(2)&0x80)
1880 //DENT: lwhat about 0x7f here ???
1881 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1882 if(OP_VAL_8(3)&0x80)
1883 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1885 if(OP_VAL_8(1)&0x80)
1886 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1887 if(OP_VAL_8(2)&0x80)
1888 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1889 if(OP_VAL_8(3)&0x80)
1890 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1898 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1902 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1905 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1906 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1911 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1915 printf ("r[r[0x%02x]] = r[0x%02x]",
1916 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1920 //actually only bits 00011100 00011100 are set
1923 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1927 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1932 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1933 //but it is way too ugly
1936 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1940 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1948 static void IfoSet( ifo_command_t com )
1950 IfoRegister( OP_VAL_16(0), 0 );
1951 printf( " %s ", IfoMath( com.i_cmd ) );
1952 IfoRegister( OP_VAL_16(1), com.i_direct );
1955 /*****************************************************************************
1956 * CommandRead : translates the command strings in ifo into command
1958 *****************************************************************************/
1959 void CommandRead( ifo_command_t com )
1961 u8* pi_code = (u8*)(&com);
1963 switch( com.i_type )
1976 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1977 ifo_cmp[com.i_cmp]);
1978 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1983 switch( com.i_sub_cmd )
1986 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1990 printf( "stop VM" );
1994 printf( "Set Parental Level To %s and goto Line 0x%02x",
1995 ifo_parental[OP_VAL_8(4)&0x7],
2000 printf( "Illegal" );
2019 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
2020 ifo_cmp[com.i_cmp] );
2021 IfoRegister( OP_VAL_8(5), 0 );
2032 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
2033 ifo_cmp[com.i_cmp] );
2034 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
2048 IfoSetSystem( com );
2050 else if( com.i_cmp && !com.i_sub_cmd )
2052 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
2053 IfoRegister( OP_VAL_8(5), 0 );
2055 IfoSetSystem( com );
2057 else if( !com.i_cmp && com.i_sub_cmd )
2060 IfoSetSystem( com );
2076 else if( com.i_cmp && !com.i_sub_cmd )
2078 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
2079 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
2083 else if( !com.i_cmp && com.i_sub_cmd )
2097 * math command on r[opcode[1]] and
2098 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
2099 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
2101 * boolean operation cmp on r[opcode[1]] and
2102 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
2103 * on true result, buttons(c[6], c[7]) is called
2104 * problem is 'what is buttons()'
2107 printf( "r[0x%X] ", pi_code[1] );
2108 printf( " %s ", IfoMath( com.i_cmd ) );
2109 if( com.i_cmd == 2 )
2111 printf( "r[0x%X] ", OP_VAL_8(1) );
2115 IfoRegister( OP_VAL_16(0), com.i_direct );
2119 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
2120 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
2121 printf( " ) then {" );
2122 IfoAdvanced( &OP_VAL_8(4) );
2127 * opposite to case 4: boolean, math and buttons.
2133 if( !com.i_direct && com.i_dir_cmp )
2135 printf( "0x%X", OP_VAL_16(1) );
2139 IfoRegister( OP_VAL_8(3), 0 );
2140 if( OP_VAL_8(3)&0x80 )
2142 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2146 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2147 // 0x1F is either not a mistake,
2148 // or Microsoft programmer's mistake!!!
2152 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2153 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2154 printf( " ) then {" );
2155 printf( "r[0x%X] ", pi_code[1] & 0xF );
2156 printf( " %s ", IfoMath( com.i_cmd ) );
2158 if( com.i_cmd == 0x02 ) // swap
2160 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2166 printf( "0x%X", OP_VAL_16(0) );
2170 if( OP_VAL_8(0) & 0x80 )
2172 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2176 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2182 IfoAdvanced( &OP_VAL_8(4) );
2188 printf( "Unknown Command\n" );
2195 /*****************************************************************************
2196 * CommandPrint : print in clear text (I hope so !) what a command does
2197 *****************************************************************************/
2198 void CommandPrint( ifo_t ifo )