1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.22 2001/04/15 21:17:50 stef 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 *****************************************************************************/
47 #include "input_dvd.h"
52 void CommandRead ( command_desc_t );
53 static int ReadTitle ( ifo_t * , title_t *, off_t );
54 static int FreeTitle ( title_t * );
55 static int ReadUnitInf ( ifo_t * , unit_inf_t *, off_t );
56 static int FreeUnitInf ( unit_inf_t * );
57 static int ReadTitleUnit ( ifo_t * , title_unit_t *, off_t );
58 static int FreeTitleUnit ( title_unit_t * );
59 static int ReadVobuMap ( ifo_t * , vobu_map_t *, off_t );
60 static int FreeVobuMap ( vobu_map_t * );
61 static int ReadCellInf ( ifo_t * , cell_inf_t *, off_t );
62 static int FreeCellInf ( cell_inf_t * );
63 static int FreeTitleSet ( vts_t * );
65 /*****************************************************************************
67 *****************************************************************************/
68 static __inline__ u8* FillBuffer( ifo_t* p_ifo, u8* pi_buffer, off_t i_pos )
70 memset( pi_buffer, 0, DVD_LB_SIZE );
71 p_ifo->i_pos = lseek( p_ifo->i_fd, i_pos, SEEK_SET );
72 read( p_ifo->i_fd, pi_buffer, DVD_LB_SIZE );
77 static __inline__ u8 ReadByte( ifo_t * p_ifo, u8* pi_buffer, u8** pp_current )
81 if( *pp_current > pi_buffer + DVD_LB_SIZE )
83 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
86 i_ret = *(*pp_current)++;
91 static __inline__ u16 ReadWord( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
95 if( *pp_current > pi_buffer + DVD_LB_SIZE - 2 )
97 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
100 i_ret = U16_AT(*pp_current);
106 static __inline__ u32 ReadDouble( ifo_t * p_ifo, u8* pi_buffer,
111 if( *pp_current > pi_buffer + DVD_LB_SIZE - 4 )
113 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE);
114 // intf_WarnMsg( 1, "new buffer in double @ %lld", p_ifo->i_pos );
117 i_ret = U32_AT(*pp_current);
123 static __inline__ u64 ReadQuad( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
127 if( *pp_current > pi_buffer + DVD_LB_SIZE - 8 )
129 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
132 i_ret = U64_AT(*pp_current);
138 static __inline__ void ReadBits( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current,
139 u8* pi_dest, int i_nb )
141 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
143 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
146 memcpy( pi_dest, *pp_current, i_nb );
152 static __inline__ void DumpBits( ifo_t* p_ifo, u8* pi_buffer,
153 u8** pp_current, 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 );
168 /*****************************************************************************
169 * IfoCreate : Creates an ifo structure and prepares for parsing directly
171 *****************************************************************************/
172 int IfoCreate( thread_dvd_data_t * p_dvd )
174 p_dvd->p_ifo = malloc( sizeof(ifo_t) );
175 if( p_dvd->p_ifo == NULL )
177 intf_ErrMsg( "ifo error: unable to allocate memory. aborting" );
181 /* if we are here the dvd device has already been opened */
182 p_dvd->p_ifo->i_fd = p_dvd->i_fd;
187 /*****************************************************************************
188 * IfoInit : Reads information from the management table.
189 *****************************************************************************/
190 int IfoInit( ifo_t * p_ifo )
192 u8 pi_buffer[DVD_LB_SIZE];
199 /* find the start sector of video information on the dvd */
200 i_lba = UDFFindFile( p_ifo->i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
202 p_ifo->i_off = (off_t)(i_lba) * DVD_LB_SIZE;
204 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off );
205 //i_start = p_ifo->i_pos;
207 * read the video manager information table
209 #define manager_inf p_ifo->vmg.manager_inf
210 //fprintf( stderr, "VMGI\n" );
212 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id, 12 );
213 manager_inf.psz_id[12] = '\0';
214 manager_inf.i_vmg_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
215 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
216 manager_inf.i_vmg_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
217 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
218 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
219 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
220 manager_inf.i_volume_nb = ReadWord( p_ifo, pi_buffer, &p_current );
221 manager_inf.i_volume = ReadWord( p_ifo, pi_buffer, &p_current );
222 manager_inf.i_disc_side = ReadByte( p_ifo, pi_buffer, &p_current );
223 DumpBits( p_ifo, pi_buffer, &p_current, 19 );
224 manager_inf.i_title_set_nb = ReadWord( p_ifo, pi_buffer, &p_current );
225 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.ps_provider_id, 32 );
226 manager_inf.i_pos_code = ReadQuad( p_ifo, pi_buffer, &p_current );
227 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
228 manager_inf.i_vmg_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
229 manager_inf.i_first_play_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
230 DumpBits( p_ifo, pi_buffer, &p_current, 56 );
231 manager_inf.i_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
232 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
233 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
234 manager_inf.i_parental_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
235 manager_inf.i_vts_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
236 manager_inf.i_text_data_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
237 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
238 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
239 DumpBits( p_ifo, pi_buffer, &p_current, 32 );
240 // GETS( &manager_inf.video_atrt );
241 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
242 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
243 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
244 //fprintf( stderr, "vmgi audio nb : %d\n", manager_inf.i_audio_nb );
245 for( i=0 ; i < 8 ; i++ )
247 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
249 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
250 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
251 //fprintf( stderr, "vmgi subpic nb : %d\n", manager_inf.i_spu_nb );
252 for( i=0 ; i < manager_inf.i_spu_nb ; i++ )
254 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
255 /* FIXME : take care of endianness */
259 * read first play title.
261 if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_off +
262 manager_inf.i_first_play_title_start_byte ) < 0 )
268 * fills the title information structure.
270 #define title_inf p_ifo->vmg.title_inf
271 if( manager_inf.i_title_inf_start_sector )
273 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
274 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
275 //fprintf( stderr, "title inf %lld\n", p_ifo->i_pos );
277 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
278 //fprintf( stderr, "title_inf: TTU nb %d\n", title_inf.i_title_nb );
279 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
280 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
282 /* parsing of title attributes */
283 title_inf.p_attr = malloc( title_inf.i_title_nb *sizeof(title_attr_t) );
284 if( title_inf.p_attr == NULL )
286 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
290 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
292 title_inf.p_attr[i].i_play_type = ReadByte( p_ifo, pi_buffer, &p_current );
293 title_inf.p_attr[i].i_angle_nb = ReadByte( p_ifo, pi_buffer, &p_current );
294 title_inf.p_attr[i].i_chapter_nb = ReadWord( p_ifo, pi_buffer, &p_current );
295 title_inf.p_attr[i].i_parental_id = ReadWord( p_ifo, pi_buffer, &p_current );
296 title_inf.p_attr[i].i_title_set_num = ReadByte( p_ifo, pi_buffer, &p_current );
297 title_inf.p_attr[i].i_title_num = ReadByte( p_ifo, pi_buffer, &p_current );
298 title_inf.p_attr[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
299 //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 );
304 title_inf.p_attr = NULL;
309 * fills the title unit structure.
311 if( manager_inf.i_title_unit_start_sector )
313 if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_off +
314 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
321 * fills the structure about parental information.
323 #define parental p_ifo->vmg.parental_inf
324 if( manager_inf.i_parental_inf_start_sector )
326 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
327 manager_inf.i_parental_inf_start_sector *DVD_LB_SIZE );
328 i_start = p_ifo->i_pos;
330 //fprintf( stderr, "PTL\n" );
332 parental.i_country_nb = ReadWord( p_ifo, pi_buffer, &p_current );
333 parental.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );
334 parental.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
336 parental.p_parental_desc = malloc( parental.i_country_nb *
337 sizeof(parental_desc_t) );
338 if( parental.p_parental_desc == NULL )
340 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
344 for( i = 0 ; i < parental.i_country_nb ; i++ )
346 ReadBits( p_ifo, pi_buffer, &p_current,
347 parental.p_parental_desc[i].ps_country_code, 2 );
348 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
349 parental.p_parental_desc[i].i_parental_mask_start_byte =
350 ReadWord( p_ifo, pi_buffer, &p_current );
351 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
354 parental.p_parental_mask = malloc( parental.i_country_nb *
355 sizeof(parental_mask_t) );
356 if( parental.p_parental_mask == NULL )
358 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
362 for( i = 0 ; i < parental.i_country_nb ; i++ )
364 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
365 parental.p_parental_desc[i].i_parental_mask_start_byte );
366 for( j = 0 ; j < 8 ; j++ )
368 parental.p_parental_mask[i].ppi_mask[j] =
369 malloc( ( parental.i_vts_nb + 1 ) *sizeof(u16) );
370 if( parental.p_parental_mask[i].ppi_mask[j] == NULL )
372 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
375 for( k = 0 ; k < parental.i_vts_nb + 1 ; k++ )
377 parental.p_parental_mask[i].ppi_mask[j][k] =
378 ReadWord( p_ifo, pi_buffer, &p_current );
386 * information and attributes about for each vts.
388 #define vts_inf p_ifo->vmg.vts_inf
389 if( manager_inf.i_vts_inf_start_sector )
393 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
394 manager_inf.i_vts_inf_start_sector *DVD_LB_SIZE );
395 i_start = p_ifo->i_pos;
397 //fprintf( stderr, "VTS ATTR\n" );
399 vts_inf.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
400 //fprintf( stderr, "VTS ATTR Nb: %d\n", vts_inf.i_vts_nb );
401 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
402 vts_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
403 vts_inf.pi_vts_attr_start_byte =
404 malloc( vts_inf.i_vts_nb *sizeof(u32) );
405 if( vts_inf.pi_vts_attr_start_byte == NULL )
407 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
411 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
413 vts_inf.pi_vts_attr_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
416 vts_inf.p_vts_attr = malloc( vts_inf.i_vts_nb *sizeof(vts_attr_t) );
417 if( vts_inf.p_vts_attr == NULL )
419 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
423 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
425 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
426 vts_inf.pi_vts_attr_start_byte[i] );
427 vts_inf.p_vts_attr[i].i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
428 vts_inf.p_vts_attr[i].i_cat_app_type = ReadDouble( p_ifo, pi_buffer, &p_current );
429 // GETS( &vts_inf.p_vts_attr[i].vts_menu_video_attr );
430 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
431 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
432 vts_inf.p_vts_attr[i].i_vts_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
433 //fprintf( stderr, "m audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_audio_nb );
434 for( j = 0 ; j < 8 ; j++ )
436 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
438 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
439 vts_inf.p_vts_attr[i].i_vts_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
440 //fprintf( stderr, "m subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_spu_nb );
441 for( j = 0 ; j < 28 ; j++ )
443 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
444 /* FIXME : Fix endianness issue here */
446 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
447 // GETS( &vts_inf.p_vts_attr[i].vtstt_video_vts_inf );
448 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
449 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
450 vts_inf.p_vts_attr[i].i_vts_title_audio_nb =
451 ReadDouble( p_ifo, pi_buffer, &p_current );
452 //fprintf( stderr, "tt audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_audio_nb );
453 for( j = 0 ; j < 8 ; j++ )
455 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
457 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
458 vts_inf.p_vts_attr[i].i_vts_title_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
459 //fprintf( stderr, "tt subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_spu_nb );
460 for( j=0 ; j<28/*vts_inf.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
462 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
463 /* FIXME : Fix endianness issue here */
472 if( manager_inf.i_cell_inf_start_sector )
474 if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_off +
475 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
482 * global vob unit map.
484 if( manager_inf.i_vobu_map_start_sector )
486 if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_off +
487 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
494 p_ifo->vts.b_initialized = 0;
496 intf_WarnMsg( 1, "ifo info: vmg initialized" );
501 /*****************************************************************************
502 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
503 *****************************************************************************/
504 int IfoTitleSet( ifo_t * p_ifo )
506 u8 pi_buffer[DVD_LB_SIZE];
513 if( p_ifo->vts.b_initialized )
515 FreeTitleSet( &p_ifo->vts );
519 (off_t)( p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_start_sector )
523 //fprintf(stderr, "offset: %lld\n" , i_off );
525 p_current = FillBuffer( p_ifo, pi_buffer, i_off );
526 //i_start = p_ifo->i_pos;
527 p_ifo->vts.i_pos = p_ifo->i_pos;
529 #define manager_inf p_ifo->vts.manager_inf
531 * reads manager information
533 //fprintf( stderr, "VTSI\n" );
535 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id , 12 );
536 manager_inf.psz_id[12] = '\0';
537 manager_inf.i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
538 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
539 manager_inf.i_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
540 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
541 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
542 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
543 DumpBits( p_ifo, pi_buffer, &p_current, 90 );
544 manager_inf.i_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
545 DumpBits( p_ifo, pi_buffer, &p_current, 60 );
546 manager_inf.i_menu_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
547 manager_inf.i_title_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
548 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
549 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
550 manager_inf.i_menu_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
551 manager_inf.i_time_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
552 manager_inf.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
553 manager_inf.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
554 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
555 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
556 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
557 // GETS( &manager_inf.m_video_atrt );
558 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
559 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
560 manager_inf.i_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
561 for( i = 0 ; i < 8 ; i++ )
563 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
565 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
566 manager_inf.i_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
567 for( i = 0 ; i < 28 ; i++ )
569 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
570 /* FIXME : take care of endianness */
572 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
573 // GETS( &manager_inf.video_atrt );
574 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
575 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
576 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
577 //fprintf( stderr, "vtsi audio nb : %d\n", manager_inf.i_audio_nb );
578 for( i = 0 ; i < 8 ; i++ )
580 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
581 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
583 manager_inf.p_audio_attr[i].i_bar = i_temp & 0xff;
585 manager_inf.p_audio_attr[i].i_caption = i_temp & 0xff;
587 manager_inf.p_audio_attr[i].i_foo = i_temp & 0xff;
589 manager_inf.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
591 manager_inf.p_audio_attr[i].i_num_channels = i_temp & 0x7;
593 manager_inf.p_audio_attr[i].i_test = i_temp & 0x1;
595 manager_inf.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
597 manager_inf.p_audio_attr[i].i_quantization = i_temp & 0x3;
599 manager_inf.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
601 manager_inf.p_audio_attr[i].i_type = i_temp & 0x3;
603 manager_inf.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
605 manager_inf.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
607 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
608 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
609 //fprintf( stderr, "vtsi subpic nb : %d\n", manager_inf.i_spu_nb );
610 for( i=0 ; i<manager_inf.i_spu_nb ; i++ )
612 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
613 i_temp = hton64( i_temp ) >> 16;
614 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
615 manager_inf.p_spu_attr[i].i_caption = i_temp & 0xff;
617 manager_inf.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
619 manager_inf.p_spu_attr[i].i_prefix = i_temp & 0xffff;
623 * reads title information: set of pointers to title
625 #define title_inf p_ifo->vts.title_inf
626 if( manager_inf.i_title_inf_start_sector )
628 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
629 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
631 i_start = p_ifo->i_pos;
633 //fprintf( stderr, "VTS PTR\n" );
635 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
636 //fprintf( stderr, "VTS title_inf nb: %d\n", title_inf.i_title_nb );
637 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
638 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
640 title_inf.pi_start_byte = malloc( title_inf.i_title_nb *sizeof(u32) );
641 if( title_inf.pi_start_byte == NULL )
643 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
647 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
649 title_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
653 title_inf.p_title_start = malloc( title_inf.i_title_nb
654 *sizeof(title_start_t) );
655 if( title_inf.p_title_start == NULL )
657 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
661 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
663 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
664 title_inf.pi_start_byte[i] );
666 title_inf.p_title_start[i].i_program_chain_num =
667 ReadWord( p_ifo, pi_buffer, &p_current );
668 title_inf.p_title_start[i].i_program_num = ReadWord( p_ifo, pi_buffer, &p_current );
669 //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 );
675 * menu unit information
677 if( manager_inf.i_menu_unit_start_sector )
679 if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
680 manager_inf.i_menu_unit_start_sector *DVD_LB_SIZE ) < 0 )
687 * title unit information
689 if( manager_inf.i_title_unit_start_sector )
691 if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
692 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
699 * time map inforamtion
701 #define time_inf p_ifo->vts.time_inf
702 if( manager_inf.i_time_inf_start_sector )
704 u8 pi_buffer[DVD_LB_SIZE];
706 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
707 manager_inf.i_time_inf_start_sector *DVD_LB_SIZE );
709 //fprintf( stderr, "TMAP\n" );
711 time_inf.i_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
712 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
713 time_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
715 time_inf.pi_start_byte = malloc( time_inf.i_nb *sizeof(u32) );
716 if( time_inf.pi_start_byte == NULL )
718 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
722 for( i = 0 ; i < time_inf.i_nb ; i++ )
724 time_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
727 time_inf.p_time_map = malloc( time_inf.i_nb *sizeof(time_map_t) );
728 if( time_inf.p_time_map == NULL )
730 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
734 for( i = 0 ; i < time_inf.i_nb ; i++ )
736 time_inf.p_time_map[i].i_time_unit = ReadByte( p_ifo, pi_buffer, &p_current );
737 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
738 time_inf.p_time_map[i].i_entry_nb = ReadWord( p_ifo, pi_buffer, &p_current );
740 time_inf.p_time_map[i].pi_sector =
741 malloc( time_inf.p_time_map[i].i_entry_nb *sizeof(u32) );
742 if( time_inf.p_time_map[i].pi_sector == NULL )
744 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
748 for( j = 0 ; j < time_inf.p_time_map[i].i_entry_nb ; j++ )
750 time_inf.p_time_map[i].pi_sector[j] = ReadDouble( p_ifo, pi_buffer, &p_current );
756 if( manager_inf.i_menu_cell_inf_start_sector )
758 if( ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
759 manager_inf.i_menu_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
765 if( manager_inf.i_menu_vobu_map_start_sector )
767 if( ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
768 manager_inf.i_menu_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
774 if( manager_inf.i_cell_inf_start_sector )
776 if( ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
777 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) )
783 if( manager_inf.i_vobu_map_start_sector )
785 if( ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
786 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) )
793 intf_WarnMsg( 2, "ifo info: vts %d initialized",
794 p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_title_set_num );
796 p_ifo->vts.b_initialized = 1;
801 /*****************************************************************************
802 * FreeTitleSet : free all structures allocated by IfoTitleSet
803 *****************************************************************************/
804 static int FreeTitleSet( vts_t * p_vts )
808 if( p_vts->manager_inf.i_vobu_map_start_sector )
810 FreeVobuMap( &p_vts->vobu_map );
813 if( p_vts->manager_inf.i_cell_inf_start_sector )
815 FreeCellInf( &p_vts->cell_inf );
818 if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
820 FreeVobuMap( &p_vts->menu_vobu_map );
823 if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
825 FreeCellInf( &p_vts->menu_cell_inf );
828 if( p_vts->manager_inf.i_time_inf_start_sector )
830 for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
832 free( p_vts->time_inf.p_time_map[i].pi_sector );
835 free( p_vts->time_inf.p_time_map );
836 free( p_vts->time_inf.pi_start_byte );
839 if( p_vts->manager_inf.i_title_unit_start_sector )
841 FreeUnitInf( &p_vts->title_unit );
844 if( p_vts->manager_inf.i_menu_unit_start_sector )
846 FreeTitleUnit( &p_vts->menu_unit );
849 if( p_vts->manager_inf.i_title_inf_start_sector )
851 free( p_vts->title_inf.pi_start_byte );
852 free( p_vts->title_inf.p_title_start );
855 p_vts->b_initialized = 0;
860 /*****************************************************************************
861 * IfoDestroy : Frees all the memory allocated to ifo structures
862 *****************************************************************************/
863 void IfoDestroy( ifo_t * p_ifo )
867 FreeTitleSet( &p_ifo->vts );
869 if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
871 FreeVobuMap( &p_ifo->vmg.vobu_map );
874 if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
876 FreeCellInf( &p_ifo->vmg.cell_inf );
879 if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
881 free( p_ifo->vmg.vts_inf.p_vts_attr );
882 free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
885 /* free parental information structures */
886 if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
888 for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
890 for( j = 0 ; j < 8 ; j++ )
892 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
896 free( p_ifo->vmg.parental_inf.p_parental_mask );
897 free( p_ifo->vmg.parental_inf.p_parental_desc );
900 if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
902 FreeTitleUnit( &p_ifo->vmg.title_unit );
905 if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
907 free( p_ifo->vmg.title_inf.p_attr );
910 FreeTitle( &p_ifo->vmg.title );
917 * Function common to Video Manager and Video Title set Processing
920 /*****************************************************************************
921 * ReadTitle : Fills the title structure.
922 *****************************************************************************
923 * Titles are logical stream units that correspond to a whole inside the dvd.
924 * Several title can point to the same part of the physical DVD, and give
925 * map to different anglesfor instance.
926 *****************************************************************************/
927 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, off_t i_pos )
929 u8 pi_buffer[DVD_LB_SIZE];
934 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
936 i_start = p_ifo->i_pos;
938 //fprintf( stderr, "PGC @ %lld\n",p_ifo->i_pos );
940 DumpBits( p_ifo, pi_buffer, &p_current, 2);
941 p_title->i_chapter_nb = ReadByte( p_ifo, pi_buffer, &p_current );
942 p_title->i_cell_nb = ReadByte( p_ifo, pi_buffer, &p_current );
943 //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb );
944 p_title->i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
945 p_title->i_prohibited_user_op = ReadDouble( p_ifo, pi_buffer, &p_current );
946 for( i = 0 ; i < 8 ; i++ )
948 p_title->pi_audio_status[i] = ReadWord( p_ifo, pi_buffer, &p_current );
950 for( i = 0 ; i < 32 ; i++ )
952 p_title->pi_subpic_status[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
954 p_title->i_next_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
955 p_title->i_prev_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
956 p_title->i_go_up_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
957 //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 );
958 p_title->i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
959 p_title->i_play_mode = ReadByte( p_ifo, pi_buffer, &p_current );
960 for( i = 0 ; i < 16 ; i++ )
962 p_title->pi_yuv_color[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
963 /* FIXME : We have to erase the extra bit */
965 p_title->i_command_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
966 p_title->i_chapter_map_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
967 p_title->i_cell_play_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
968 p_title->i_cell_pos_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
970 /* parsing of command_t */
971 if( p_title->i_command_start_byte )
973 p_current = FillBuffer( p_ifo, pi_buffer,
974 i_start + p_title->i_command_start_byte );
977 p_title->command.i_pre_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
978 p_title->command.i_post_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
979 p_title->command.i_cell_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
980 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
982 /* pre-title commands */
983 if( p_title->command.i_pre_command_nb )
985 p_title->command.p_pre_command =
986 malloc( p_title->command.i_pre_command_nb
987 *sizeof(command_desc_t) );
989 if( p_title->command.p_pre_command == NULL )
991 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
995 for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
997 p_title->command.p_pre_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1002 p_title->command.p_pre_command = NULL;
1005 /* post-title commands */
1006 if( p_title->command.i_post_command_nb )
1008 p_title->command.p_post_command =
1009 malloc( p_title->command.i_post_command_nb
1010 *sizeof(command_desc_t) );
1012 if( p_title->command.p_post_command == NULL )
1014 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1018 for( i=0 ; i<p_title->command.i_post_command_nb ; i++ )
1020 p_title->command.p_post_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1025 p_title->command.p_post_command = NULL;
1029 if( p_title->command.i_cell_command_nb )
1031 p_title->command.p_cell_command =
1032 malloc( p_title->command.i_cell_command_nb
1033 *sizeof(command_desc_t) );
1035 if( p_title->command.p_cell_command == NULL )
1037 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1041 for( i=0 ; i<p_title->command.i_cell_command_nb ; i++ )
1043 p_title->command.p_cell_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1048 p_title->command.p_cell_command = NULL;
1052 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1053 if( p_title->i_chapter_map_start_byte )
1055 p_ifo->i_pos = lseek( p_ifo->i_fd,
1056 i_start + p_title->i_chapter_map_start_byte,
1059 p_title->chapter_map.pi_start_cell =
1060 malloc( p_title->i_chapter_nb *sizeof(chapter_map_t) );
1062 if( p_title->chapter_map.pi_start_cell == NULL )
1064 intf_ErrMsg( "ifo error: out of memory in Read Title" );
1068 ReadBits( p_ifo, pi_buffer, &p_current, p_title->chapter_map.pi_start_cell,
1069 p_title->i_chapter_nb );
1073 p_title->chapter_map.pi_start_cell = NULL;
1076 /* parsing of cell_play_t */
1077 if( p_title->i_cell_play_start_byte )
1079 p_current = FillBuffer( p_ifo, pi_buffer,
1080 i_start + p_title->i_cell_play_start_byte );
1082 p_title->p_cell_play = malloc( p_title->i_cell_nb
1083 *sizeof(cell_play_t) );
1085 if( p_title->p_cell_play == NULL )
1087 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1091 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1093 p_title->p_cell_play[i].i_category = ReadWord( p_ifo, pi_buffer, &p_current );
1094 p_title->p_cell_play[i].i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1095 p_title->p_cell_play[i].i_command_nb = ReadByte( p_ifo, pi_buffer, &p_current );
1096 p_title->p_cell_play[i].i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
1097 p_title->p_cell_play[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1098 p_title->p_cell_play[i].i_first_ilvu_vobu_esector =
1099 ReadDouble( p_ifo, pi_buffer, &p_current );
1100 p_title->p_cell_play[i].i_last_vobu_start_sector =
1101 ReadDouble( p_ifo, pi_buffer, &p_current );
1102 p_title->p_cell_play[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1106 /* Parsing of cell_pos_t */
1107 if( p_title->i_cell_pos_start_byte )
1109 p_current = FillBuffer( p_ifo, pi_buffer,
1110 i_start + p_title->i_cell_pos_start_byte );
1112 p_title->p_cell_pos = malloc( p_title->i_cell_nb
1113 *sizeof(cell_pos_t) );
1115 if( p_title->p_cell_pos == NULL )
1117 intf_ErrMsg( "ifo error: out of memory" );
1121 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1123 p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1124 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1125 p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1132 /*****************************************************************************
1133 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1134 *****************************************************************************/
1135 static int FreeTitle( title_t * p_title )
1137 if( p_title->i_command_start_byte )
1139 if( p_title->command.i_pre_command_nb )
1141 free( p_title->command.p_pre_command );
1144 if( p_title->command.i_post_command_nb )
1146 free( p_title->command.p_post_command );
1149 if( p_title->command.i_cell_command_nb )
1151 free( p_title->command.p_cell_command );
1154 if( p_title->i_chapter_map_start_byte )
1156 free( p_title->chapter_map.pi_start_cell );
1159 if( p_title->i_cell_play_start_byte )
1161 free( p_title->p_cell_play );
1164 if( p_title->i_cell_pos_start_byte )
1166 free( p_title->p_cell_pos );
1173 /*****************************************************************************
1174 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1175 *****************************************************************************/
1176 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf, off_t i_pos )
1178 u8 pi_buffer[DVD_LB_SIZE];
1183 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1185 i_start = p_ifo->i_pos;
1186 //fprintf( stderr, "Unit\n" );
1188 p_unit_inf->i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1189 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1190 p_unit_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1192 p_unit_inf->p_title =
1193 malloc( p_unit_inf->i_title_nb *sizeof(unit_title_t) );
1194 if( p_unit_inf->p_title == NULL )
1196 intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1200 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1202 p_unit_inf->p_title[i].i_category_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1203 p_unit_inf->p_title[i].i_category = ReadByte( p_ifo, pi_buffer, &p_current );
1204 p_unit_inf->p_title[i].i_parental_mask = ReadWord( p_ifo, pi_buffer, &p_current );
1205 p_unit_inf->p_title[i].i_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1208 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1210 //fprintf( stderr, "Unit: PGC %d @ %lld\n", i, p_ifo->i_pos );
1211 ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1212 p_unit_inf->p_title[i].i_title_start_byte );
1218 /*****************************************************************************
1219 * FreeUnitInf : frees a structure allocated by ReadUnit
1220 *****************************************************************************/
1221 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1223 if( p_unit_inf->p_title != NULL )
1225 free( p_unit_inf->p_title );
1232 /*****************************************************************************
1233 * ReadTitleUnit: Fills the Title Unit structure.
1234 *****************************************************************************/
1235 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1238 u8 pi_buffer[DVD_LB_SIZE];
1243 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1244 i_start = p_ifo->i_pos;
1245 //fprintf( stderr, "Unit Table\n" );
1247 p_title_unit->i_unit_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1248 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1249 p_title_unit->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1251 //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1253 p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb *sizeof(unit_t) );
1254 if( p_title_unit->p_unit == NULL )
1256 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1260 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1262 ReadBits( p_ifo, pi_buffer, &p_current, p_title_unit->p_unit[i].ps_lang_code, 2 );
1263 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1264 p_title_unit->p_unit[i].i_existence_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1265 p_title_unit->p_unit[i].i_unit_inf_start_byte =
1266 ReadDouble( p_ifo, pi_buffer, &p_current );
1269 p_title_unit->p_unit_inf =
1270 malloc( p_title_unit->i_unit_nb *sizeof(unit_inf_t) );
1271 if( p_title_unit->p_unit_inf == NULL )
1273 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1277 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1279 ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1280 p_title_unit->p_unit[i].i_unit_inf_start_byte );
1286 /*****************************************************************************
1287 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1288 *****************************************************************************/
1289 static int FreeTitleUnit( title_unit_t * p_title_unit )
1293 if( p_title_unit->p_unit_inf != NULL )
1295 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1297 FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1300 free( p_title_unit->p_unit_inf );
1306 /*****************************************************************************
1307 * ReadCellInf : Fills the Cell Information structure.
1308 *****************************************************************************/
1309 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, off_t i_pos )
1311 u8 pi_buffer[DVD_LB_SIZE];
1316 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1317 i_start = p_ifo->i_pos;
1318 //fprintf( stderr, "CELL ADD\n" );
1320 p_cell_inf->i_vob_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1321 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1322 p_cell_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1324 p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t);
1326 //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 );
1328 p_cell_inf->p_cell_map =
1329 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1330 if( p_cell_inf->p_cell_map == NULL )
1332 intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1336 for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1338 p_cell_inf->p_cell_map[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1339 p_cell_inf->p_cell_map[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1340 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1341 p_cell_inf->p_cell_map[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1342 // fprintf(stderr, "sector[%d] %d (%lld)\n", i,ntohl(*(u32*)(p_current)), p_ifo->i_pos);
1343 p_cell_inf->p_cell_map[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1349 /*****************************************************************************
1350 * FreeCellInf : frees structures allocated by ReadCellInf
1351 *****************************************************************************/
1352 static int FreeCellInf( cell_inf_t * p_cell_inf )
1354 free( p_cell_inf->p_cell_map );
1359 /*****************************************************************************
1360 * ReadVobuMap : Fills the VOBU Map structure.
1361 *****************************************************************************/
1362 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, off_t i_pos )
1364 u8 pi_buffer[DVD_LB_SIZE];
1369 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1370 i_start = p_ifo->i_pos;
1371 //fprintf( stderr, "VOBU ADMAP\n" );
1373 p_vobu_map->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1374 i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos )
1377 p_vobu_map->pi_vobu_start_sector = malloc( i_max *sizeof(u32) );
1378 if( p_vobu_map->pi_vobu_start_sector == NULL )
1380 intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1384 for( i = 0 ; i < i_max ; i++ )
1386 p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1392 /*****************************************************************************
1393 * FreeVobuMap: frees structures allocated by ReadVobuMap
1394 *****************************************************************************/
1395 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1397 free( p_vobu_map->pi_vobu_start_sector );
1403 * IFO virtual machine : a set of commands that give the
1404 * interactive behaviour of the dvd
1408 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1409 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1411 static char ifo_reg[][80]=
1413 "Menu_Language_Code",
1415 "SubPicture_Stream_#",
1421 "Highlighted_Button_#",
1424 "Karaoke_audio_mixing_mode",
1425 "Parental_mgmt_country_code",
1429 "Audio_language_code_setting",
1430 "Audio_language_extension_code",
1431 "SPU_language_code_setting",
1432 "SPU_language_extension_code",
1433 "?Player_Regional_Code",
1439 static char * IfoMath( char val )
1441 static char math_op[][10] =
1461 return (char *) math_op[val & 0x0f];
1465 char ifo_cmp[][10] =
1477 char ifo_parental[][10] =
1489 char ifo_menu_id[][80] =
1501 char * IfoMenuName( char index )
1503 return ifo_menu_id[index&0x07];
1506 static void IfoRegister( u16 i_data, u8 i_direct)
1510 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1512 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1516 printf("0x%02x", i_data);
1531 printf("s[%s]", ifo_reg[i_data]);
1544 printf("r[0x%02x]", i_data);
1550 static void IfoAdvanced( u8 *pi_code )
1552 u8 i_cmd = pi_code[0];
1558 printf( " Highlight button %d; ", pi_code[1]>>2 );
1563 printf( " Illegal " );
1568 printf( "ReSuME %d", pi_code[7] );
1570 else if( ( i_cmd & 0x06) == 0x02 )
1572 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1576 printf( "advanced (0x%02x) ", i_cmd );
1581 static void IfoJmp( ifo_command_t com )
1586 switch( com.i_sub_cmd )
1592 printf( "VTS 0x%02x", OP_VAL_8(3) );
1595 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1598 printf( "This VTS Title 0x%02x Part 0x%04x",
1600 OP_VAL_8(0)<<8|OP_VAL_8(1));
1604 printf ("in SystemSpace ");
1605 switch (OP_VAL_8(3)>>4) {
1607 printf ("to play first PGC");
1610 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1614 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1617 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1620 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1623 switch( OP_VAL_8(3)>>6 )
1626 printf( "to play first PGC" );
1629 printf( "to VMG title menu (?)" );
1632 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1635 IfoMenuName( OP_VAL_8(3)&0xF ) );
1638 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1645 switch(OP_VAL_8(3)>>4) {
1647 printf ("system first pgc");
1650 printf ("system title menu");
1653 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1656 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1659 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1662 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1666 // OP_VAL_8(2) is number of cell
1667 // it is processed BEFORE switch
1668 // under some conditions, it is ignored
1669 // I don't understand exactly what it means
1670 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1672 switch( OP_VAL_8(3)>>6 )
1675 printf( "to FP PGC" );
1678 printf( "to VMG root menu (?)" );
1681 printf( "to VTS menu \"%s\" (?)",
1682 IfoMenuName(OP_VAL_8(3)&0xF) );
1685 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1693 static void IfoLnk( ifo_command_t com )
1695 u16 i_button=OP_VAL_8(4)>>2;
1699 switch( com.i_sub_cmd )
1702 IfoAdvanced( &OP_VAL_8(4) );
1706 printf( "PGC 0x%02x", OP_VAL_16(2) );
1710 printf( "PTT 0x%02x", OP_VAL_16(2) );
1714 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1718 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1726 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1731 void IfoSetSystem( ifo_command_t com )
1738 for( i=1; i<=3; i++ )
1740 if( OP_VAL_8(i)&0x80 )
1744 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1748 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1754 if(OP_VAL_8(1]&0x80)
1755 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1756 if(OP_VAL_8(2)&0x80)
1757 //DENT: lwhat about 0x7f here ???
1758 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1759 if(OP_VAL_8(3)&0x80)
1760 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1762 if(OP_VAL_8(1)&0x80)
1763 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1764 if(OP_VAL_8(2)&0x80)
1765 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1766 if(OP_VAL_8(3)&0x80)
1767 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1775 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1779 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1782 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1783 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1788 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1792 printf ("r[r[0x%02x]] = r[0x%02x]",
1793 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1797 //actually only bits 00011100 00011100 are set
1800 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1804 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1809 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1810 //but it is way too ugly
1813 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1817 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1825 static void IfoSet( ifo_command_t com )
1827 IfoRegister( OP_VAL_16(0), 0 );
1828 printf( " %s ", IfoMath( com.i_cmd ) );
1829 IfoRegister( OP_VAL_16(1), com.i_direct );
1832 /*****************************************************************************
1833 * CommandRead : translates the command strings in ifo into command
1835 *****************************************************************************/
1836 void CommandRead( ifo_command_t com )
1838 u8* pi_code = (u8*)(&com);
1840 switch( com.i_type )
1853 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1854 ifo_cmp[com.i_cmp]);
1855 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1860 switch( com.i_sub_cmd )
1863 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1867 printf( "stop VM" );
1871 printf( "Set Parental Level To %s and goto Line 0x%02x",
1872 ifo_parental[OP_VAL_8(4)&0x7],
1877 printf( "Illegal" );
1896 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1897 ifo_cmp[com.i_cmp] );
1898 IfoRegister( OP_VAL_8(5), 0 );
1909 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1910 ifo_cmp[com.i_cmp] );
1911 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1925 IfoSetSystem( com );
1927 else if( com.i_cmp && !com.i_sub_cmd )
1929 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1930 IfoRegister( OP_VAL_8(5), 0 );
1932 IfoSetSystem( com );
1934 else if( !com.i_cmp && com.i_sub_cmd )
1937 IfoSetSystem( com );
1953 else if( com.i_cmp && !com.i_sub_cmd )
1955 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1956 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1960 else if( !com.i_cmp && com.i_sub_cmd )
1974 * math command on r[opcode[1]] and
1975 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1976 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1978 * boolean operation cmp on r[opcode[1]] and
1979 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1980 * on true result, buttons(c[6], c[7]) is called
1981 * problem is 'what is buttons()'
1984 printf( "r[0x%X] ", pi_code[1] );
1985 printf( " %s ", IfoMath( com.i_cmd ) );
1986 if( com.i_cmd == 2 )
1988 printf( "r[0x%X] ", OP_VAL_8(1) );
1992 IfoRegister( OP_VAL_16(0), com.i_direct );
1996 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1997 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1998 printf( " ) then {" );
1999 IfoAdvanced( &OP_VAL_8(4) );
2004 * opposite to case 4: boolean, math and buttons.
2010 if( !com.i_direct && com.i_dir_cmp )
2012 printf( "0x%X", OP_VAL_16(1) );
2016 IfoRegister( OP_VAL_8(3), 0 );
2017 if( OP_VAL_8(3)&0x80 )
2019 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2023 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2024 // 0x1F is either not a mistake,
2025 // or Microsoft programmer's mistake!!!
2029 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2030 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2031 printf( " ) then {" );
2032 printf( "r[0x%X] ", pi_code[1] & 0xF );
2033 printf( " %s ", IfoMath( com.i_cmd ) );
2035 if( com.i_cmd == 0x02 ) // swap
2037 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2043 printf( "0x%X", OP_VAL_16(0) );
2047 if( OP_VAL_8(0) & 0x80 )
2049 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2053 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2059 IfoAdvanced( &OP_VAL_8(4) );
2065 printf( "Unknown Command\n" );
2072 /*****************************************************************************
2073 * CommandPrint : print in clear text (I hope so !) what a command does
2074 *****************************************************************************/
2075 void CommandPrint( ifo_t ifo )