1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.29 2001/05/31 03:12:49 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 )
52 #include "input_dvd.h"
54 /*****************************************************************************
56 *****************************************************************************/
57 void CommandRead ( command_desc_t );
58 static int ReadTitle ( ifo_t * , title_t *, off_t );
59 static int FreeTitle ( title_t * );
60 static int ReadUnitInf ( ifo_t * , unit_inf_t *, off_t );
61 static int FreeUnitInf ( unit_inf_t * );
62 static int ReadTitleUnit ( ifo_t * , title_unit_t *, off_t );
63 static int FreeTitleUnit ( title_unit_t * );
64 static int ReadVobuMap ( ifo_t * , vobu_map_t *, off_t );
65 static int FreeVobuMap ( vobu_map_t * );
66 static int ReadCellInf ( ifo_t * , cell_inf_t *, off_t );
67 static int FreeCellInf ( cell_inf_t * );
68 static int FreeTitleSet ( vts_t * );
70 /*****************************************************************************
72 *****************************************************************************/
73 static __inline__ u8* FillBuffer( ifo_t* p_ifo, u8* pi_buffer, off_t i_pos )
79 memset( pi_buffer, 0, DVD_LB_SIZE );
81 p_ifo->i_pos = lseek( p_ifo->i_fd, i_pos, SEEK_SET );
82 read( p_ifo->i_fd, pi_buffer, DVD_LB_SIZE );
84 p_ifo->i_pos = SetFilePointer( (HANDLE) p_ifo->i_fd, i_pos, NULL, FILE_BEGIN );
85 ReadFile( (HANDLE) p_ifo->i_fd, pi_buffer, DVD_LB_SIZE, &tmp, NULL );
91 static __inline__ u8 ReadByte( ifo_t * p_ifo, u8* pi_buffer, u8** pp_current )
95 if( *pp_current > pi_buffer + DVD_LB_SIZE )
97 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
100 i_ret = *(*pp_current)++;
105 static __inline__ u16 ReadWord( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
109 if( *pp_current > pi_buffer + DVD_LB_SIZE - 2 )
111 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
114 i_ret = U16_AT(*pp_current);
120 static __inline__ u32 ReadDouble( ifo_t * p_ifo, u8* pi_buffer,
125 if( *pp_current > pi_buffer + DVD_LB_SIZE - 4 )
127 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE);
128 // intf_WarnMsg( 1, "new buffer in double @ %lld", p_ifo->i_pos );
131 i_ret = U32_AT(*pp_current);
137 static __inline__ u64 ReadQuad( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
141 if( *pp_current > pi_buffer + DVD_LB_SIZE - 8 )
143 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
146 i_ret = U64_AT(*pp_current);
152 static __inline__ void ReadBits( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current,
153 u8* pi_dest, int i_nb )
155 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
157 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
160 memcpy( pi_dest, *pp_current, i_nb );
166 static __inline__ void DumpBits( ifo_t* p_ifo, u8* pi_buffer,
167 u8** pp_current, int i_nb )
169 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
171 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
182 /*****************************************************************************
183 * IfoCreate : Creates an ifo structure and prepares for parsing directly
185 *****************************************************************************/
186 int IfoCreate( thread_dvd_data_t * p_dvd )
188 p_dvd->p_ifo = malloc( sizeof(ifo_t) );
189 if( p_dvd->p_ifo == NULL )
191 intf_ErrMsg( "ifo error: unable to allocate memory. aborting" );
195 /* if we are here the dvd device has already been opened */
196 p_dvd->p_ifo->i_fd = p_dvd->i_fd;
201 /*****************************************************************************
202 * IfoInit : Reads information from the management table.
203 *****************************************************************************/
204 int IfoInit( ifo_t * p_ifo )
206 u8 pi_buffer[DVD_LB_SIZE];
213 /* find the start sector of video information on the dvd */
214 i_lba = UDFFindFile( p_ifo->i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
216 p_ifo->i_off = (off_t)(i_lba) * DVD_LB_SIZE;
218 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off );
219 //i_start = p_ifo->i_pos;
221 * read the video manager information table
223 #define manager_inf p_ifo->vmg.manager_inf
224 //fprintf( stderr, "VMGI\n" );
226 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id, 12 );
227 manager_inf.psz_id[12] = '\0';
228 manager_inf.i_vmg_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
229 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
230 manager_inf.i_vmg_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
231 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
232 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
233 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
234 manager_inf.i_volume_nb = ReadWord( p_ifo, pi_buffer, &p_current );
235 manager_inf.i_volume = ReadWord( p_ifo, pi_buffer, &p_current );
236 manager_inf.i_disc_side = ReadByte( p_ifo, pi_buffer, &p_current );
237 DumpBits( p_ifo, pi_buffer, &p_current, 19 );
238 manager_inf.i_title_set_nb = ReadWord( p_ifo, pi_buffer, &p_current );
239 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.ps_provider_id, 32 );
240 manager_inf.i_pos_code = ReadQuad( p_ifo, pi_buffer, &p_current );
241 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
242 manager_inf.i_vmg_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
243 manager_inf.i_first_play_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
244 DumpBits( p_ifo, pi_buffer, &p_current, 56 );
245 manager_inf.i_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
246 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
247 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
248 manager_inf.i_parental_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
249 manager_inf.i_vts_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
250 manager_inf.i_text_data_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
251 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
252 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
253 DumpBits( p_ifo, pi_buffer, &p_current, 32 );
254 // GETS( &manager_inf.video_atrt );
255 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
256 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
257 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
258 //fprintf( stderr, "vmgi audio nb : %d\n", manager_inf.i_audio_nb );
259 for( i=0 ; i < 8 ; i++ )
261 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
263 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
264 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
265 //fprintf( stderr, "vmgi subpic nb : %d\n", manager_inf.i_spu_nb );
266 for( i=0 ; i < manager_inf.i_spu_nb ; i++ )
268 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
269 /* FIXME : take care of endianness */
273 * read first play title.
275 if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_off +
276 manager_inf.i_first_play_title_start_byte ) < 0 )
282 * fills the title information structure.
284 #define title_inf p_ifo->vmg.title_inf
285 if( manager_inf.i_title_inf_start_sector )
287 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
288 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
289 //fprintf( stderr, "title inf %lld\n", p_ifo->i_pos );
291 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
292 //fprintf( stderr, "title_inf: TTU nb %d\n", title_inf.i_title_nb );
293 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
294 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
296 /* parsing of title attributes */
297 title_inf.p_attr = malloc( title_inf.i_title_nb *sizeof(title_attr_t) );
298 if( title_inf.p_attr == NULL )
300 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
304 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
306 title_inf.p_attr[i].i_play_type = ReadByte( p_ifo, pi_buffer, &p_current );
307 title_inf.p_attr[i].i_angle_nb = ReadByte( p_ifo, pi_buffer, &p_current );
308 title_inf.p_attr[i].i_chapter_nb = ReadWord( p_ifo, pi_buffer, &p_current );
309 title_inf.p_attr[i].i_parental_id = ReadWord( p_ifo, pi_buffer, &p_current );
310 title_inf.p_attr[i].i_title_set_num = ReadByte( p_ifo, pi_buffer, &p_current );
311 title_inf.p_attr[i].i_title_num = ReadByte( p_ifo, pi_buffer, &p_current );
312 title_inf.p_attr[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
313 //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 );
318 title_inf.p_attr = NULL;
323 * fills the title unit structure.
325 if( manager_inf.i_title_unit_start_sector )
327 if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_off +
328 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
335 * fills the structure about parental information.
337 #define parental p_ifo->vmg.parental_inf
338 if( manager_inf.i_parental_inf_start_sector )
340 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
341 manager_inf.i_parental_inf_start_sector *DVD_LB_SIZE );
342 i_start = p_ifo->i_pos;
344 //fprintf( stderr, "PTL\n" );
346 parental.i_country_nb = ReadWord( p_ifo, pi_buffer, &p_current );
347 parental.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );
348 parental.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
350 parental.p_parental_desc = malloc( parental.i_country_nb *
351 sizeof(parental_desc_t) );
352 if( parental.p_parental_desc == NULL )
354 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
358 for( i = 0 ; i < parental.i_country_nb ; i++ )
360 ReadBits( p_ifo, pi_buffer, &p_current,
361 parental.p_parental_desc[i].ps_country_code, 2 );
362 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
363 parental.p_parental_desc[i].i_parental_mask_start_byte =
364 ReadWord( p_ifo, pi_buffer, &p_current );
365 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
368 parental.p_parental_mask = malloc( parental.i_country_nb *
369 sizeof(parental_mask_t) );
370 if( parental.p_parental_mask == NULL )
372 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
376 for( i = 0 ; i < parental.i_country_nb ; i++ )
378 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
379 parental.p_parental_desc[i].i_parental_mask_start_byte );
380 for( j = 0 ; j < 8 ; j++ )
382 parental.p_parental_mask[i].ppi_mask[j] =
383 malloc( ( parental.i_vts_nb + 1 ) *sizeof(u16) );
384 if( parental.p_parental_mask[i].ppi_mask[j] == NULL )
386 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
389 for( k = 0 ; k < parental.i_vts_nb + 1 ; k++ )
391 parental.p_parental_mask[i].ppi_mask[j][k] =
392 ReadWord( p_ifo, pi_buffer, &p_current );
400 * information and attributes about for each vts.
402 #define vts_inf p_ifo->vmg.vts_inf
403 if( manager_inf.i_vts_inf_start_sector )
407 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
408 manager_inf.i_vts_inf_start_sector *DVD_LB_SIZE );
409 i_start = p_ifo->i_pos;
411 //fprintf( stderr, "VTS ATTR\n" );
413 vts_inf.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
414 //fprintf( stderr, "VTS ATTR Nb: %d\n", vts_inf.i_vts_nb );
415 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
416 vts_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
417 vts_inf.pi_vts_attr_start_byte =
418 malloc( vts_inf.i_vts_nb *sizeof(u32) );
419 if( vts_inf.pi_vts_attr_start_byte == NULL )
421 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
425 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
427 vts_inf.pi_vts_attr_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
430 vts_inf.p_vts_attr = malloc( vts_inf.i_vts_nb *sizeof(vts_attr_t) );
431 if( vts_inf.p_vts_attr == NULL )
433 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
437 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
439 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
440 vts_inf.pi_vts_attr_start_byte[i] );
441 vts_inf.p_vts_attr[i].i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
442 vts_inf.p_vts_attr[i].i_cat_app_type = ReadDouble( p_ifo, pi_buffer, &p_current );
443 // GETS( &vts_inf.p_vts_attr[i].vts_menu_video_attr );
444 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
445 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
446 vts_inf.p_vts_attr[i].i_vts_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
447 //fprintf( stderr, "m audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_audio_nb );
448 for( j = 0 ; j < 8 ; j++ )
450 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
452 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
453 vts_inf.p_vts_attr[i].i_vts_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
454 //fprintf( stderr, "m subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_spu_nb );
455 for( j = 0 ; j < 28 ; j++ )
457 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
458 /* FIXME : Fix endianness issue here */
460 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
461 // GETS( &vts_inf.p_vts_attr[i].vtstt_video_vts_inf );
462 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
463 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
464 vts_inf.p_vts_attr[i].i_vts_title_audio_nb =
465 ReadDouble( p_ifo, pi_buffer, &p_current );
466 //fprintf( stderr, "tt audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_audio_nb );
467 for( j = 0 ; j < 8 ; j++ )
469 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
471 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
472 vts_inf.p_vts_attr[i].i_vts_title_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
473 //fprintf( stderr, "tt subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_spu_nb );
474 for( j=0 ; j<28/*vts_inf.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
476 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
477 /* FIXME : Fix endianness issue here */
486 if( manager_inf.i_cell_inf_start_sector )
488 if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_off +
489 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
496 * global vob unit map.
498 if( manager_inf.i_vobu_map_start_sector )
500 if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_off +
501 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
508 p_ifo->vts.b_initialized = 0;
510 intf_WarnMsg( 2, "ifo info: vmg initialized" );
515 /*****************************************************************************
516 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
517 *****************************************************************************/
518 int IfoTitleSet( ifo_t * p_ifo )
520 u8 pi_buffer[DVD_LB_SIZE];
528 if( p_ifo->vts.b_initialized )
530 FreeTitleSet( &p_ifo->vts );
534 (off_t)( p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_start_sector )
538 //fprintf(stderr, "offset: %lld\n" , i_off );
540 p_current = FillBuffer( p_ifo, pi_buffer, i_off );
541 //i_start = p_ifo->i_pos;
542 p_ifo->vts.i_pos = p_ifo->i_pos;
544 #define manager_inf p_ifo->vts.manager_inf
546 * reads manager information
548 //fprintf( stderr, "VTSI\n" );
550 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id , 12 );
551 manager_inf.psz_id[12] = '\0';
552 manager_inf.i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
553 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
554 manager_inf.i_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
555 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
556 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
557 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
558 DumpBits( p_ifo, pi_buffer, &p_current, 90 );
559 manager_inf.i_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
560 DumpBits( p_ifo, pi_buffer, &p_current, 60 );
561 manager_inf.i_menu_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
562 manager_inf.i_title_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
563 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
564 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
565 manager_inf.i_menu_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
566 manager_inf.i_time_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
567 manager_inf.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
568 manager_inf.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
569 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
570 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
571 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
572 // GETS( &manager_inf.m_video_atrt );
573 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
574 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
575 manager_inf.i_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
576 for( i = 0 ; i < 8 ; i++ )
578 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
580 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
581 manager_inf.i_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
582 for( i = 0 ; i < 28 ; i++ )
584 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
585 /* FIXME : take care of endianness */
587 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
589 i_short = ReadWord( p_ifo, pi_buffer, &p_current );
591 manager_inf.video_attr.i_mode = i_short & 0x1;
593 manager_inf.video_attr.i_letterboxed = i_short & 0x1;
595 manager_inf.video_attr.i_source_res = i_short & 0x3;
597 manager_inf.video_attr.i_line21_2 = i_short & 0x1;
599 manager_inf.video_attr.i_line21_1 = i_short & 0x1;
601 manager_inf.video_attr.i_perm_displ = i_short & 0x3;
603 manager_inf.video_attr.i_ratio = i_short & 0x3;
605 manager_inf.video_attr.i_system = i_short & 0x3;
607 manager_inf.video_attr.i_compression = i_short & 0x3;
609 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
610 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
611 //fprintf( stderr, "vtsi audio nb : %d\n", manager_inf.i_audio_nb );
612 for( i = 0 ; i < 8 ; i++ )
614 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
615 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
617 manager_inf.p_audio_attr[i].i_bar = i_temp & 0xff;
619 manager_inf.p_audio_attr[i].i_caption = i_temp & 0xff;
621 manager_inf.p_audio_attr[i].i_foo = i_temp & 0xff;
623 manager_inf.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
625 manager_inf.p_audio_attr[i].i_num_channels = i_temp & 0x7;
627 manager_inf.p_audio_attr[i].i_test = i_temp & 0x1;
629 manager_inf.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
631 manager_inf.p_audio_attr[i].i_quantization = i_temp & 0x3;
633 manager_inf.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
635 manager_inf.p_audio_attr[i].i_type = i_temp & 0x3;
637 manager_inf.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
639 manager_inf.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
641 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
642 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
643 //fprintf( stderr, "vtsi subpic nb : %d\n", manager_inf.i_spu_nb );
644 for( i=0 ; i<manager_inf.i_spu_nb ; i++ )
646 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
647 i_temp = hton64( i_temp ) >> 16;
648 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
649 manager_inf.p_spu_attr[i].i_caption = i_temp & 0xff;
651 manager_inf.p_spu_attr[i].i_foo = i_temp & 0xff;
653 manager_inf.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
655 manager_inf.p_spu_attr[i].i_prefix = i_temp & 0xffff;
659 * reads title information: set of pointers to title
661 #define title_inf p_ifo->vts.title_inf
662 if( manager_inf.i_title_inf_start_sector )
664 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
665 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
667 i_start = p_ifo->i_pos;
669 //fprintf( stderr, "VTS PTR\n" );
671 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
672 //fprintf( stderr, "VTS title_inf nb: %d\n", title_inf.i_title_nb );
673 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
674 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
676 title_inf.pi_start_byte = malloc( title_inf.i_title_nb *sizeof(u32) );
677 if( title_inf.pi_start_byte == NULL )
679 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
683 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
685 title_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
689 title_inf.p_title_start = malloc( title_inf.i_title_nb
690 *sizeof(title_start_t) );
691 if( title_inf.p_title_start == NULL )
693 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
697 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
699 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
700 title_inf.pi_start_byte[i] );
702 title_inf.p_title_start[i].i_title_id =
703 ReadWord( p_ifo, pi_buffer, &p_current );
704 title_inf.p_title_start[i].i_chapter = ReadWord( p_ifo, pi_buffer, &p_current );
705 //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 );
711 * menu unit information
713 if( manager_inf.i_menu_unit_start_sector )
715 if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
716 manager_inf.i_menu_unit_start_sector *DVD_LB_SIZE ) < 0 )
723 * title unit information
725 if( manager_inf.i_title_unit_start_sector )
727 if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
728 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
735 * time map inforamtion
737 #define time_inf p_ifo->vts.time_inf
738 if( manager_inf.i_time_inf_start_sector )
740 u8 pi_buffer[DVD_LB_SIZE];
742 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
743 manager_inf.i_time_inf_start_sector *DVD_LB_SIZE );
745 //fprintf( stderr, "TMAP\n" );
747 time_inf.i_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
748 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
749 time_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
751 time_inf.pi_start_byte = malloc( time_inf.i_nb *sizeof(u32) );
752 if( time_inf.pi_start_byte == NULL )
754 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
758 for( i = 0 ; i < time_inf.i_nb ; i++ )
760 time_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
763 time_inf.p_time_map = malloc( time_inf.i_nb *sizeof(time_map_t) );
764 if( time_inf.p_time_map == NULL )
766 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
770 for( i = 0 ; i < time_inf.i_nb ; i++ )
772 time_inf.p_time_map[i].i_time_unit = ReadByte( p_ifo, pi_buffer, &p_current );
773 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
774 time_inf.p_time_map[i].i_entry_nb = ReadWord( p_ifo, pi_buffer, &p_current );
776 time_inf.p_time_map[i].pi_sector =
777 malloc( time_inf.p_time_map[i].i_entry_nb *sizeof(u32) );
778 if( time_inf.p_time_map[i].pi_sector == NULL )
780 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
784 for( j = 0 ; j < time_inf.p_time_map[i].i_entry_nb ; j++ )
786 time_inf.p_time_map[i].pi_sector[j] = ReadDouble( p_ifo, pi_buffer, &p_current );
792 if( manager_inf.i_menu_cell_inf_start_sector )
794 if( ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
795 manager_inf.i_menu_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
801 if( manager_inf.i_menu_vobu_map_start_sector )
803 if( ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
804 manager_inf.i_menu_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
810 if( manager_inf.i_cell_inf_start_sector )
812 if( ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
813 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) )
819 if( manager_inf.i_vobu_map_start_sector )
821 if( ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
822 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) )
829 intf_WarnMsg( 2, "ifo info: vts %d initialized",
830 p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_title_set_num );
832 p_ifo->vts.b_initialized = 1;
837 /*****************************************************************************
838 * FreeTitleSet : free all structures allocated by IfoTitleSet
839 *****************************************************************************/
840 static int FreeTitleSet( vts_t * p_vts )
844 if( p_vts->manager_inf.i_vobu_map_start_sector )
846 FreeVobuMap( &p_vts->vobu_map );
849 if( p_vts->manager_inf.i_cell_inf_start_sector )
851 FreeCellInf( &p_vts->cell_inf );
854 if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
856 FreeVobuMap( &p_vts->menu_vobu_map );
859 if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
861 FreeCellInf( &p_vts->menu_cell_inf );
864 if( p_vts->manager_inf.i_time_inf_start_sector )
866 for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
868 free( p_vts->time_inf.p_time_map[i].pi_sector );
871 free( p_vts->time_inf.p_time_map );
872 free( p_vts->time_inf.pi_start_byte );
875 if( p_vts->manager_inf.i_title_unit_start_sector )
877 FreeUnitInf( &p_vts->title_unit );
880 if( p_vts->manager_inf.i_menu_unit_start_sector )
882 FreeTitleUnit( &p_vts->menu_unit );
885 if( p_vts->manager_inf.i_title_inf_start_sector )
887 free( p_vts->title_inf.pi_start_byte );
888 free( p_vts->title_inf.p_title_start );
891 p_vts->b_initialized = 0;
896 /*****************************************************************************
897 * IfoDestroy : Frees all the memory allocated to ifo structures
898 *****************************************************************************/
899 void IfoDestroy( ifo_t * p_ifo )
903 FreeTitleSet( &p_ifo->vts );
905 if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
907 FreeVobuMap( &p_ifo->vmg.vobu_map );
910 if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
912 FreeCellInf( &p_ifo->vmg.cell_inf );
915 if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
917 free( p_ifo->vmg.vts_inf.p_vts_attr );
918 free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
921 /* free parental information structures */
922 if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
924 for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
926 for( j = 0 ; j < 8 ; j++ )
928 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
932 free( p_ifo->vmg.parental_inf.p_parental_mask );
933 free( p_ifo->vmg.parental_inf.p_parental_desc );
936 if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
938 FreeTitleUnit( &p_ifo->vmg.title_unit );
941 if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
943 free( p_ifo->vmg.title_inf.p_attr );
946 FreeTitle( &p_ifo->vmg.title );
953 * Function common to Video Manager and Video Title set Processing
956 /*****************************************************************************
957 * ReadTitle : Fills the title structure.
958 *****************************************************************************
959 * Titles are logical stream units that correspond to a whole inside the dvd.
960 * Several title can point to the same part of the physical DVD, and give
961 * map to different anglesfor instance.
962 *****************************************************************************/
963 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, off_t i_pos )
965 u8 pi_buffer[DVD_LB_SIZE];
972 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
974 i_start = p_ifo->i_pos;
976 //fprintf( stderr, "PGC @ %lld\n",p_ifo->i_pos );
978 DumpBits( p_ifo, pi_buffer, &p_current, 2);
979 p_title->i_chapter_nb = ReadByte( p_ifo, pi_buffer, &p_current );
980 p_title->i_cell_nb = ReadByte( p_ifo, pi_buffer, &p_current );
981 //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb );
982 p_title->i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
983 p_title->i_prohibited_user_op = ReadDouble( p_ifo, pi_buffer, &p_current );
984 for( i = 0 ; i < 8 ; i++ )
986 i_audio = ReadWord( p_ifo, pi_buffer, &p_current );
987 p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
989 p_title->pi_audio_status[i].i_position = i_audio & 0x07;
991 p_title->pi_audio_status[i].i_available = i_audio;
993 for( i = 0 ; i < 32 ; i++ )
995 i_spu = ReadDouble( p_ifo, pi_buffer, &p_current );
996 p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
998 p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
1000 p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
1002 p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
1004 p_title->pi_spu_status[i].i_available = i_spu;
1006 p_title->i_next_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1007 p_title->i_prev_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1008 p_title->i_go_up_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1009 //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 );
1010 p_title->i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1011 p_title->i_play_mode = ReadByte( p_ifo, pi_buffer, &p_current );
1012 for( i = 0 ; i < 16 ; i++ )
1014 p_title->pi_yuv_color[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1015 /* FIXME : We have to erase the extra bit */
1017 p_title->i_command_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1018 p_title->i_chapter_map_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1019 p_title->i_cell_play_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1020 p_title->i_cell_pos_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1022 /* parsing of command_t */
1023 if( p_title->i_command_start_byte )
1025 p_current = FillBuffer( p_ifo, pi_buffer,
1026 i_start + p_title->i_command_start_byte );
1029 p_title->command.i_pre_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1030 p_title->command.i_post_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1031 p_title->command.i_cell_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1032 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1034 /* pre-title commands */
1035 if( p_title->command.i_pre_command_nb )
1037 p_title->command.p_pre_command =
1038 malloc( p_title->command.i_pre_command_nb
1039 *sizeof(command_desc_t) );
1041 if( p_title->command.p_pre_command == NULL )
1043 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1047 for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
1049 p_title->command.p_pre_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1054 p_title->command.p_pre_command = NULL;
1057 /* post-title commands */
1058 if( p_title->command.i_post_command_nb )
1060 p_title->command.p_post_command =
1061 malloc( p_title->command.i_post_command_nb
1062 *sizeof(command_desc_t) );
1064 if( p_title->command.p_post_command == NULL )
1066 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1070 for( i=0 ; i<p_title->command.i_post_command_nb ; i++ )
1072 p_title->command.p_post_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1077 p_title->command.p_post_command = NULL;
1081 if( p_title->command.i_cell_command_nb )
1083 p_title->command.p_cell_command =
1084 malloc( p_title->command.i_cell_command_nb
1085 *sizeof(command_desc_t) );
1087 if( p_title->command.p_cell_command == NULL )
1089 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1093 for( i=0 ; i<p_title->command.i_cell_command_nb ; i++ )
1095 p_title->command.p_cell_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1100 p_title->command.p_cell_command = NULL;
1104 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1105 if( p_title->i_chapter_map_start_byte )
1107 #if !defined( WIN32 )
1108 p_ifo->i_pos = lseek( p_ifo->i_fd,
1109 i_start + p_title->i_chapter_map_start_byte,
1112 p_ifo->i_pos = SetFilePointer( (HANDLE) p_ifo->i_fd,
1113 i_start + p_title->i_chapter_map_start_byte,
1117 p_title->chapter_map.pi_start_cell =
1118 malloc( p_title->i_chapter_nb *sizeof(chapter_map_t) );
1120 if( p_title->chapter_map.pi_start_cell == NULL )
1122 intf_ErrMsg( "ifo error: out of memory in Read Title" );
1126 ReadBits( p_ifo, pi_buffer, &p_current, p_title->chapter_map.pi_start_cell,
1127 p_title->i_chapter_nb );
1131 p_title->chapter_map.pi_start_cell = NULL;
1134 /* parsing of cell_play_t */
1135 if( p_title->i_cell_play_start_byte )
1137 p_current = FillBuffer( p_ifo, pi_buffer,
1138 i_start + p_title->i_cell_play_start_byte );
1140 p_title->p_cell_play = malloc( p_title->i_cell_nb
1141 *sizeof(cell_play_t) );
1143 if( p_title->p_cell_play == NULL )
1145 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1149 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1151 p_title->p_cell_play[i].i_category = ReadWord( p_ifo, pi_buffer, &p_current );
1152 p_title->p_cell_play[i].i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1153 p_title->p_cell_play[i].i_command_nb = ReadByte( p_ifo, pi_buffer, &p_current );
1154 p_title->p_cell_play[i].i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
1155 p_title->p_cell_play[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1156 p_title->p_cell_play[i].i_first_ilvu_vobu_esector =
1157 ReadDouble( p_ifo, pi_buffer, &p_current );
1158 p_title->p_cell_play[i].i_last_vobu_start_sector =
1159 ReadDouble( p_ifo, pi_buffer, &p_current );
1160 p_title->p_cell_play[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1164 /* Parsing of cell_pos_t */
1165 if( p_title->i_cell_pos_start_byte )
1167 p_current = FillBuffer( p_ifo, pi_buffer,
1168 i_start + p_title->i_cell_pos_start_byte );
1170 p_title->p_cell_pos = malloc( p_title->i_cell_nb
1171 *sizeof(cell_pos_t) );
1173 if( p_title->p_cell_pos == NULL )
1175 intf_ErrMsg( "ifo error: out of memory" );
1179 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1181 p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1182 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1183 p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1190 /*****************************************************************************
1191 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1192 *****************************************************************************/
1193 static int FreeTitle( title_t * p_title )
1195 if( p_title->i_command_start_byte )
1197 if( p_title->command.i_pre_command_nb )
1199 free( p_title->command.p_pre_command );
1202 if( p_title->command.i_post_command_nb )
1204 free( p_title->command.p_post_command );
1207 if( p_title->command.i_cell_command_nb )
1209 free( p_title->command.p_cell_command );
1212 if( p_title->i_chapter_map_start_byte )
1214 free( p_title->chapter_map.pi_start_cell );
1217 if( p_title->i_cell_play_start_byte )
1219 free( p_title->p_cell_play );
1222 if( p_title->i_cell_pos_start_byte )
1224 free( p_title->p_cell_pos );
1231 /*****************************************************************************
1232 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1233 *****************************************************************************/
1234 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf, off_t i_pos )
1236 u8 pi_buffer[DVD_LB_SIZE];
1241 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1243 i_start = p_ifo->i_pos;
1244 //fprintf( stderr, "Unit\n" );
1246 p_unit_inf->i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1247 //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb );
1248 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1249 p_unit_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1251 p_unit_inf->p_title =
1252 malloc( p_unit_inf->i_title_nb *sizeof(unit_title_t) );
1253 if( p_unit_inf->p_title == NULL )
1255 intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1259 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1261 p_unit_inf->p_title[i].i_category_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1262 p_unit_inf->p_title[i].i_category = ReadByte( p_ifo, pi_buffer, &p_current );
1263 //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 );
1264 p_unit_inf->p_title[i].i_parental_mask = ReadWord( p_ifo, pi_buffer, &p_current );
1265 p_unit_inf->p_title[i].i_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1268 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1270 //fprintf( stderr, "Unit: PGC %d @ %lld\n", i, p_ifo->i_pos );
1271 ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1272 p_unit_inf->p_title[i].i_title_start_byte );
1278 /*****************************************************************************
1279 * FreeUnitInf : frees a structure allocated by ReadUnit
1280 *****************************************************************************/
1281 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1283 if( p_unit_inf->p_title != NULL )
1285 free( p_unit_inf->p_title );
1292 /*****************************************************************************
1293 * ReadTitleUnit: Fills the Title Unit structure.
1294 *****************************************************************************/
1295 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1298 u8 pi_buffer[DVD_LB_SIZE];
1303 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1304 i_start = p_ifo->i_pos;
1305 //fprintf( stderr, "Unit Table\n" );
1307 p_title_unit->i_unit_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1308 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1309 p_title_unit->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1311 //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1313 p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb *sizeof(unit_t) );
1314 if( p_title_unit->p_unit == NULL )
1316 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1320 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1322 //ReadBits( p_ifo, pi_buffer, &p_current, p_title_unit->p_unit[i].ps_lang_code, 2 );
1323 p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, pi_buffer, &p_current );
1324 //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code );
1325 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1326 p_title_unit->p_unit[i].i_existence_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1327 p_title_unit->p_unit[i].i_unit_inf_start_byte =
1328 ReadDouble( p_ifo, pi_buffer, &p_current );
1331 p_title_unit->p_unit_inf =
1332 malloc( p_title_unit->i_unit_nb *sizeof(unit_inf_t) );
1333 if( p_title_unit->p_unit_inf == NULL )
1335 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1339 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1341 ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1342 p_title_unit->p_unit[i].i_unit_inf_start_byte );
1348 /*****************************************************************************
1349 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1350 *****************************************************************************/
1351 static int FreeTitleUnit( title_unit_t * p_title_unit )
1355 if( p_title_unit->p_unit_inf != NULL )
1357 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1359 FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1362 free( p_title_unit->p_unit_inf );
1368 /*****************************************************************************
1369 * ReadCellInf : Fills the Cell Information structure.
1370 *****************************************************************************/
1371 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, off_t i_pos )
1373 u8 pi_buffer[DVD_LB_SIZE];
1378 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1379 i_start = p_ifo->i_pos;
1380 //fprintf( stderr, "CELL ADD\n" );
1382 p_cell_inf->i_vob_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1383 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1384 p_cell_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1386 p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t);
1388 //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 );
1390 p_cell_inf->p_cell_map =
1391 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1392 if( p_cell_inf->p_cell_map == NULL )
1394 intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1398 for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1400 p_cell_inf->p_cell_map[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1401 p_cell_inf->p_cell_map[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1402 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1403 p_cell_inf->p_cell_map[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1404 // fprintf(stderr, "sector[%d] %d (%lld)\n", i,ntohl(*(u32*)(p_current)), p_ifo->i_pos);
1405 p_cell_inf->p_cell_map[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1411 /*****************************************************************************
1412 * FreeCellInf : frees structures allocated by ReadCellInf
1413 *****************************************************************************/
1414 static int FreeCellInf( cell_inf_t * p_cell_inf )
1416 free( p_cell_inf->p_cell_map );
1421 /*****************************************************************************
1422 * ReadVobuMap : Fills the VOBU Map structure.
1423 *****************************************************************************/
1424 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, off_t i_pos )
1426 u8 pi_buffer[DVD_LB_SIZE];
1431 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1432 i_start = p_ifo->i_pos;
1433 //fprintf( stderr, "VOBU ADMAP\n" );
1435 p_vobu_map->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1436 i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos )
1439 p_vobu_map->pi_vobu_start_sector = malloc( i_max *sizeof(u32) );
1440 if( p_vobu_map->pi_vobu_start_sector == NULL )
1442 intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1446 for( i = 0 ; i < i_max ; i++ )
1448 p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1454 /*****************************************************************************
1455 * FreeVobuMap: frees structures allocated by ReadVobuMap
1456 *****************************************************************************/
1457 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1459 free( p_vobu_map->pi_vobu_start_sector );
1465 * IFO virtual machine : a set of commands that give the
1466 * interactive behaviour of the dvd
1470 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1471 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1473 static char ifo_reg[][80]=
1475 "Menu_Language_Code",
1477 "SubPicture_Stream_#",
1483 "Highlighted_Button_#",
1486 "Karaoke_audio_mixing_mode",
1487 "Parental_mgmt_country_code",
1491 "Audio_language_code_setting",
1492 "Audio_language_extension_code",
1493 "SPU_language_code_setting",
1494 "SPU_language_extension_code",
1495 "?Player_Regional_Code",
1501 static char * IfoMath( char val )
1503 static char math_op[][10] =
1523 return (char *) math_op[val & 0x0f];
1527 char ifo_cmp[][10] =
1539 char ifo_parental[][10] =
1551 char ifo_menu_id[][80] =
1563 char * IfoMenuName( char index )
1565 return ifo_menu_id[index&0x07];
1568 static void IfoRegister( u16 i_data, u8 i_direct)
1572 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1574 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1578 printf("0x%02x", i_data);
1593 printf("s[%s]", ifo_reg[i_data]);
1606 printf("r[0x%02x]", i_data);
1612 static void IfoAdvanced( u8 *pi_code )
1614 u8 i_cmd = pi_code[0];
1620 printf( " Highlight button %d; ", pi_code[1]>>2 );
1625 printf( " Illegal " );
1630 printf( "ReSuME %d", pi_code[7] );
1632 else if( ( i_cmd & 0x06) == 0x02 )
1634 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1638 printf( "advanced (0x%02x) ", i_cmd );
1643 static void IfoJmp( ifo_command_t com )
1648 switch( com.i_sub_cmd )
1654 printf( "VTS 0x%02x", OP_VAL_8(3) );
1657 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1660 printf( "This VTS Title 0x%02x Part 0x%04x",
1662 OP_VAL_8(0)<<8|OP_VAL_8(1));
1666 printf ("in SystemSpace ");
1667 switch (OP_VAL_8(3)>>4) {
1669 printf ("to play first PGC");
1672 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1676 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1679 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1682 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1685 switch( OP_VAL_8(3)>>6 )
1688 printf( "to play first PGC" );
1691 printf( "to VMG title menu (?)" );
1694 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1697 IfoMenuName( OP_VAL_8(3)&0xF ) );
1700 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1707 switch(OP_VAL_8(3)>>4) {
1709 printf ("system first pgc");
1712 printf ("system title menu");
1715 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1718 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1721 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1724 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1728 // OP_VAL_8(2) is number of cell
1729 // it is processed BEFORE switch
1730 // under some conditions, it is ignored
1731 // I don't understand exactly what it means
1732 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1734 switch( OP_VAL_8(3)>>6 )
1737 printf( "to FP PGC" );
1740 printf( "to VMG root menu (?)" );
1743 printf( "to VTS menu \"%s\" (?)",
1744 IfoMenuName(OP_VAL_8(3)&0xF) );
1747 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1755 static void IfoLnk( ifo_command_t com )
1757 u16 i_button=OP_VAL_8(4)>>2;
1761 switch( com.i_sub_cmd )
1764 IfoAdvanced( &OP_VAL_8(4) );
1768 printf( "PGC 0x%02x", OP_VAL_16(2) );
1772 printf( "PTT 0x%02x", OP_VAL_16(2) );
1776 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1780 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1788 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1793 void IfoSetSystem( ifo_command_t com )
1800 for( i=1; i<=3; i++ )
1802 if( OP_VAL_8(i)&0x80 )
1806 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1810 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1816 if(OP_VAL_8(1]&0x80)
1817 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1818 if(OP_VAL_8(2)&0x80)
1819 //DENT: lwhat about 0x7f here ???
1820 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1821 if(OP_VAL_8(3)&0x80)
1822 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1824 if(OP_VAL_8(1)&0x80)
1825 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1826 if(OP_VAL_8(2)&0x80)
1827 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1828 if(OP_VAL_8(3)&0x80)
1829 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1837 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1841 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1844 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1845 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1850 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1854 printf ("r[r[0x%02x]] = r[0x%02x]",
1855 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1859 //actually only bits 00011100 00011100 are set
1862 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1866 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1871 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1872 //but it is way too ugly
1875 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1879 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1887 static void IfoSet( ifo_command_t com )
1889 IfoRegister( OP_VAL_16(0), 0 );
1890 printf( " %s ", IfoMath( com.i_cmd ) );
1891 IfoRegister( OP_VAL_16(1), com.i_direct );
1894 /*****************************************************************************
1895 * CommandRead : translates the command strings in ifo into command
1897 *****************************************************************************/
1898 void CommandRead( ifo_command_t com )
1900 u8* pi_code = (u8*)(&com);
1902 switch( com.i_type )
1915 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1916 ifo_cmp[com.i_cmp]);
1917 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1922 switch( com.i_sub_cmd )
1925 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1929 printf( "stop VM" );
1933 printf( "Set Parental Level To %s and goto Line 0x%02x",
1934 ifo_parental[OP_VAL_8(4)&0x7],
1939 printf( "Illegal" );
1958 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1959 ifo_cmp[com.i_cmp] );
1960 IfoRegister( OP_VAL_8(5), 0 );
1971 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1972 ifo_cmp[com.i_cmp] );
1973 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1987 IfoSetSystem( com );
1989 else if( com.i_cmp && !com.i_sub_cmd )
1991 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1992 IfoRegister( OP_VAL_8(5), 0 );
1994 IfoSetSystem( com );
1996 else if( !com.i_cmp && com.i_sub_cmd )
1999 IfoSetSystem( com );
2015 else if( com.i_cmp && !com.i_sub_cmd )
2017 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
2018 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
2022 else if( !com.i_cmp && com.i_sub_cmd )
2036 * math command on r[opcode[1]] and
2037 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
2038 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
2040 * boolean operation cmp on r[opcode[1]] and
2041 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
2042 * on true result, buttons(c[6], c[7]) is called
2043 * problem is 'what is buttons()'
2046 printf( "r[0x%X] ", pi_code[1] );
2047 printf( " %s ", IfoMath( com.i_cmd ) );
2048 if( com.i_cmd == 2 )
2050 printf( "r[0x%X] ", OP_VAL_8(1) );
2054 IfoRegister( OP_VAL_16(0), com.i_direct );
2058 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
2059 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
2060 printf( " ) then {" );
2061 IfoAdvanced( &OP_VAL_8(4) );
2066 * opposite to case 4: boolean, math and buttons.
2072 if( !com.i_direct && com.i_dir_cmp )
2074 printf( "0x%X", OP_VAL_16(1) );
2078 IfoRegister( OP_VAL_8(3), 0 );
2079 if( OP_VAL_8(3)&0x80 )
2081 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2085 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2086 // 0x1F is either not a mistake,
2087 // or Microsoft programmer's mistake!!!
2091 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2092 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2093 printf( " ) then {" );
2094 printf( "r[0x%X] ", pi_code[1] & 0xF );
2095 printf( " %s ", IfoMath( com.i_cmd ) );
2097 if( com.i_cmd == 0x02 ) // swap
2099 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2105 printf( "0x%X", OP_VAL_16(0) );
2109 if( OP_VAL_8(0) & 0x80 )
2111 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2115 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2121 IfoAdvanced( &OP_VAL_8(4) );
2127 printf( "Unknown Command\n" );
2134 /*****************************************************************************
2135 * CommandPrint : print in clear text (I hope so !) what a command does
2136 *****************************************************************************/
2137 void CommandPrint( ifo_t ifo )