X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fdvdnav.c;h=67e7b8b189fc3e695b7d96978ae1f0ae07215d74;hb=9972486f44c586225d98967441dcd3f3fd920636;hp=8d7ac70e7e99b4a77e20e26da958ab71c2a5fcce;hpb=82802f78f3056cf89da7dfe651cefb6d0371ae01;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 8d7ac70e..67e7b8b1 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -26,7 +26,8 @@ static int hb_dvdnav_read( hb_dvd_t * d, hb_buffer_t * b ); static int hb_dvdnav_chapter( hb_dvd_t * d ); static void hb_dvdnav_close( hb_dvd_t ** _d ); static int hb_dvdnav_angle_count( hb_dvd_t * d ); -static void hb_dvdnav_set_angle( hb_dvd_t * e, int angle ); +static void hb_dvdnav_set_angle( hb_dvd_t * d, int angle ); +static int hb_dvdnav_main_feature( hb_dvd_t * d, hb_list_t * list_title ); hb_dvd_func_t hb_dvdnav_func = { @@ -41,7 +42,8 @@ hb_dvd_func_t hb_dvdnav_func = hb_dvdnav_read, hb_dvdnav_chapter, hb_dvdnav_angle_count, - hb_dvdnav_set_angle + hb_dvdnav_set_angle, + hb_dvdnav_main_feature }; // there can be at most 999 PGCs per title. round that up to the nearest @@ -589,10 +591,6 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t ) hb_list_add( title->list_audio, audio ); } - memcpy( title->palette, - ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->palette, - 16 * sizeof( uint32_t ) ); - /* Check for subtitles */ for( i = 0; i < ifo->vtsi_mat->nr_of_vts_subp_streams; i++ ) { @@ -648,6 +646,10 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t ) subtitle->config.dest = RENDERSUB; // By default render (burn-in) the VOBSUB. subtitle->type = lang_extension; + + memcpy( subtitle->palette, + ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->palette, + 16 * sizeof( uint32_t ) ); switch( lang_extension ) { @@ -818,6 +820,498 @@ cleanup: } /*********************************************************************** + * hb_dvdnav_title_scan + **********************************************************************/ +static int find_title( hb_list_t * list_title, int title ) +{ + int ii; + + for ( ii = 0; ii < hb_list_count( list_title ); ii++ ) + { + hb_title_t * hbtitle = hb_list_item( list_title, ii ); + if ( hbtitle->index == title ) + return ii; + } + return -1; +} + +static void skip_some( dvdnav_t * dvdnav, int blocks ) +{ + int ii; + int result, event, len; + uint8_t buf[HB_DVD_READ_BUFFER_SIZE]; + + for ( ii = 0; ii < blocks; ii++ ) + { + result = dvdnav_get_next_block( dvdnav, buf, &event, &len ); + if ( result == DVDNAV_STATUS_ERR ) + { + hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(dvdnav)); + return; + } + switch ( event ) + { + case DVDNAV_BLOCK_OK: + break; + + case DVDNAV_CELL_CHANGE: + { + } break; + + case DVDNAV_STILL_FRAME: + dvdnav_still_skip( dvdnav ); + break; + + case DVDNAV_WAIT: + dvdnav_wait_skip( dvdnav ); + break; + + case DVDNAV_STOP: + return; + + case DVDNAV_HOP_CHANNEL: + break; + + case DVDNAV_NAV_PACKET: + break; + + case DVDNAV_VTS_CHANGE: + { + dvdnav_vts_change_event_t *event; + event = (dvdnav_vts_change_event_t*)buf; + // Some discs initialize the vts with the "first play" item + // and some don't seem to. So if we see it is uninitialized, + // set it. + if ( event->new_vtsN <= 0 ) + result = dvdnav_title_play( dvdnav, 1 ); + } break; + + case DVDNAV_HIGHLIGHT: + break; + + case DVDNAV_AUDIO_STREAM_CHANGE: + break; + + case DVDNAV_SPU_STREAM_CHANGE: + break; + + case DVDNAV_SPU_CLUT_CHANGE: + break; + + case DVDNAV_NOP: + break; + + default: + break; + } + } +} + +static int try_button( dvdnav_t * dvdnav, int menu_id, int button, hb_list_t * list_title ) +{ + int result, event, len; + uint8_t buf[HB_DVD_READ_BUFFER_SIZE]; + int ii, jj; + int32_t cur_title, title, pgcn, pgn; + uint64_t longest_duration = 0; + int longest = -1; + + pci_t *pci = dvdnav_get_current_nav_pci( dvdnav ); + result = dvdnav_button_select_and_activate( dvdnav, pci, button + 1 ); + if (result != DVDNAV_STATUS_OK) + { + hb_log("dvdnav_button_select_and_activate: %s", dvdnav_err_to_string(dvdnav)); + } + + result = dvdnav_current_title_program( dvdnav, &title, &pgcn, &pgn ); + if (result != DVDNAV_STATUS_OK) + hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(dvdnav)); + + if ( title > 0 ) + { + hb_title_t * hbtitle; + int index; + index = find_title( list_title, title ); + hbtitle = hb_list_item( list_title, index ); + if ( hbtitle != NULL ) + { + if ( hbtitle->duration > longest_duration ) + { + longest_duration = hbtitle->duration; + longest = title; + } + } + // If the duration is longer than 10min, assume + // this isn't garbage leading to something bigger. + if ( longest_duration / 90000 > 10 * 60 ) + { + return longest; + } + } + cur_title = title; + + for (jj = 0; jj < 5; jj++) + { + for (ii = 0; ii < 2000; ii++) + { + result = dvdnav_get_next_block( dvdnav, buf, &event, &len ); + if ( result == DVDNAV_STATUS_ERR ) + { + hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(dvdnav)); + return 0; + } + switch ( event ) + { + case DVDNAV_BLOCK_OK: + break; + + case DVDNAV_CELL_CHANGE: + { + result = dvdnav_current_title_program( dvdnav, &title, &pgcn, &pgn ); + if (result != DVDNAV_STATUS_OK) + hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(dvdnav)); + + if ( title != cur_title && title > 0 ) + { + hb_title_t * hbtitle; + int index; + index = find_title( list_title, title ); + hbtitle = hb_list_item( list_title, index ); + if ( hbtitle != NULL ) + { + if ( hbtitle->duration > longest_duration ) + { + longest_duration = hbtitle->duration; + longest = title; + } + } + // If the duration is longer than 10min, assume + // this isn't garbage leading to something bigger. + if ( longest_duration / 90000 > 10 * 60 ) + { + return longest; + } + } + cur_title = title; + if (title > 0) + { + result = dvdnav_next_pg_search( dvdnav ); + if ( result != DVDNAV_STATUS_OK ) + { + return longest; + } + } + } break; + + case DVDNAV_STILL_FRAME: + dvdnav_still_skip( dvdnav ); + break; + + case DVDNAV_WAIT: + dvdnav_wait_skip( dvdnav ); + break; + + case DVDNAV_STOP: + return 0; + + case DVDNAV_HOP_CHANNEL: + break; + + case DVDNAV_NAV_PACKET: + { + } break; + + case DVDNAV_VTS_CHANGE: + { + result = dvdnav_current_title_program( dvdnav, &title, &pgcn, &pgn ); + if (result != DVDNAV_STATUS_OK) + hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(dvdnav)); + + if ( title != cur_title && title > 0 ) + { + hb_title_t * hbtitle; + int index; + index = find_title( list_title, title ); + hbtitle = hb_list_item( list_title, index ); + if ( hbtitle != NULL ) + { + if ( hbtitle->duration > longest_duration ) + { + longest_duration = hbtitle->duration; + longest = title; + } + } + if ( longest_duration / 90000 > 10 * 60 ) + { + return longest; + } + } + cur_title = title; + } break; + + case DVDNAV_HIGHLIGHT: + break; + + case DVDNAV_AUDIO_STREAM_CHANGE: + break; + + case DVDNAV_SPU_STREAM_CHANGE: + break; + + case DVDNAV_SPU_CLUT_CHANGE: + break; + + case DVDNAV_NOP: + break; + + default: + break; + } + } + if (cur_title > 0) + { + // Some titles have long lead-ins. Try skipping it. + dvdnav_next_pg_search( dvdnav ); + } + } + return longest; +} + +static int try_menu( + hb_dvdnav_t * d, + hb_list_t * list_title, + DVDMenuID_t menu, + uint64_t fallback_duration ) +{ + int result, event, len; + uint8_t buf[HB_DVD_READ_BUFFER_SIZE]; + int ii, jj; + int32_t cur_title, title, pgcn, pgn; + uint64_t longest_duration = 0; + int longest = -1; + + + result = dvdnav_menu_call( d->dvdnav, menu ); + if ( result != DVDNAV_STATUS_OK ) + { + // Sometimes the "first play" item doesn't initialize the + // initial VTS. So do it here. + result = dvdnav_title_play( d->dvdnav, 1 ); + result = dvdnav_menu_call( d->dvdnav, menu ); + if ( result != DVDNAV_STATUS_OK ) + { + hb_error("dvdnav: Can not set dvd menu, %s", dvdnav_err_to_string(d->dvdnav)); + goto done; + } + } + + result = dvdnav_current_title_program( d->dvdnav, &title, &pgcn, &pgn ); + if (result != DVDNAV_STATUS_OK) + hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(d->dvdnav)); + + cur_title = title; + + for (jj = 0; jj < 4; jj++) + { + for (ii = 0; ii < 4000; ii++) + { + result = dvdnav_get_next_block( d->dvdnav, buf, &event, &len ); + if ( result == DVDNAV_STATUS_ERR ) + { + hb_error("dvdnav: Read Error, %s", dvdnav_err_to_string(d->dvdnav)); + goto done; + } + switch ( event ) + { + case DVDNAV_BLOCK_OK: + break; + + case DVDNAV_CELL_CHANGE: + { + result = dvdnav_current_title_program( d->dvdnav, &title, &pgcn, &pgn ); + if (result != DVDNAV_STATUS_OK) + hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(d->dvdnav)); + cur_title = title; + } break; + + case DVDNAV_STILL_FRAME: + dvdnav_still_skip( d->dvdnav ); + break; + + case DVDNAV_WAIT: + dvdnav_wait_skip( d->dvdnav ); + break; + + case DVDNAV_STOP: + goto done; + + case DVDNAV_HOP_CHANNEL: + break; + + case DVDNAV_NAV_PACKET: + { + pci_t *pci = dvdnav_get_current_nav_pci( d->dvdnav ); + int kk; + int buttons; + if ( pci == NULL ) break; + + buttons = pci->hli.hl_gi.btn_ns; + if ( cur_title == 0 && buttons > 1 ) + { + int menu_title, menu_id; + result = dvdnav_current_title_info( d->dvdnav, &menu_title, &menu_id ); + if (result != DVDNAV_STATUS_OK) + hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(d->dvdnav)); + for (kk = 0; kk < buttons; kk++) + { + dvdnav_t *dvdnav_copy; + + result = dvdnav_dup( &dvdnav_copy, d->dvdnav ); + if (result != DVDNAV_STATUS_OK) + { + hb_log("dvdnav dup failed: %s", dvdnav_err_to_string(d->dvdnav)); + goto done; + } + title = try_button( dvdnav_copy, menu_id, kk, list_title ); + dvdnav_free_dup( dvdnav_copy ); + + if ( title >= 0 ) + { + hb_title_t * hbtitle; + int index; + index = find_title( list_title, title ); + hbtitle = hb_list_item( list_title, index ); + if ( hbtitle != NULL ) + { + if ( hbtitle->duration > longest_duration ) + { + longest_duration = hbtitle->duration; + longest = title; + if ((float)fallback_duration * 0.75 < longest_duration) + goto done; + } + } + } + } + goto done; + } + if ( cur_title == 0 && buttons == 1 ) + { + dvdnav_button_select_and_activate( d->dvdnav, pci, 1 ); + } + } break; + + case DVDNAV_VTS_CHANGE: + { + result = dvdnav_current_title_program( d->dvdnav, &title, &pgcn, &pgn ); + if (result != DVDNAV_STATUS_OK) + hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(d->dvdnav)); + cur_title = title; + } break; + + case DVDNAV_HIGHLIGHT: + break; + + case DVDNAV_AUDIO_STREAM_CHANGE: + break; + + case DVDNAV_SPU_STREAM_CHANGE: + break; + + case DVDNAV_SPU_CLUT_CHANGE: + break; + + case DVDNAV_NOP: + break; + + default: + break; + } + } + // Sometimes the menu is preceeded by a intro that just + // gets restarted when hitting the menu button. So + // try skipping with the skip forward button. Then + // try hitting the menu again. + if ( !(jj & 1) ) + dvdnav_next_pg_search( d->dvdnav ); + else + result = dvdnav_menu_call( d->dvdnav, menu ); + } + +done: + return longest; +} + +static int hb_dvdnav_main_feature( hb_dvd_t * e, hb_list_t * list_title ) +{ + hb_dvdnav_t * d = &(e->dvdnav); + int longest_root; + int longest_title; + int longest_fallback; + int ii; + uint64_t longest_duration_root = 0; + uint64_t longest_duration_title = 0; + uint64_t longest_duration_fallback = 0; + + for ( ii = 0; ii < hb_list_count( list_title ); ii++ ) + { + hb_title_t * title = hb_list_item( list_title, ii ); + if ( title->duration > longest_duration_fallback ) + { + longest_duration_fallback = title->duration; + longest_fallback = title->index; + } + } + + dvdnav_reset( d->dvdnav ); + skip_some( d->dvdnav, 500 ); + + longest_root = try_menu( d, list_title, DVD_MENU_Root, longest_duration_fallback ); + if ( longest_root >= 0 ) + { + hb_title_t * hbtitle; + int index; + index = find_title( list_title, longest_root ); + hbtitle = hb_list_item( list_title, index ); + if ( hbtitle ) + longest_duration_root = hbtitle->duration; + } + if ( longest_root < 0 || + (float)longest_duration_fallback * 0.7 > longest_duration_root) + { + longest_title = try_menu( d, list_title, DVD_MENU_Title, longest_duration_fallback ); + if ( longest_title >= 0 ) + { + hb_title_t * hbtitle; + int index; + index = find_title( list_title, longest_title ); + hbtitle = hb_list_item( list_title, index ); + if ( hbtitle ) + longest_duration_title = hbtitle->duration; + } + } + + uint64_t longest_duration; + int longest; + + if ( longest_duration_root > longest_duration_title ) + { + longest_duration = longest_duration_root; + longest = longest_root; + } + else + { + longest_duration = longest_duration_title; + longest = longest_title; + } + if ((float)longest_duration_fallback * 0.7 > longest_duration) + { + longest = longest_fallback; + } + return longest; +} + +/*********************************************************************** * hb_dvdnav_start *********************************************************************** * Title and chapter start at 1 @@ -836,6 +1330,7 @@ static int hb_dvdnav_start( hb_dvd_t * e, hb_title_t *title, int c ) { return 0; } + dvdnav_reset( d->dvdnav ); chapter = hb_list_item( title->list_chapter, c - 1); if (chapter != NULL) result = dvdnav_program_play(d->dvdnav, t, chapter->pgcn, chapter->pgn); @@ -905,6 +1400,13 @@ static int hb_dvdnav_seek( hb_dvd_t * e, float f ) int32_t title, pgcn, pgn; if (dvdnav_current_title_program( d->dvdnav, &title, &pgcn, &pgn ) != DVDNAV_STATUS_OK) hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(d->dvdnav)); + // If we find ourselves in a new title, it means a title + // transition was made while reading data. Jumping between + // titles can cause the vm to get into a bad state. So + // reset the vm in this case. + if ( d->title != title ) + dvdnav_reset( d->dvdnav ); + if ( d->title != title || chapter->pgcn != pgcn ) { // this chapter is in a different pgc - switch to it. @@ -1088,6 +1590,16 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) * event can be used to query such information only when * necessary and update the decoding/displaying accordingly. */ + { + int tt = 0, pgcn = 0, pgn = 0; + + dvdnav_current_title_program(d->dvdnav, &tt, &pgcn, &pgn); + if (tt != d->title) + { + // Transition to another title signals that we are done. + return 0; + } + } break; case DVDNAV_CELL_CHANGE: