// Allocate state and enable navigation features. Must happen before // initializing cache, because the cache would read data. Since stream_dvdnav is // in a mode which skips all transitions on reading data (before enabling // navigation), this would skip some menu screens. void mp_nav_init(struct MPContext *mpctx) { assert(!mpctx->nav_state); // dvdnav is interactive if (mpctx->encode_lavc_ctx) return; struct mp_nav_cmd inp = {MP_NAV_CMD_ENABLE}; if (stream_control(mpctx->stream, STREAM_CTRL_NAV_CMD, &inp) < 1) return; mpctx->nav_state = talloc_zero(NULL, struct mp_nav_state); mpctx->nav_state->log = mp_log_new(mpctx->nav_state, mpctx->log, "discnav"); MP_VERBOSE(mpctx->nav_state, "enabling\n"); mp_input_enable_section(mpctx->input, "discnav", 0); mp_input_set_section_mouse_area(mpctx->input, "discnav-menu", INT_MIN, INT_MIN, INT_MAX, INT_MAX); }
// Allocate state and enable navigation features. Must happen before // initializing cache, because the cache would read data. Since stream_dvdnav is // in a mode which skips all transitions on reading data (before enabling // navigation), this would skip some menu screens. void mp_nav_init(struct MPContext *mpctx) { assert(!mpctx->nav_state); // dvdnav is interactive if (mpctx->encode_lavc_ctx) return; struct mp_nav_cmd inp = {MP_NAV_CMD_ENABLE}; if (run_stream_control(mpctx, STREAM_CTRL_NAV_CMD, &inp) < 1) return; mpctx->nav_state = talloc_zero(NULL, struct mp_nav_state); mpctx->nav_state->log = mp_log_new(mpctx->nav_state, mpctx->log, "discnav"); pthread_mutex_init(&mpctx->nav_state->osd_lock, NULL); MP_VERBOSE(mpctx->nav_state, "enabling\n"); mp_input_enable_section(mpctx->input, "discnav", MP_INPUT_ALLOW_VO_DRAGGING | MP_INPUT_ALLOW_HIDE_CURSOR); update_state(mpctx); update_mouse_on_button(mpctx); }
void mp_handle_nav(struct MPContext *mpctx) { struct mp_nav_state *nav = mpctx->nav_state; if (!nav) return; mpctx->sleeptime = MPMIN(mpctx->sleeptime, 0.5); while (1) { if (!mpctx->demuxer) break; struct mp_nav_event *ev = NULL; demux_control(mpctx->demuxer, DEMUXER_CTRL_GET_NAV_EVENT, &ev); if (!ev) break; switch (ev->event) { case MP_NAV_EVENT_DRAIN: { nav->nav_draining = true; MP_VERBOSE(nav, "drain requested\n"); break; } case MP_NAV_EVENT_RESET_ALL: { mpctx->stop_play = PT_RELOAD_DEMUXER; MP_VERBOSE(nav, "reload\n"); // return immediately. // other events should be handled after reloaded. talloc_free(ev); return; } case MP_NAV_EVENT_RESET: { nav->nav_still_frame = 0; break; } case MP_NAV_EVENT_EOF: nav->nav_eof = true; break; case MP_NAV_EVENT_STILL_FRAME: { int len = ev->u.still_frame.seconds; MP_VERBOSE(nav, "wait for %d seconds\n", len); if (len > 0 && nav->nav_still_frame == 0) nav->nav_still_frame = len; break; } case MP_NAV_EVENT_MENU_MODE: nav->nav_menu = ev->u.menu_mode.enable; if (nav->nav_menu) { mp_input_enable_section(mpctx->input, "discnav-menu", MP_INPUT_ON_TOP); } else { mp_input_disable_section(mpctx->input, "discnav-menu"); } update_state(mpctx); break; case MP_NAV_EVENT_HIGHLIGHT: { pthread_mutex_lock(&nav->osd_lock); MP_VERBOSE(nav, "highlight: %d %d %d - %d %d\n", ev->u.highlight.display, ev->u.highlight.sx, ev->u.highlight.sy, ev->u.highlight.ex, ev->u.highlight.ey); nav->highlight[0] = ev->u.highlight.sx; nav->highlight[1] = ev->u.highlight.sy; nav->highlight[2] = ev->u.highlight.ex; nav->highlight[3] = ev->u.highlight.ey; nav->hi_visible = ev->u.highlight.display; pthread_mutex_unlock(&nav->osd_lock); update_resolution(mpctx); osd_set_nav_highlight(mpctx->osd, mpctx); break; } case MP_NAV_EVENT_OVERLAY: { pthread_mutex_lock(&nav->osd_lock); for (int i = 0; i < 2; i++) { if (nav->overlays[i]) talloc_free(nav->overlays[i]); nav->overlays[i] = talloc_steal(nav, ev->u.overlay.images[i]); } pthread_mutex_unlock(&nav->osd_lock); update_resolution(mpctx); osd_set_nav_highlight(mpctx->osd, mpctx); break; } default: ; // ignore } talloc_free(ev); } update_resolution(mpctx); if (mpctx->stop_play == AT_END_OF_FILE) { if (nav->nav_still_frame > 0) { // gross hack mpctx->time_frame += nav->nav_still_frame; nav->nav_still_frame = -2; } else if (nav->nav_still_frame == -2) { struct mp_nav_cmd inp = {MP_NAV_CMD_SKIP_STILL}; run_stream_control(mpctx, STREAM_CTRL_NAV_CMD, &inp); } } if (nav->nav_draining && mpctx->stop_play == AT_END_OF_FILE) { MP_VERBOSE(nav, "execute drain\n"); struct mp_nav_cmd inp = {MP_NAV_CMD_DRAIN_OK}; run_stream_control(mpctx, STREAM_CTRL_NAV_CMD, &inp); nav->nav_draining = false; run_stream_control(mpctx, STREAM_CTRL_RESUME_CACHE, NULL); } // E.g. keep displaying still frames if (mpctx->stop_play == AT_END_OF_FILE && !nav->nav_eof) mpctx->stop_play = KEEP_PLAYING; }