WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / dvdnav.c
blob09dc411f8a9b9d0e9a04837b680fdc636e4ccd0a
1 /* dvdnav.c
3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 */
10 #include "hb.h"
11 #include "lang.h"
12 #include "dvd.h"
14 #include "dvdnav/dvdnav.h"
15 #include "dvdread/ifo_read.h"
16 #include "dvdread/ifo_print.h"
17 #include "dvdread/nav_read.h"
19 #define DVD_READ_CACHE 1
21 static char * hb_dvdnav_name( char * path );
22 static hb_dvd_t * hb_dvdnav_init( hb_handle_t * h, char * path );
23 static int hb_dvdnav_title_count( hb_dvd_t * d );
24 static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * d, int t, uint64_t min_duration );
25 static int hb_dvdnav_start( hb_dvd_t * d, hb_title_t *title, int chapter );
26 static void hb_dvdnav_stop( hb_dvd_t * d );
27 static int hb_dvdnav_seek( hb_dvd_t * d, float f );
28 static hb_buffer_t * hb_dvdnav_read( hb_dvd_t * d );
29 static int hb_dvdnav_chapter( hb_dvd_t * d );
30 static void hb_dvdnav_close( hb_dvd_t ** _d );
31 static int hb_dvdnav_angle_count( hb_dvd_t * d );
32 static void hb_dvdnav_set_angle( hb_dvd_t * d, int angle );
33 static int hb_dvdnav_main_feature( hb_dvd_t * d, hb_list_t * list_title );
35 hb_dvd_func_t hb_dvdnav_func =
37 hb_dvdnav_init,
38 hb_dvdnav_close,
39 hb_dvdnav_name,
40 hb_dvdnav_title_count,
41 hb_dvdnav_title_scan,
42 hb_dvdnav_start,
43 hb_dvdnav_stop,
44 hb_dvdnav_seek,
45 hb_dvdnav_read,
46 hb_dvdnav_chapter,
47 hb_dvdnav_angle_count,
48 hb_dvdnav_set_angle,
49 hb_dvdnav_main_feature
52 // there can be at most 999 PGCs per title. round that up to the nearest
53 // power of two.
54 #define MAX_PGCN 1024
56 /***********************************************************************
57 * Local prototypes
58 **********************************************************************/
59 static void PgcWalkInit( uint32_t pgcn_map[MAX_PGCN/32] );
60 static int FindChapterIndex( hb_list_t * list, int pgcn, int pgn );
61 static int NextPgcn( ifo_handle_t *ifo, int pgcn, uint32_t pgcn_map[MAX_PGCN/32] );
62 static int FindNextCell( pgc_t *pgc, int cell_cur );
63 static int dvdtime2msec( dvd_time_t * );
65 hb_dvd_func_t * hb_dvdnav_methods( void )
67 return &hb_dvdnav_func;
70 static char * hb_dvdnav_name( char * path )
72 static char name[1024];
73 unsigned char unused[1024];
74 dvd_reader_t * reader;
76 reader = DVDOpen( path );
77 if( !reader )
79 return NULL;
82 if( DVDUDFVolumeInfo( reader, name, sizeof( name ),
83 unused, sizeof( unused ) ) )
85 DVDClose( reader );
86 return NULL;
89 DVDClose( reader );
90 return name;
93 /***********************************************************************
94 * hb_dvdnav_reset
95 ***********************************************************************
96 * Once dvdnav has entered the 'stopped' state, it can not be revived
97 * dvdnav_reset doesn't work because it doesn't remember the path
98 * So this function re-opens dvdnav
99 **********************************************************************/
100 static int hb_dvdnav_reset( hb_dvdnav_t * d )
102 char * path_ccp = hb_utf8_to_cp( d->path );
103 if ( d->dvdnav )
104 dvdnav_close( d->dvdnav );
106 /* Open device */
107 if( dvdnav_open(&d->dvdnav, path_ccp) != DVDNAV_STATUS_OK )
110 * Not an error, may be a stream - which we'll try in a moment.
112 hb_log( "dvd: not a dvd - trying as a stream/file instead" );
113 goto fail;
116 if (dvdnav_set_readahead_flag(d->dvdnav, DVD_READ_CACHE) !=
117 DVDNAV_STATUS_OK)
119 hb_error("Error: dvdnav_set_readahead_flag: %s\n",
120 dvdnav_err_to_string(d->dvdnav));
121 goto fail;
125 ** set the PGC positioning flag to have position information
126 ** relatively to the whole feature instead of just relatively to the
127 ** current chapter
129 if (dvdnav_set_PGC_positioning_flag(d->dvdnav, 1) != DVDNAV_STATUS_OK)
131 hb_error("Error: dvdnav_set_PGC_positioning_flag: %s\n",
132 dvdnav_err_to_string(d->dvdnav));
133 goto fail;
136 free( path_ccp );
138 return 1;
140 fail:
141 if( d->dvdnav ) dvdnav_close( d->dvdnav );
142 free( path_ccp );
143 return 0;
146 /***********************************************************************
147 * hb_dvdnav_init
148 ***********************************************************************
150 **********************************************************************/
151 static hb_dvd_t * hb_dvdnav_init( hb_handle_t * h, char * path )
153 hb_dvd_t * e;
154 hb_dvdnav_t * d;
155 int region_mask;
156 char * path_ccp;
158 e = calloc( sizeof( hb_dvd_t ), 1 );
159 d = &(e->dvdnav);
160 d->h = h;
163 * Convert UTF-8 path to current code page on Windows
164 * hb_utf8_to_cp() is the same as strdup on non-Windows,
165 * so no #ifdef required here
167 path_ccp = hb_utf8_to_cp( path );
169 /* Log DVD drive region code */
170 if ( hb_dvd_region( path_ccp, &region_mask ) == 0 )
172 hb_log( "dvd: Region mask 0x%02x", region_mask );
173 if ( region_mask == 0xFF )
175 hb_log( "dvd: Warning, DVD device has no region set" );
179 /* Open device */
180 if( dvdnav_open(&d->dvdnav, path_ccp) != DVDNAV_STATUS_OK )
183 * Not an error, may be a stream - which we'll try in a moment.
185 hb_log( "dvd: not a dvd - trying as a stream/file instead" );
186 goto fail;
189 if (dvdnav_set_readahead_flag(d->dvdnav, DVD_READ_CACHE) !=
190 DVDNAV_STATUS_OK)
192 hb_error("Error: dvdnav_set_readahead_flag: %s\n",
193 dvdnav_err_to_string(d->dvdnav));
194 goto fail;
198 ** set the PGC positioning flag to have position information
199 ** relatively to the whole feature instead of just relatively to the
200 ** current chapter
202 if (dvdnav_set_PGC_positioning_flag(d->dvdnav, 1) != DVDNAV_STATUS_OK)
204 hb_error("Error: dvdnav_set_PGC_positioning_flag: %s\n",
205 dvdnav_err_to_string(d->dvdnav));
206 goto fail;
209 /* Open device */
210 if( !( d->reader = DVDOpen( path_ccp ) ) )
213 * Not an error, may be a stream - which we'll try in a moment.
215 hb_log( "dvd: not a dvd - trying as a stream/file instead" );
216 goto fail;
219 /* Open main IFO */
220 if( !( d->vmg = ifoOpen( d->reader, 0 ) ) )
222 hb_error( "dvd: ifoOpen failed" );
223 goto fail;
226 d->path = strdup( path ); /* hb_dvdnav_title_scan assumes UTF-8 path, so not path_ccp here */
227 free( path_ccp );
229 return e;
231 fail:
232 if( d->dvdnav ) dvdnav_close( d->dvdnav );
233 if( d->vmg ) ifoClose( d->vmg );
234 if( d->reader ) DVDClose( d->reader );
235 free( e );
236 free( path_ccp );
237 return NULL;
240 /***********************************************************************
241 * hb_dvdnav_title_count
242 **********************************************************************/
243 static int hb_dvdnav_title_count( hb_dvd_t * e )
245 int titles = 0;
246 hb_dvdnav_t * d = &(e->dvdnav);
248 dvdnav_get_number_of_titles(d->dvdnav, &titles);
249 return titles;
252 static uint64_t
253 PttDuration(ifo_handle_t *ifo, int ttn, int pttn, int *blocks, int *last_pgcn)
255 int pgcn, pgn;
256 pgc_t * pgc;
257 uint64_t duration = 0;
258 int cell_start, cell_end;
259 int i;
261 *blocks = 0;
263 // Initialize map of visited pgc's to prevent loops
264 uint32_t pgcn_map[MAX_PGCN/32];
265 PgcWalkInit( pgcn_map );
266 pgcn = ifo->vts_ptt_srpt->title[ttn-1].ptt[pttn-1].pgcn;
267 pgn = ifo->vts_ptt_srpt->title[ttn-1].ptt[pttn-1].pgn;
268 if ( pgcn < 1 || pgcn > ifo->vts_pgcit->nr_of_pgci_srp || pgcn >= MAX_PGCN)
270 hb_log( "invalid PGC ID %d, skipping", pgcn );
271 return 0;
274 if( pgn <= 0 || pgn > 99 )
276 hb_log( "scan: pgn %d not valid, skipping", pgn );
277 return 0;
282 pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
283 if (!pgc)
285 *blocks = 0;
286 duration = 0;
287 hb_log( "scan: pgc not valid, skipping" );
288 break;
291 if (pgc->cell_playback == NULL)
293 *blocks = 0;
294 duration = 0;
295 hb_log("invalid PGC cell_playback table, skipping");
296 break;
299 if (pgn > pgc->nr_of_programs)
301 pgn = 1;
302 continue;
305 duration += 90LL * dvdtime2msec( &pgc->playback_time );
307 cell_start = pgc->program_map[pgn-1] - 1;
308 cell_end = pgc->nr_of_cells - 1;
309 for(i = cell_start; i <= cell_end; i = FindNextCell(pgc, i))
311 *blocks += pgc->cell_playback[i].last_sector + 1 -
312 pgc->cell_playback[i].first_sector;
314 *last_pgcn = pgcn;
315 pgn = 1;
316 } while((pgcn = NextPgcn(ifo, pgcn, pgcn_map)) != 0);
317 return duration;
320 /***********************************************************************
321 * hb_dvdnav_title_scan
322 **********************************************************************/
323 static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_duration )
326 hb_dvdnav_t * d = &(e->dvdnav);
327 hb_title_t * title;
328 ifo_handle_t * ifo = NULL;
329 int pgcn, pgn, pgcn_end, i, c;
330 int title_pgcn;
331 pgc_t * pgc;
332 int cell_cur;
333 hb_chapter_t * chapter;
334 int count;
335 uint64_t duration, longest;
336 int longest_pgcn, longest_pgn, longest_pgcn_end;
337 const char * name;
338 unsigned char unused[1024];
339 const char * codec_name;
341 hb_log( "scan: scanning title %d", t );
343 title = hb_title_init( d->path, t );
344 title->type = HB_DVD_TYPE;
345 if (dvdnav_get_title_string(d->dvdnav, &name) == DVDNAV_STATUS_OK)
347 strncpy( title->name, name, sizeof( title->name ) );
350 if (strlen(title->name) == 0)
352 if( DVDUDFVolumeInfo( d->reader, title->name, sizeof( title->name ),
353 unused, sizeof( unused ) ) )
356 char * p_cur, * p_last = d->path;
357 for( p_cur = d->path; *p_cur; p_cur++ )
359 if( IS_DIR_SEP(p_cur[0]) && p_cur[1] )
361 p_last = &p_cur[1];
364 snprintf( title->name, sizeof( title->name ), "%s", p_last );
365 char *dot_term = strrchr(title->name, '.');
366 if (dot_term)
367 *dot_term = '\0';
371 /* VTS which our title is in */
372 title->vts = d->vmg->tt_srpt->title[t-1].title_set_nr;
374 if ( !title->vts )
376 /* A VTS of 0 means the title wasn't found in the title set */
377 hb_log("Invalid VTS (title set) number: %i", title->vts);
378 goto fail;
381 hb_log( "scan: opening IFO for VTS %d", title->vts );
382 if( !( ifo = ifoOpen( d->reader, title->vts ) ) )
384 hb_log( "scan: ifoOpen failed" );
385 goto fail;
388 /* ignore titles with bogus cell addresses so we don't abort later
389 ** in libdvdread. */
390 for ( i = 0; i < ifo->vts_c_adt->nr_of_vobs; ++i)
392 if( (ifo->vts_c_adt->cell_adr_table[i].start_sector & 0xffffff ) ==
393 0xffffff )
395 hb_log( "scan: cell_adr_table[%d].start_sector invalid (0x%x) "
396 "- skipping title", i,
397 ifo->vts_c_adt->cell_adr_table[i].start_sector );
398 goto fail;
400 if( (ifo->vts_c_adt->cell_adr_table[i].last_sector & 0xffffff ) ==
401 0xffffff )
403 hb_log( "scan: cell_adr_table[%d].last_sector invalid (0x%x) "
404 "- skipping title", i,
405 ifo->vts_c_adt->cell_adr_table[i].last_sector );
406 goto fail;
410 if( global_verbosity_level == 3 )
412 ifo_print( d->reader, title->vts );
415 /* Position of the title in the VTS */
416 title->ttn = d->vmg->tt_srpt->title[t-1].vts_ttn;
417 if ( title->ttn < 1 || title->ttn > ifo->vts_ptt_srpt->nr_of_srpts )
419 hb_log( "invalid VTS PTT offset %d for title %d, skipping", title->ttn, t );
420 goto fail;
423 longest = 0LL;
424 longest_pgcn = -1;
425 longest_pgn = 1;
426 longest_pgcn_end = -1;
427 pgcn_end = -1;
428 for( i = 0; i < ifo->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts; i++ )
430 int blocks = 0;
432 duration = PttDuration(ifo, title->ttn, i+1, &blocks, &pgcn_end);
433 pgcn = ifo->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgcn;
434 pgn = ifo->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgn;
435 if( duration > longest )
437 longest_pgcn = pgcn;
438 longest_pgn = pgn;
439 longest_pgcn_end = pgcn_end;
440 longest = duration;
441 title->block_count = blocks;
443 else if (pgcn == longest_pgcn && pgn < longest_pgn)
445 longest_pgn = pgn;
446 title->block_count = blocks;
450 /* Get duration */
451 title->duration = longest;
452 title->hours = title->duration / 90000 / 3600;
453 title->minutes = ( ( title->duration / 90000 ) % 3600 ) / 60;
454 title->seconds = ( title->duration / 90000 ) % 60;
455 hb_log( "scan: duration is %02d:%02d:%02d (%"PRId64" ms)",
456 title->hours, title->minutes, title->seconds,
457 title->duration / 90 );
459 /* ignore titles under 10 seconds because they're often stills or
460 * clips with no audio & our preview code doesn't currently handle
461 * either of these. */
462 if( longest < min_duration )
464 hb_log( "scan: ignoring title (too short)" );
465 goto fail;
468 pgcn = longest_pgcn;
469 pgcn_end = longest_pgcn_end;
470 pgn = longest_pgn;;
471 title_pgcn = pgcn;
474 /* Get pgc */
475 if ( pgcn < 1 || pgcn > ifo->vts_pgcit->nr_of_pgci_srp || pgcn >= MAX_PGCN)
477 hb_log( "invalid PGC ID %d for title %d, skipping", pgcn, t );
478 goto fail;
481 // Check all pgc's for validity
482 uint32_t pgcn_map[MAX_PGCN/32];
483 PgcWalkInit( pgcn_map );
486 pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
488 if( !pgc || !pgc->program_map )
490 hb_log( "scan: pgc not valid, skipping" );
491 goto fail;
494 if (pgc->cell_playback == NULL)
496 hb_log( "invalid PGC cell_playback table for title %d, skipping", t );
497 goto fail;
499 } while ((pgcn = NextPgcn(ifo, pgcn, pgcn_map)) != 0);
501 pgcn = longest_pgcn;
502 pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
504 hb_log("pgc_id: %d, pgn: %d: pgc: %p", pgcn, pgn, pgc);
505 if (pgn > pgc->nr_of_programs)
507 hb_log( "invalid PGN %d for title %d, skipping", pgn, t );
508 goto fail;
511 /* Title start */
512 title->cell_start = pgc->program_map[pgn-1] - 1;
513 title->block_start = pgc->cell_playback[title->cell_start].first_sector;
515 pgc = ifo->vts_pgcit->pgci_srp[pgcn_end-1].pgc;
517 /* Title end */
518 title->cell_end = pgc->nr_of_cells - 1;
519 title->block_end = pgc->cell_playback[title->cell_end].last_sector;
521 hb_log( "scan: vts=%d, ttn=%d, cells=%d->%d, blocks=%"PRIu64"->%"PRIu64", "
522 "%"PRIu64" blocks", title->vts, title->ttn, title->cell_start,
523 title->cell_end, title->block_start, title->block_end,
524 title->block_count );
526 /* Detect languages */
527 for( i = 0; i < ifo->vtsi_mat->nr_of_vts_audio_streams; i++ )
529 int audio_format, lang_code, lang_extension, audio_control, position, j;
530 hb_audio_t * audio, * audio_tmp;
531 iso639_lang_t * lang;
533 hb_log( "scan: checking audio %d", i + 1 );
535 audio = calloc( sizeof( hb_audio_t ), 1 );
537 audio_format = ifo->vtsi_mat->vts_audio_attr[i].audio_format;
538 lang_code = ifo->vtsi_mat->vts_audio_attr[i].lang_code;
539 lang_extension = ifo->vtsi_mat->vts_audio_attr[i].code_extension;
540 audio_control =
541 ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->audio_control[i];
543 if( !( audio_control & 0x8000 ) )
545 hb_log( "scan: audio channel is not active" );
546 free( audio );
547 continue;
550 position = ( audio_control & 0x7F00 ) >> 8;
552 switch( audio_format )
554 case 0x00:
555 audio->id = ( ( 0x80 + position ) << 8 ) | 0xbd;
556 audio->config.in.codec = HB_ACODEC_AC3;
557 audio->config.in.codec_param = AV_CODEC_ID_AC3;
558 codec_name = "AC3";
559 break;
561 case 0x02:
562 case 0x03:
563 audio->id = 0xc0 + position;
564 audio->config.in.codec = HB_ACODEC_FFMPEG;
565 audio->config.in.codec_param = AV_CODEC_ID_MP2;
566 codec_name = "MPEG";
567 break;
569 case 0x04:
570 audio->id = ( ( 0xa0 + position ) << 8 ) | 0xbd;
571 audio->config.in.codec = HB_ACODEC_LPCM;
572 codec_name = "LPCM";
573 break;
575 case 0x06:
576 audio->id = ( ( 0x88 + position ) << 8 ) | 0xbd;
577 audio->config.in.codec = HB_ACODEC_DCA;
578 audio->config.in.codec_param = AV_CODEC_ID_DTS;
579 codec_name = "DTS";
580 break;
582 default:
583 audio->id = 0;
584 audio->config.in.codec = 0;
585 codec_name = "Unknown";
586 hb_log( "scan: unknown audio codec (%x)",
587 audio_format );
588 break;
590 if( !audio->id )
592 continue;
595 /* Check for duplicate tracks */
596 audio_tmp = NULL;
597 for( j = 0; j < hb_list_count( title->list_audio ); j++ )
599 audio_tmp = hb_list_item( title->list_audio, j );
600 if( audio->id == audio_tmp->id )
602 break;
604 audio_tmp = NULL;
606 if( audio_tmp )
608 hb_log( "scan: duplicate audio track" );
609 free( audio );
610 continue;
613 lang = lang_for_code( lang_code );
615 audio->config.lang.type = lang_extension;
617 snprintf( audio->config.lang.simple,
618 sizeof( audio->config.lang.simple ), "%s",
619 strlen( lang->native_name ) ? lang->native_name : lang->eng_name );
620 snprintf( audio->config.lang.iso639_2,
621 sizeof( audio->config.lang.iso639_2 ), "%s", lang->iso639_2 );
623 hb_log("scan: id=0x%x, lang=%s (%s), 3cc=%s ext=%i", audio->id,
624 audio->config.lang.simple, codec_name,
625 audio->config.lang.iso639_2, lang_extension);
627 audio->config.in.track = i;
628 hb_list_add( title->list_audio, audio );
631 /* Check for subtitles */
632 for( i = 0; i < ifo->vtsi_mat->nr_of_vts_subp_streams; i++ )
634 hb_subtitle_t * subtitle;
635 int spu_control;
636 int position;
637 iso639_lang_t * lang;
638 int lang_extension = 0;
640 hb_log( "scan: checking subtitle %d", i + 1 );
642 spu_control =
643 ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->subp_control[i];
645 if( !( spu_control & 0x80000000 ) )
647 hb_log( "scan: subtitle channel is not active" );
648 continue;
651 if( ifo->vtsi_mat->vts_video_attr.display_aspect_ratio )
653 switch( ifo->vtsi_mat->vts_video_attr.permitted_df )
655 case 1:
656 position = spu_control & 0xFF;
657 break;
658 case 2:
659 position = ( spu_control >> 8 ) & 0xFF;
660 break;
661 default:
662 position = ( spu_control >> 16 ) & 0xFF;
665 else
667 position = ( spu_control >> 24 ) & 0x7F;
670 lang_extension = ifo->vtsi_mat->vts_subp_attr[i].code_extension;
672 lang = lang_for_code( ifo->vtsi_mat->vts_subp_attr[i].lang_code );
674 subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
675 subtitle->track = i;
676 subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd;
677 snprintf( subtitle->lang, sizeof( subtitle->lang ), "%s",
678 strlen(lang->native_name) ? lang->native_name : lang->eng_name);
679 snprintf( subtitle->iso639_2, sizeof( subtitle->iso639_2 ), "%s",
680 lang->iso639_2);
681 subtitle->format = PICTURESUB;
682 subtitle->source = VOBSUB;
683 subtitle->config.dest = RENDERSUB; // By default render (burn-in) the VOBSUB.
684 subtitle->stream_type = 0xbd;
685 subtitle->substream_type = 0x20 + position;
686 subtitle->codec = WORK_DECVOBSUB;
688 subtitle->type = lang_extension;
690 memcpy( subtitle->palette,
691 ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->palette,
692 16 * sizeof( uint32_t ) );
693 subtitle->palette_set = 1;
695 switch( lang_extension )
697 case 2:
698 strcat( subtitle->lang, " (Caption with bigger size character)" );
699 break;
700 case 3:
701 strcat( subtitle->lang, " (Caption for Children)" );
702 break;
703 case 5:
704 strcat( subtitle->lang, " (Closed Caption)" );
705 break;
706 case 6:
707 strcat( subtitle->lang, " (Closed Caption with bigger size character)" );
708 break;
709 case 7:
710 strcat( subtitle->lang, " (Closed Caption for Children)" );
711 break;
712 case 9:
713 strcat( subtitle->lang, " (Forced Caption)" );
714 break;
715 case 13:
716 strcat( subtitle->lang, " (Director's Commentary)" );
717 break;
718 case 14:
719 strcat( subtitle->lang, " (Director's Commentary with bigger size character)" );
720 break;
721 case 15:
722 strcat( subtitle->lang, " (Director's Commentary for Children)" );
723 default:
724 break;
727 hb_log( "scan: id=0x%x, lang=%s, 3cc=%s ext=%i", subtitle->id,
728 subtitle->lang, subtitle->iso639_2, lang_extension );
730 hb_list_add( title->list_subtitle, subtitle );
733 /* Chapters */
734 PgcWalkInit( pgcn_map );
735 c = 0;
738 pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
740 for (i = pgn; i <= pgc->nr_of_programs; i++)
742 char chapter_title[80];
743 chapter = calloc( sizeof( hb_chapter_t ), 1 );
745 chapter->pgcn = pgcn;
746 chapter->pgn = i;
747 chapter->index = c + 1;
748 sprintf( chapter_title, "Chapter %d", chapter->index );
749 hb_chapter_set_title( chapter, chapter_title );
751 hb_list_add( title->list_chapter, chapter );
752 c++;
755 pgn = 1;
756 } while ((pgcn = NextPgcn(ifo, pgcn, pgcn_map)) != 0);
758 hb_log( "scan: title %d has %d chapters", t, c );
760 count = hb_list_count( title->list_chapter );
761 for (i = 0; i < count; i++)
763 chapter = hb_list_item( title->list_chapter, i );
765 pgcn = chapter->pgcn;
766 pgn = chapter->pgn;
767 pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
769 /* Start cell */
770 chapter->cell_start = pgc->program_map[pgn-1] - 1;
771 chapter->block_start = pgc->cell_playback[chapter->cell_start].first_sector;
772 // if there are no more programs in this pgc, the end cell is the
773 // last cell. Otherwise it's the cell before the start cell of the
774 // next program.
775 if ( pgn == pgc->nr_of_programs )
777 chapter->cell_end = pgc->nr_of_cells - 1;
779 else
781 chapter->cell_end = pgc->program_map[pgn] - 2;;
783 chapter->block_end = pgc->cell_playback[chapter->cell_end].last_sector;
785 /* Block count, duration */
786 chapter->block_count = 0;
787 chapter->duration = 0;
789 cell_cur = chapter->cell_start;
790 while( cell_cur <= chapter->cell_end )
792 #define cp pgc->cell_playback[cell_cur]
793 chapter->block_count += cp.last_sector + 1 - cp.first_sector;
794 chapter->duration += 90LL * dvdtime2msec( &cp.playback_time );
795 #undef cp
796 cell_cur = FindNextCell( pgc, cell_cur );
800 for( i = 0; i < hb_list_count( title->list_chapter ); i++ )
802 chapter = hb_list_item( title->list_chapter, i );
804 int seconds = ( chapter->duration + 45000 ) / 90000;
805 chapter->hours = ( seconds / 3600 );
806 chapter->minutes = ( seconds % 3600 ) / 60;
807 chapter->seconds = ( seconds % 60 );
809 hb_log( "scan: chap %d c=%d->%d, b=%"PRIu64"->%"PRIu64" (%"PRIu64"), %"PRId64" ms",
810 chapter->index, chapter->cell_start, chapter->cell_end,
811 chapter->block_start, chapter->block_end,
812 chapter->block_count, chapter->duration / 90 );
815 /* Get aspect. We don't get width/height/rate infos here as
816 they tend to be wrong */
817 switch( ifo->vtsi_mat->vts_video_attr.display_aspect_ratio )
819 case 0:
820 title->container_dar.num = 4;
821 title->container_dar.den = 3;
822 break;
823 case 3:
824 title->container_dar.num = 16;
825 title->container_dar.den = 9;
826 break;
827 default:
828 hb_log( "scan: unknown aspect" );
829 goto fail;
832 hb_log("scan: aspect = %d:%d",
833 title->container_dar.num, title->container_dar.den);
835 /* This title is ok so far */
836 goto cleanup;
838 fail:
839 hb_title_close( &title );
841 cleanup:
842 if( ifo ) ifoClose( ifo );
844 return title;
847 /***********************************************************************
848 * hb_dvdnav_title_scan
849 **********************************************************************/
850 static int find_title( hb_list_t * list_title, int title )
852 int ii;
854 for ( ii = 0; ii < hb_list_count( list_title ); ii++ )
856 hb_title_t * hbtitle = hb_list_item( list_title, ii );
857 if ( hbtitle->index == title )
858 return ii;
860 return -1;
863 static int skip_to_menu( dvdnav_t * dvdnav, int blocks )
865 int ii;
866 int result, event, len;
867 uint8_t buf[HB_DVD_READ_BUFFER_SIZE];
869 for ( ii = 0; ii < blocks; ii++ )
871 result = dvdnav_get_next_block( dvdnav, buf, &event, &len );
872 if ( result == DVDNAV_STATUS_ERR )
874 hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(dvdnav));
875 return 0;
877 switch ( event )
879 case DVDNAV_BLOCK_OK:
880 break;
882 case DVDNAV_CELL_CHANGE:
884 } break;
886 case DVDNAV_STILL_FRAME:
888 dvdnav_still_event_t *event;
889 event = (dvdnav_still_event_t*)buf;
890 dvdnav_still_skip( dvdnav );
891 if ( event->length == 255 )
893 // Infinite still. Can't be the main feature unless
894 // you like watching paint dry.
895 return 0;
897 } break;
899 case DVDNAV_WAIT:
900 dvdnav_wait_skip( dvdnav );
901 break;
903 case DVDNAV_STOP:
904 return 0;
906 case DVDNAV_HOP_CHANNEL:
907 break;
909 case DVDNAV_NAV_PACKET:
911 pci_t *pci = dvdnav_get_current_nav_pci( dvdnav );
912 if ( pci == NULL ) break;
914 int buttons = pci->hli.hl_gi.btn_ns;
916 int title, part;
917 result = dvdnav_current_title_info( dvdnav, &title, &part );
918 if (result != DVDNAV_STATUS_OK)
920 hb_log("dvdnav title info: %s", dvdnav_err_to_string(dvdnav));
922 else if ( title == 0 && buttons > 0 )
924 // Check button activation duration to see if this
925 // isn't another fake menu.
926 if ( pci->hli.hl_gi.btn_se_e_ptm - pci->hli.hl_gi.hli_s_ptm >
927 15 * 90000 )
929 // Found what appears to be a good menu.
930 return 1;
933 } break;
935 case DVDNAV_VTS_CHANGE:
937 dvdnav_vts_change_event_t *event;
938 event = (dvdnav_vts_change_event_t*)buf;
939 // Some discs initialize the vts with the "first play" item
940 // and some don't seem to. So if we see it is uninitialized,
941 // set it.
942 if ( event->new_vtsN <= 0 )
943 result = dvdnav_title_play( dvdnav, 1 );
944 } break;
946 case DVDNAV_HIGHLIGHT:
947 break;
949 case DVDNAV_AUDIO_STREAM_CHANGE:
950 break;
952 case DVDNAV_SPU_STREAM_CHANGE:
953 break;
955 case DVDNAV_SPU_CLUT_CHANGE:
956 break;
958 case DVDNAV_NOP:
959 break;
961 default:
962 break;
965 return 0;
968 static int try_button( dvdnav_t * dvdnav, int button, hb_list_t * list_title )
970 int result, event, len;
971 uint8_t buf[HB_DVD_READ_BUFFER_SIZE];
972 int ii, jj;
973 int32_t cur_title = 0, title, part;
974 uint64_t longest_duration = 0;
975 int longest = -1;
977 pci_t *pci = dvdnav_get_current_nav_pci( dvdnav );
979 result = dvdnav_button_select_and_activate( dvdnav, pci, button + 1 );
980 if (result != DVDNAV_STATUS_OK)
982 hb_log("dvdnav_button_select_and_activate: %s", dvdnav_err_to_string(dvdnav));
985 result = dvdnav_current_title_info( dvdnav, &title, &part );
986 if (result != DVDNAV_STATUS_OK)
987 hb_log("dvdnav cur title info: %s", dvdnav_err_to_string(dvdnav));
989 cur_title = title;
991 for (jj = 0; jj < 10; jj++)
993 for (ii = 0; ii < 2000; ii++)
995 result = dvdnav_get_next_block( dvdnav, buf, &event, &len );
996 if ( result == DVDNAV_STATUS_ERR )
998 hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(dvdnav));
999 goto done;
1001 switch ( event )
1003 case DVDNAV_BLOCK_OK:
1004 break;
1006 case DVDNAV_CELL_CHANGE:
1008 result = dvdnav_current_title_info( dvdnav, &title, &part );
1009 if (result != DVDNAV_STATUS_OK)
1010 hb_log("dvdnav title info: %s", dvdnav_err_to_string(dvdnav));
1012 cur_title = title;
1013 // Note, some "fake" titles have long advertised durations
1014 // but then jump to the real title early in playback.
1015 // So keep reading after finding a long title to detect
1016 // such cases.
1017 } break;
1019 case DVDNAV_STILL_FRAME:
1021 dvdnav_still_event_t *event;
1022 event = (dvdnav_still_event_t*)buf;
1023 dvdnav_still_skip( dvdnav );
1024 if ( event->length == 255 )
1026 // Infinite still. Can't be the main feature unless
1027 // you like watching paint dry.
1028 goto done;
1030 } break;
1032 case DVDNAV_WAIT:
1033 dvdnav_wait_skip( dvdnav );
1034 break;
1036 case DVDNAV_STOP:
1037 goto done;
1039 case DVDNAV_HOP_CHANNEL:
1040 break;
1042 case DVDNAV_NAV_PACKET:
1044 } break;
1046 case DVDNAV_VTS_CHANGE:
1048 result = dvdnav_current_title_info( dvdnav, &title, &part );
1049 if (result != DVDNAV_STATUS_OK)
1050 hb_log("dvdnav title info: %s", dvdnav_err_to_string(dvdnav));
1052 cur_title = title;
1053 // Note, some "fake" titles have long advertised durations
1054 // but then jump to the real title early in playback.
1055 // So keep reading after finding a long title to detect
1056 // such cases.
1057 } break;
1059 case DVDNAV_HIGHLIGHT:
1060 break;
1062 case DVDNAV_AUDIO_STREAM_CHANGE:
1063 break;
1065 case DVDNAV_SPU_STREAM_CHANGE:
1066 break;
1068 case DVDNAV_SPU_CLUT_CHANGE:
1069 break;
1071 case DVDNAV_NOP:
1072 break;
1074 default:
1075 break;
1078 // Check if the current title is long enough to qualify
1079 // as the main feature.
1080 if ( cur_title > 0 )
1082 hb_title_t * hbtitle;
1083 int index;
1084 index = find_title( list_title, cur_title );
1085 hbtitle = hb_list_item( list_title, index );
1086 if ( hbtitle != NULL )
1088 if ( hbtitle->duration / 90000 > 10 * 60 )
1090 hb_deep_log( 3, "dvdnav: Found candidate feature title %d duration %02d:%02d:%02d on button %d",
1091 cur_title, hbtitle->hours, hbtitle->minutes,
1092 hbtitle->seconds, button+1 );
1093 return cur_title;
1095 if ( hbtitle->duration > longest_duration )
1097 longest_duration = hbtitle->duration;
1098 longest = title;
1101 // Some titles have long lead-ins. Try skipping it.
1102 dvdnav_next_pg_search( dvdnav );
1106 done:
1107 if ( longest != -1 )
1109 hb_title_t * hbtitle;
1110 int index;
1111 index = find_title( list_title, longest );
1112 hbtitle = hb_list_item( list_title, index );
1113 if ( hbtitle != NULL )
1115 hb_deep_log( 3, "dvdnav: Found candidate feature title %d duration %02d:%02d:%02d on button %d",
1116 longest, hbtitle->hours, hbtitle->minutes,
1117 hbtitle->seconds, button+1 );
1120 return longest;
1123 static int try_menu(
1124 hb_dvdnav_t * d,
1125 hb_list_t * list_title,
1126 DVDMenuID_t menu,
1127 uint64_t fallback_duration )
1129 int result, event, len;
1130 uint8_t buf[HB_DVD_READ_BUFFER_SIZE];
1131 int ii, jj;
1132 int32_t cur_title, title, part;
1133 uint64_t longest_duration = 0;
1134 int longest = -1;
1136 // A bit of a hack here. Abusing Escape menu to mean use whatever
1137 // current menu is already set.
1138 if ( menu != DVD_MENU_Escape )
1140 result = dvdnav_menu_call( d->dvdnav, menu );
1141 if ( result != DVDNAV_STATUS_OK )
1143 // Sometimes the "first play" item doesn't initialize the
1144 // initial VTS. So do it here.
1145 result = dvdnav_title_play( d->dvdnav, 1 );
1146 result = dvdnav_menu_call( d->dvdnav, menu );
1147 if ( result != DVDNAV_STATUS_OK )
1149 hb_error("dvdnav: Can not set dvd menu, %s", dvdnav_err_to_string(d->dvdnav));
1150 goto done;
1155 result = dvdnav_current_title_info( d->dvdnav, &title, &part );
1156 if (result != DVDNAV_STATUS_OK)
1157 hb_log("dvdnav title info: %s", dvdnav_err_to_string(d->dvdnav));
1159 cur_title = title;
1161 for (jj = 0; jj < 4; jj++)
1163 for (ii = 0; ii < 4000; ii++)
1165 result = dvdnav_get_next_block( d->dvdnav, buf, &event, &len );
1166 if ( result == DVDNAV_STATUS_ERR )
1168 hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(d->dvdnav));
1169 goto done;
1171 switch ( event )
1173 case DVDNAV_BLOCK_OK:
1174 break;
1176 case DVDNAV_CELL_CHANGE:
1178 result = dvdnav_current_title_info( d->dvdnav, &title, &part );
1179 if (result != DVDNAV_STATUS_OK)
1180 hb_log("dvdnav title info: %s", dvdnav_err_to_string(d->dvdnav));
1181 cur_title = title;
1182 } break;
1184 case DVDNAV_STILL_FRAME:
1186 dvdnav_still_event_t *event;
1187 event = (dvdnav_still_event_t*)buf;
1188 dvdnav_still_skip( d->dvdnav );
1189 if ( event->length == 255 )
1191 // Infinite still. There won't be any menus after this.
1192 goto done;
1194 } break;
1196 case DVDNAV_WAIT:
1197 dvdnav_wait_skip( d->dvdnav );
1198 break;
1200 case DVDNAV_STOP:
1201 goto done;
1203 case DVDNAV_HOP_CHANNEL:
1204 break;
1206 case DVDNAV_NAV_PACKET:
1208 pci_t *pci = dvdnav_get_current_nav_pci( d->dvdnav );
1209 int kk;
1210 int buttons;
1211 if ( pci == NULL ) break;
1213 buttons = pci->hli.hl_gi.btn_ns;
1215 // If we are on a menu that has buttons and
1216 // the button activation duration is long enough
1217 // that this isn't another fake menu.
1218 if ( cur_title == 0 && buttons > 0 &&
1219 pci->hli.hl_gi.btn_se_e_ptm - pci->hli.hl_gi.hli_s_ptm >
1220 15 * 90000 )
1222 for (kk = 0; kk < buttons; kk++)
1224 dvdnav_t *dvdnav_copy;
1226 result = dvdnav_dup( &dvdnav_copy, d->dvdnav );
1227 if (result != DVDNAV_STATUS_OK)
1229 hb_log("dvdnav dup failed: %s", dvdnav_err_to_string(d->dvdnav));
1230 goto done;
1232 title = try_button( dvdnav_copy, kk, list_title );
1233 dvdnav_free_dup( dvdnav_copy );
1235 if ( title >= 0 )
1237 hb_title_t * hbtitle;
1238 int index;
1239 index = find_title( list_title, title );
1240 hbtitle = hb_list_item( list_title, index );
1241 if ( hbtitle != NULL )
1243 if ( hbtitle->duration > longest_duration )
1245 longest_duration = hbtitle->duration;
1246 longest = title;
1247 if ((float)fallback_duration * 0.75 < longest_duration)
1248 goto done;
1253 goto done;
1255 } break;
1257 case DVDNAV_VTS_CHANGE:
1259 result = dvdnav_current_title_info( d->dvdnav, &title, &part );
1260 if (result != DVDNAV_STATUS_OK)
1261 hb_log("dvdnav title info: %s", dvdnav_err_to_string(d->dvdnav));
1262 cur_title = title;
1263 } break;
1265 case DVDNAV_HIGHLIGHT:
1266 break;
1268 case DVDNAV_AUDIO_STREAM_CHANGE:
1269 break;
1271 case DVDNAV_SPU_STREAM_CHANGE:
1272 break;
1274 case DVDNAV_SPU_CLUT_CHANGE:
1275 break;
1277 case DVDNAV_NOP:
1278 break;
1280 default:
1281 break;
1284 // Sometimes the menu is preceeded by a intro that just
1285 // gets restarted when hitting the menu button. So
1286 // try skipping with the skip forward button. Then
1287 // try hitting the menu again.
1288 if ( !(jj & 1) )
1290 dvdnav_next_pg_search( d->dvdnav );
1292 else
1294 result = dvdnav_menu_call( d->dvdnav, menu );
1298 done:
1299 return longest;
1302 static int hb_dvdnav_main_feature( hb_dvd_t * e, hb_list_t * list_title )
1304 hb_dvdnav_t * d = &(e->dvdnav);
1305 int longest_root = -1;
1306 int longest_title = -1;
1307 int longest_fallback = 0;
1308 int ii;
1309 uint64_t longest_duration_root = 0;
1310 uint64_t longest_duration_title = 0;
1311 uint64_t longest_duration_fallback = 0;
1312 uint64_t avg_duration = 0;
1313 int avg_cnt = 0;
1314 hb_title_t * title;
1315 int index;
1317 hb_deep_log( 2, "dvdnav: Searching menus for main feature" );
1318 for ( ii = 0; ii < hb_list_count( list_title ); ii++ )
1320 title = hb_list_item( list_title, ii );
1321 if ( title->duration > longest_duration_fallback )
1323 longest_duration_fallback = title->duration;
1324 longest_fallback = title->index;
1326 if ( title->duration > 90000L * 60 * 30 )
1328 avg_duration += title->duration;
1329 avg_cnt++;
1332 if ( avg_cnt )
1333 avg_duration /= avg_cnt;
1335 index = find_title( list_title, longest_fallback );
1336 title = hb_list_item( list_title, index );
1337 if ( title )
1339 hb_deep_log( 2, "dvdnav: Longest title %d duration %02d:%02d:%02d",
1340 longest_fallback, title->hours, title->minutes,
1341 title->seconds );
1344 dvdnav_reset( d->dvdnav );
1345 if ( skip_to_menu( d->dvdnav, 2000 ) )
1347 longest_root = try_menu( d, list_title, DVD_MENU_Escape, longest_duration_fallback );
1348 if ( longest_root >= 0 )
1350 index = find_title( list_title, longest_root );
1351 title = hb_list_item( list_title, index );
1352 if ( title )
1354 longest_duration_root = title->duration;
1355 hb_deep_log( 2, "dvdnav: Found first-play title %d duration %02d:%02d:%02d",
1356 longest_root, title->hours, title->minutes, title->seconds );
1359 else
1361 hb_deep_log( 2, "dvdnav: No first-play menu title found" );
1365 if ( longest_root < 0 ||
1366 (float)longest_duration_fallback * 0.7 > longest_duration_root)
1368 longest_root = try_menu( d, list_title, DVD_MENU_Root, longest_duration_fallback );
1369 if ( longest_root >= 0 )
1371 index = find_title( list_title, longest_root );
1372 title = hb_list_item( list_title, index );
1373 if ( title )
1375 longest_duration_root = title->duration;
1376 hb_deep_log( 2, "dvdnav: Found root title %d duration %02d:%02d:%02d",
1377 longest_root, title->hours, title->minutes, title->seconds );
1380 else
1382 hb_deep_log( 2, "dvdnav: No root menu title found" );
1386 if ( longest_root < 0 ||
1387 (float)longest_duration_fallback * 0.7 > longest_duration_root)
1389 longest_title = try_menu( d, list_title, DVD_MENU_Title, longest_duration_fallback );
1390 if ( longest_title >= 0 )
1392 index = find_title( list_title, longest_title );
1393 title = hb_list_item( list_title, index );
1394 if ( title )
1396 longest_duration_title = title->duration;
1397 hb_deep_log( 2, "dvdnav: found title %d duration %02d:%02d:%02d",
1398 longest_title, title->hours, title->minutes,
1399 title->seconds );
1402 else
1404 hb_deep_log( 2, "dvdnav: No title menu title found" );
1408 uint64_t longest_duration;
1409 int longest;
1411 if ( longest_duration_root > longest_duration_title )
1413 longest_duration = longest_duration_root;
1414 longest = longest_root;
1416 else
1418 longest_duration = longest_duration_title;
1419 longest = longest_title;
1421 if ((float)longest_duration_fallback * 0.7 > longest_duration &&
1422 longest_duration < 90000L * 60 * 30 )
1424 float factor = (float)avg_duration / longest_duration;
1425 if ( factor > 1 )
1426 factor = 1 / factor;
1427 if ( avg_cnt > 10 && factor < 0.7 )
1429 longest = longest_fallback;
1430 hb_deep_log( 2, "dvdnav: Using longest title %d", longest );
1433 return longest;
1436 /***********************************************************************
1437 * hb_dvdnav_start
1438 ***********************************************************************
1439 * Title and chapter start at 1
1440 **********************************************************************/
1441 static int hb_dvdnav_start( hb_dvd_t * e, hb_title_t *title, int c )
1443 hb_dvdnav_t * d = &(e->dvdnav);
1444 int t = title->index;
1445 hb_chapter_t *chapter;
1446 dvdnav_status_t result;
1448 d->title_block_count = title->block_count;
1449 d->list_chapter = title->list_chapter;
1451 if ( d->stopped && !hb_dvdnav_reset(d) )
1453 return 0;
1455 dvdnav_reset( d->dvdnav );
1456 chapter = hb_list_item( title->list_chapter, c - 1);
1457 if (chapter != NULL)
1458 result = dvdnav_program_play(d->dvdnav, t, chapter->pgcn, chapter->pgn);
1459 else
1460 result = dvdnav_part_play(d->dvdnav, t, 1);
1461 if (result != DVDNAV_STATUS_OK)
1463 hb_error( "dvd: dvdnav_*_play failed - %s",
1464 dvdnav_err_to_string(d->dvdnav) );
1465 return 0;
1467 d->title = t;
1468 d->stopped = 0;
1469 d->chapter = 0;
1470 d->cell = 0;
1471 return 1;
1474 /***********************************************************************
1475 * hb_dvdnav_stop
1476 ***********************************************************************
1478 **********************************************************************/
1479 static void hb_dvdnav_stop( hb_dvd_t * e )
1483 /***********************************************************************
1484 * hb_dvdnav_seek
1485 ***********************************************************************
1487 **********************************************************************/
1488 static int hb_dvdnav_seek( hb_dvd_t * e, float f )
1490 hb_dvdnav_t * d = &(e->dvdnav);
1491 uint64_t sector = f * d->title_block_count;
1492 int result, event, len;
1493 uint8_t buf[HB_DVD_READ_BUFFER_SIZE];
1494 int done = 0, ii;
1496 if (d->stopped)
1498 return 0;
1501 // XXX the current version of libdvdnav can't seek outside the current
1502 // PGC. Check if the place we're seeking to is in a different
1503 // PGC. Position there & adjust the offset if so.
1504 uint64_t pgc_offset = 0;
1505 uint64_t chap_offset = 0;
1506 hb_chapter_t *pgc_change = hb_list_item(d->list_chapter, 0 );
1507 for ( ii = 0; ii < hb_list_count( d->list_chapter ); ++ii )
1509 hb_chapter_t *chapter = hb_list_item( d->list_chapter, ii );
1510 uint64_t chap_len = chapter->block_end - chapter->block_start + 1;
1512 if ( chapter->pgcn != pgc_change->pgcn )
1514 // this chapter's in a different pgc from the previous - note the
1515 // change so we can make sector offset's be pgc relative.
1516 pgc_offset = chap_offset;
1517 pgc_change = chapter;
1519 if ( chap_offset <= sector && sector < chap_offset + chap_len )
1521 // this chapter contains the sector we want - see if it's in a
1522 // different pgc than the one we're currently in.
1523 int32_t title, pgcn, pgn;
1524 if (dvdnav_current_title_program( d->dvdnav, &title, &pgcn, &pgn ) != DVDNAV_STATUS_OK)
1525 hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(d->dvdnav));
1526 // If we find ourselves in a new title, it means a title
1527 // transition was made while reading data. Jumping between
1528 // titles can cause the vm to get into a bad state. So
1529 // reset the vm in this case.
1530 if ( d->title != title )
1531 dvdnav_reset( d->dvdnav );
1533 if ( d->title != title || chapter->pgcn != pgcn )
1535 // this chapter is in a different pgc - switch to it.
1536 if (dvdnav_program_play(d->dvdnav, d->title, chapter->pgcn, chapter->pgn) != DVDNAV_STATUS_OK)
1537 hb_log("dvdnav prog play err: %s", dvdnav_err_to_string(d->dvdnav));
1539 // seek sectors are pgc-relative so remove the pgc start sector.
1540 sector -= pgc_offset;
1541 break;
1543 chap_offset += chap_len;
1546 // dvdnav will not let you seek or poll current position
1547 // till it reaches a certain point in parsing. so we
1548 // have to get blocks until we reach a cell
1549 // Put an arbitrary limit of 100 blocks on how long we search
1550 for (ii = 0; ii < 100 && !done; ii++)
1552 result = dvdnav_get_next_block( d->dvdnav, buf, &event, &len );
1553 if ( result == DVDNAV_STATUS_ERR )
1555 hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(d->dvdnav));
1556 return 0;
1558 switch ( event )
1560 case DVDNAV_BLOCK_OK:
1561 case DVDNAV_CELL_CHANGE:
1562 done = 1;
1563 break;
1565 case DVDNAV_STILL_FRAME:
1566 dvdnav_still_skip( d->dvdnav );
1567 break;
1569 case DVDNAV_WAIT:
1570 dvdnav_wait_skip( d->dvdnav );
1571 break;
1573 case DVDNAV_STOP:
1574 hb_log("dvdnav: stop encountered during seek");
1575 d->stopped = 1;
1576 return 0;
1578 case DVDNAV_HOP_CHANNEL:
1579 case DVDNAV_NAV_PACKET:
1580 case DVDNAV_VTS_CHANGE:
1581 case DVDNAV_HIGHLIGHT:
1582 case DVDNAV_AUDIO_STREAM_CHANGE:
1583 case DVDNAV_SPU_STREAM_CHANGE:
1584 case DVDNAV_SPU_CLUT_CHANGE:
1585 case DVDNAV_NOP:
1586 default:
1587 break;
1591 if (dvdnav_sector_search(d->dvdnav, sector, SEEK_SET) != DVDNAV_STATUS_OK)
1593 hb_error( "dvd: dvdnav_sector_search failed - %s",
1594 dvdnav_err_to_string(d->dvdnav) );
1595 return 0;
1597 d->chapter = 0;
1598 d->cell = 0;
1599 return 1;
1602 /***********************************************************************
1603 * hb_dvdnav_read
1604 ***********************************************************************
1606 **********************************************************************/
1607 static hb_buffer_t * hb_dvdnav_read( hb_dvd_t * e )
1609 hb_dvdnav_t * d = &(e->dvdnav);
1610 int result, event, len;
1611 int chapter = 0;
1612 int error_count = 0;
1613 hb_buffer_t *b = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
1615 while ( 1 )
1617 if (d->stopped)
1619 hb_buffer_close( &b );
1620 return NULL;
1622 result = dvdnav_get_next_block( d->dvdnav, b->data, &event, &len );
1623 if ( result == DVDNAV_STATUS_ERR )
1625 hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(d->dvdnav));
1626 if (dvdnav_sector_search(d->dvdnav, 1, SEEK_CUR) != DVDNAV_STATUS_OK)
1628 hb_error( "dvd: dvdnav_sector_search failed - %s",
1629 dvdnav_err_to_string(d->dvdnav) );
1630 hb_buffer_close( &b );
1631 hb_set_work_error(d->h, HB_ERROR_READ);
1632 return NULL;
1634 error_count++;
1635 if (error_count > 500)
1637 hb_error("dvdnav: Error, too many consecutive read errors");
1638 hb_buffer_close( &b );
1639 hb_set_work_error(d->h, HB_ERROR_READ);
1640 return NULL;
1642 continue;
1644 switch ( event )
1646 case DVDNAV_BLOCK_OK:
1647 // We have received a regular block of the currently playing
1648 // MPEG stream.
1650 // The muxers expect to only get chapter 2 and above
1651 // They write chapter 1 when chapter 2 is detected.
1652 if (chapter > 1)
1653 b->s.new_chap = chapter;
1654 chapter = 0;
1655 error_count = 0;
1656 return b;
1658 case DVDNAV_NOP:
1660 * Nothing to do here.
1662 break;
1664 case DVDNAV_STILL_FRAME:
1666 * We have reached a still frame. A real player application
1667 * would wait the amount of time specified by the still's
1668 * length while still handling user input to make menus and
1669 * other interactive stills work. A length of 0xff means an
1670 * indefinite still which has to be skipped indirectly by some
1671 * user interaction.
1673 dvdnav_still_skip( d->dvdnav );
1674 break;
1676 case DVDNAV_WAIT:
1678 * We have reached a point in DVD playback, where timing is
1679 * critical. Player application with internal fifos can
1680 * introduce state inconsistencies, because libdvdnav is
1681 * always the fifo's length ahead in the stream compared to
1682 * what the application sees. Such applications should wait
1683 * until their fifos are empty when they receive this type of
1684 * event.
1686 dvdnav_wait_skip( d->dvdnav );
1687 break;
1689 case DVDNAV_SPU_CLUT_CHANGE:
1691 * Player applications should pass the new colour lookup table
1692 * to their SPU decoder
1694 break;
1696 case DVDNAV_SPU_STREAM_CHANGE:
1698 * Player applications should inform their SPU decoder to
1699 * switch channels
1701 break;
1703 case DVDNAV_AUDIO_STREAM_CHANGE:
1705 * Player applications should inform their audio decoder to
1706 * switch channels
1708 break;
1710 case DVDNAV_HIGHLIGHT:
1712 * Player applications should inform their overlay engine to
1713 * highlight the given button
1715 break;
1717 case DVDNAV_VTS_CHANGE:
1719 * Some status information like video aspect and video scale
1720 * permissions do not change inside a VTS. Therefore this
1721 * event can be used to query such information only when
1722 * necessary and update the decoding/displaying accordingly.
1725 int tt = 0, pgcn = 0, pgn = 0;
1727 dvdnav_current_title_program(d->dvdnav, &tt, &pgcn, &pgn);
1728 if (tt != d->title)
1730 // Transition to another title signals that we are done.
1731 hb_buffer_close( &b );
1732 hb_deep_log(2, "dvdnav: vts change, found next title");
1733 return NULL;
1736 break;
1738 case DVDNAV_CELL_CHANGE:
1740 * Some status information like the current Title and Part
1741 * numbers do not change inside a cell. Therefore this event
1742 * can be used to query such information only when necessary
1743 * and update the decoding/displaying accordingly.
1746 dvdnav_cell_change_event_t * cell_event;
1747 int tt = 0, pgcn = 0, pgn = 0, c;
1749 cell_event = (dvdnav_cell_change_event_t*)b->data;
1751 dvdnav_current_title_program(d->dvdnav, &tt, &pgcn, &pgn);
1752 if (tt != d->title)
1754 // Transition to another title signals that we are done.
1755 hb_buffer_close( &b );
1756 hb_deep_log(2, "dvdnav: cell change, found next title");
1757 return NULL;
1759 c = FindChapterIndex(d->list_chapter, pgcn, pgn);
1760 if (c != d->chapter)
1762 if (c < d->chapter)
1764 // Some titles end with a 'link' back to the beginning so
1765 // a transition to an earlier chapter means we're done.
1766 hb_buffer_close( &b );
1767 hb_deep_log(2, "dvdnav: cell change, previous chapter");
1768 return NULL;
1770 chapter = d->chapter = c;
1772 else if ( cell_event->cellN <= d->cell )
1774 hb_buffer_close( &b );
1775 hb_deep_log(2, "dvdnav: cell change, previous cell");
1776 return NULL;
1778 d->cell = cell_event->cellN;
1780 break;
1782 case DVDNAV_NAV_PACKET:
1784 * A NAV packet provides PTS discontinuity information, angle
1785 * linking information and button definitions for DVD menus.
1786 * Angles are handled completely inside libdvdnav. For the
1787 * menus to work, the NAV packet information has to be passed
1788 * to the overlay engine of the player so that it knows the
1789 * dimensions of the button areas.
1792 // mpegdemux expects to get these. I don't think it does
1793 // anything useful with them however.
1795 // The muxers expect to only get chapter 2 and above
1796 // They write chapter 1 when chapter 2 is detected.
1797 if (chapter > 1)
1798 b->s.new_chap = chapter;
1799 chapter = 0;
1800 return b;
1802 break;
1804 case DVDNAV_HOP_CHANNEL:
1806 * This event is issued whenever a non-seamless operation has
1807 * been executed. Applications with fifos should drop the
1808 * fifos content to speed up responsiveness.
1810 break;
1812 case DVDNAV_STOP:
1814 * Playback should end here.
1816 d->stopped = 1;
1817 hb_buffer_close( &b );
1818 hb_deep_log(2, "dvdnav: stop");
1819 return NULL;
1821 default:
1822 break;
1825 hb_buffer_close( &b );
1826 return NULL;
1829 /***********************************************************************
1830 * hb_dvdnav_chapter
1831 ***********************************************************************
1832 * Returns in which chapter the next block to be read is.
1833 * Chapter numbers start at 1.
1834 **********************************************************************/
1835 static int hb_dvdnav_chapter( hb_dvd_t * e )
1837 hb_dvdnav_t * d = &(e->dvdnav);
1838 int32_t t, pgcn, pgn;
1839 int32_t c;
1841 if (dvdnav_current_title_program(d->dvdnav, &t, &pgcn, &pgn) != DVDNAV_STATUS_OK)
1843 return -1;
1845 c = FindChapterIndex( d->list_chapter, pgcn, pgn );
1846 return c;
1849 /***********************************************************************
1850 * hb_dvdnav_close
1851 ***********************************************************************
1852 * Closes and frees everything
1853 **********************************************************************/
1854 static void hb_dvdnav_close( hb_dvd_t ** _d )
1856 hb_dvdnav_t * d = &((*_d)->dvdnav);
1858 if( d->dvdnav ) dvdnav_close( d->dvdnav );
1859 if( d->vmg ) ifoClose( d->vmg );
1860 if( d->reader ) DVDClose( d->reader );
1862 free(d->path);
1864 free( d );
1865 *_d = NULL;
1868 /***********************************************************************
1869 * hb_dvdnav_angle_count
1870 ***********************************************************************
1871 * Returns the number of angles supported.
1872 **********************************************************************/
1873 static int hb_dvdnav_angle_count( hb_dvd_t * e )
1875 hb_dvdnav_t * d = &(e->dvdnav);
1876 int current, angle_count;
1878 if (dvdnav_get_angle_info( d->dvdnav, &current, &angle_count) != DVDNAV_STATUS_OK)
1880 hb_log("dvdnav_get_angle_info %s", dvdnav_err_to_string(d->dvdnav));
1881 angle_count = 1;
1883 return angle_count;
1886 /***********************************************************************
1887 * hb_dvdnav_set_angle
1888 ***********************************************************************
1889 * Sets the angle to read
1890 **********************************************************************/
1891 static void hb_dvdnav_set_angle( hb_dvd_t * e, int angle )
1893 hb_dvdnav_t * d = &(e->dvdnav);
1895 if (dvdnav_angle_change( d->dvdnav, angle) != DVDNAV_STATUS_OK)
1897 hb_log("dvdnav_angle_change %s", dvdnav_err_to_string(d->dvdnav));
1901 /***********************************************************************
1902 * FindChapterIndex
1903 ***********************************************************************
1904 * Assumes pgc and cell_cur are correctly set, and sets cell_next to the
1905 * cell to be read when we will be done with cell_cur.
1906 **********************************************************************/
1907 static int FindChapterIndex( hb_list_t * list, int pgcn, int pgn )
1909 int count, ii;
1910 hb_chapter_t *chapter;
1912 count = hb_list_count( list );
1913 for (ii = 0; ii < count; ii++)
1915 chapter = hb_list_item( list, ii );
1916 if (chapter->pgcn == pgcn && chapter->pgn == pgn)
1917 return chapter->index;
1919 return 0;
1922 /***********************************************************************
1923 * FindNextCell
1924 ***********************************************************************
1925 * Assumes pgc and cell_cur are correctly set, and sets cell_next to the
1926 * cell to be read when we will be done with cell_cur.
1927 **********************************************************************/
1928 static int FindNextCell( pgc_t *pgc, int cell_cur )
1930 int i = 0;
1931 int cell_next;
1933 if( pgc->cell_playback[cell_cur].block_type ==
1934 BLOCK_TYPE_ANGLE_BLOCK )
1937 while( pgc->cell_playback[cell_cur+i].block_mode !=
1938 BLOCK_MODE_LAST_CELL )
1940 i++;
1942 cell_next = cell_cur + i + 1;
1943 hb_log( "dvd: Skipping multi-angle cells %d-%d",
1944 cell_cur,
1945 cell_next - 1 );
1947 else
1949 cell_next = cell_cur + 1;
1951 return cell_next;
1954 /***********************************************************************
1955 * NextPgcn
1956 ***********************************************************************
1957 * Assumes pgc and cell_cur are correctly set, and sets cell_next to the
1958 * cell to be read when we will be done with cell_cur.
1959 * Since pg chains can be circularly linked (either from a read error or
1960 * deliberately) pgcn_map tracks program chains we've already seen.
1961 **********************************************************************/
1962 static int NextPgcn( ifo_handle_t *ifo, int pgcn, uint32_t pgcn_map[MAX_PGCN/32] )
1964 int next_pgcn;
1965 pgc_t *pgc;
1967 pgcn_map[pgcn >> 5] |= (1 << (pgcn & 31));
1969 pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
1970 next_pgcn = pgc->next_pgc_nr;
1971 if ( next_pgcn < 1 || next_pgcn >= MAX_PGCN || next_pgcn > ifo->vts_pgcit->nr_of_pgci_srp )
1972 return 0;
1974 return pgcn_map[next_pgcn >> 5] & (1 << (next_pgcn & 31))? 0 : next_pgcn;
1977 /***********************************************************************
1978 * PgcWalkInit
1979 ***********************************************************************
1980 * Pgc links can loop. I track which have been visited in a bit vector
1981 * Initialize the bit vector to empty.
1982 **********************************************************************/
1983 static void PgcWalkInit( uint32_t pgcn_map[MAX_PGCN/32] )
1985 memset(pgcn_map, 0, sizeof(uint32_t) * MAX_PGCN/32);
1988 /***********************************************************************
1989 * dvdtime2msec
1990 ***********************************************************************
1991 * From lsdvd
1992 **********************************************************************/
1993 static int dvdtime2msec(dvd_time_t * dt)
1995 double frames_per_s[4] = {-1.0, 25.00, -1.0, 29.97};
1996 double fps = frames_per_s[(dt->frame_u & 0xc0) >> 6];
1997 long ms;
1998 ms = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000;
1999 ms += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000;
2000 ms += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000;
2002 if( fps > 0 )
2004 ms += (((dt->frame_u & 0x30) >> 3) * 5 +
2005 (dt->frame_u & 0x0f)) * 1000.0 / fps;
2008 return ms;