diff --git a/player/discnav.c b/player/discnav.c index afe9cec91a..cde474e16c 100644 --- a/player/discnav.c +++ b/player/discnav.c @@ -153,25 +153,13 @@ bool disc_nav_mouse_pos_to_src(struct MPContext *mpctx, int src_w, int src_h, } // Push the current menu/highlight state to the dvd_subtitle decoders. -static void push_dvd_overlay(struct MPContext *mpctx, - struct stream_nav_state *nav, bool visible) +static void push_dvd_overlay(struct MPContext *mpctx, struct stream_nav_state *nav) { - struct mp_dvdnav_hli hli = { - .show = visible, - .change_id = nav->change_id, - }; - if (visible) { - hli.x = nav->hl_x; - hli.y = nav->hl_y; - hli.w = nav->hl_w; - hli.h = nav->hl_h; - memcpy(hli.palette, nav->hl_palette, sizeof(hli.palette)); - } for (int n = 0; n < mpctx->num_tracks; n++) { struct track *t = mpctx->tracks[n]; if (!is_dvd_sub_track(t) || !t->d_sub) continue; - sub_control(t->d_sub, SD_CTRL_APPLY_DVDNAV, &hli); + sub_control(t->d_sub, SD_CTRL_APPLY_DVDNAV, nav); } } @@ -494,12 +482,13 @@ void disc_nav_update(struct MPContext *mpctx) sync_disc_track_selection(mpctx, s, &nav); bool is_bd = strcmp(s->info->name, "bd") == 0 || strcmp(s->info->name, "bdmv/bluray") == 0; - bool visible = nav.menu_active && (is_bd || (nav.hl_w > 0 && nav.hl_h > 0)); + bool visible = nav.menu_active && + (is_bd || (mp_rect_w(nav.hl.rect) > 0 && mp_rect_h(nav.hl.rect) > 0)); if (is_bd) { push_bd_overlay(mpctx, s, &nav, visible); } else { - push_dvd_overlay(mpctx, &nav, visible); + push_dvd_overlay(mpctx, &nav); ensure_menu_sub_selection(mpctx, nav.menu_active); } diff --git a/stream/stream.h b/stream/stream.h index 49fc3262ef..2e1a72a0f9 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -25,6 +25,7 @@ #include #include +#include "common/common.h" #include "misc/bstr.h" // Minimum guaranteed buffer and seek-back size. For any reads <= of this size, @@ -142,6 +143,12 @@ static inline bool stream_nav_action_activates(enum stream_nav_action a) } } +// A DVD subpicture button highlight. +struct mp_dvdnav_highlight { + struct mp_rect rect; // button rectangle in SPU/source coords + uint32_t palette[4]; // replacement colors for SPU pixel values 0..3 +}; + // Snapshot of the stream's menu state. struct stream_nav_state { bool nav_active; // interactive disc navigation is enabled @@ -149,10 +156,8 @@ struct stream_nav_state { bool has_popup; // disc supports a popup menu (BD only) bool still_active; // holding an indefinite still frame int src_w, src_h; // dimensions of the coordinate space mouse uses - // Highlight rectangle of the currently focused button (in src coords). - int hl_x, hl_y, hl_w, hl_h; - uint32_t hl_palette[4]; // BGRA highlight palette (0xAARRGGBB, straight) - uint32_t change_id; // Bumped whenever any of the above changes + struct mp_dvdnav_highlight hl; // focused button highlight (DVD only) + uint32_t change_id; // Bumped whenever any of the above changes uint32_t discontinuity_id; // Bumped when the stream's source position jumps // Disc-driven track selection. diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c index b0753db2f4..c92c700ef5 100644 --- a/stream/stream_dvdnav.c +++ b/stream/stream_dvdnav.c @@ -79,8 +79,7 @@ struct priv { bool in_menu; int current_button; // mirror of libdvdnav HL_BTNN_REG - int btn_rect[4]; // x, y, w, h in source coords - uint32_t hl_palette[4]; // 0xAARRGGBB for SPU pixel values 0..3 + struct mp_dvdnav_highlight hl; // focused button rect + palette uint32_t nav_change_id; uint32_t discontinuity_id; // bumped on actions that may jump bool pending_drain; // emit one EOF at the next jump boundary @@ -241,8 +240,7 @@ static bool in_menu_domain(dvdnav_t *dvdnav) static void compute_button_rect(struct priv *priv, pci_t *pci, int btn) { - priv->btn_rect[0] = priv->btn_rect[1] = 0; - priv->btn_rect[2] = priv->btn_rect[3] = 0; + priv->hl.rect = (struct mp_rect){0}; if (btn <= 0 || btn > pci->hli.hl_gi.btn_ns) return; // btni_t is packed and full of bitfields, memcpy to ensure correct alignment. @@ -250,10 +248,11 @@ static void compute_button_rect(struct priv *priv, pci_t *pci, int btn) memcpy(&b, &pci->hli.btnit[btn - 1], sizeof(b)); int xs = b.x_start, xe = b.x_end; int ys = b.y_start, ye = b.y_end; - priv->btn_rect[0] = xs; - priv->btn_rect[1] = ys; - priv->btn_rect[2] = xe > xs ? xe - xs : 0; - priv->btn_rect[3] = ye > ys ? ye - ys : 0; + priv->hl.rect = (struct mp_rect){ + .x0 = xs, .y0 = ys, + .x1 = xe > xs ? xe : xs, + .y1 = ye > ys ? ye : ys, + }; } // Resolve the 4-entry "select-state" highlight palette for the focused button. @@ -262,7 +261,7 @@ static void compute_button_rect(struct priv *priv, pci_t *pci, int btn) // alphas. static void compute_highlight_palette(struct priv *priv, pci_t *pci, int btn) { - memset(priv->hl_palette, 0, sizeof(priv->hl_palette)); + memset(priv->hl.palette, 0, sizeof(priv->hl.palette)); if (!priv->spu_clut_valid || btn <= 0 || btn > pci->hli.hl_gi.btn_ns) return; btni_t b; @@ -289,7 +288,7 @@ static void compute_highlight_palette(struct priv *priv, pci_t *pci, int btn) int c[3]; mp_map_fixp_color(&cmatrix, 8, y, 8, c); uint32_t alpha = (a << 4) | a; - priv->hl_palette[i] = (alpha << 24) | (c[0] << 16) | (c[1] << 8) | c[2]; + priv->hl.palette[i] = (alpha << 24) | (c[0] << 16) | (c[1] << 8) | c[2]; } } @@ -334,11 +333,8 @@ static void refresh_video_resolution(struct priv *priv) static void update_highlight(struct priv *priv) { int prev_btn = priv->current_button; - int prev_x = priv->btn_rect[0], prev_y = priv->btn_rect[1]; - int prev_w = priv->btn_rect[2], prev_h = priv->btn_rect[3]; bool prev_menu = priv->in_menu; - uint32_t prev_palette[4]; - memcpy(prev_palette, priv->hl_palette, sizeof(prev_palette)); + struct mp_dvdnav_highlight prev_hl = priv->hl; priv->in_menu = in_menu_domain(priv->dvdnav); pci_t *pci = priv->in_menu ? dvdnav_get_current_nav_pci(priv->dvdnav) : NULL; @@ -362,9 +358,7 @@ static void update_highlight(struct priv *priv) if (!highlight_live || btn <= 0 || btn > pci->hli.hl_gi.btn_ns) { priv->current_button = 0; - priv->btn_rect[0] = priv->btn_rect[1] = 0; - priv->btn_rect[2] = priv->btn_rect[3] = 0; - memset(priv->hl_palette, 0, sizeof(priv->hl_palette)); + priv->hl = (struct mp_dvdnav_highlight){0}; } else { priv->current_button = btn; compute_button_rect(priv, pci, btn); @@ -372,9 +366,7 @@ static void update_highlight(struct priv *priv) } if (priv->in_menu != prev_menu || priv->current_button != prev_btn || - priv->btn_rect[0] != prev_x || priv->btn_rect[1] != prev_y || - priv->btn_rect[2] != prev_w || priv->btn_rect[3] != prev_h || - memcmp(prev_palette, priv->hl_palette, sizeof(prev_palette)) != 0) + memcmp(&prev_hl, &priv->hl, sizeof(prev_hl)) != 0) { priv->nav_change_id++; } @@ -909,10 +901,7 @@ static int control(stream_t *stream, int cmd, void *arg) .still_active = priv->still_active, .src_w = priv->src_w, .src_h = priv->src_h, - .hl_x = priv->btn_rect[0], - .hl_y = priv->btn_rect[1], - .hl_w = priv->btn_rect[2], - .hl_h = priv->btn_rect[3], + .hl = priv->hl, .change_id = priv->nav_change_id, .discontinuity_id = priv->discontinuity_id, .active_audio_id = dvd_physical_audio_to_substream(priv, priv->audio_physical), @@ -921,7 +910,6 @@ static int control(stream_t *stream, int cmd, void *arg) .angle = cur_angle, .num_angles = num_angles, }; - memcpy(st->hl_palette, priv->hl_palette, sizeof(st->hl_palette)); return STREAM_OK; } } diff --git a/sub/dec_sub.h b/sub/dec_sub.h index b236aa9da1..63832cb68d 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -5,6 +5,7 @@ #include #include "player/core.h" +#include "stream/stream.h" #include "osd.h" struct sh_stream; @@ -21,14 +22,7 @@ enum sd_ctrl { SD_CTRL_SET_VIDEO_DEF_FPS, SD_CTRL_RESET_SOFT, SD_CTRL_UPDATE_OPTS, - SD_CTRL_APPLY_DVDNAV, // struct mp_dvdnav_hli * -}; - -struct mp_dvdnav_hli { - bool show; - int x, y, w, h; // button rect in SPU/source coords - uint32_t palette[4]; // 0xAARRGGBB, straight alpha - uint32_t change_id; // bumped on any visible change + SD_CTRL_APPLY_DVDNAV, // const struct stream_nav_state * }; enum sd_text_type { diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index 3d0a4b3131..ce9416e8da 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -72,8 +72,9 @@ struct sd_lavc_priv { int num_seekpoints; struct bitmap_packer *packer; - // DVD-nav per-pixel highlight overlay state. - struct mp_dvdnav_hli hli; + // DVD-nav menu/highlight overlay state. + bool menu_active; // in-menu: gates the highlight overlay + struct mp_dvdnav_highlight hl; // focused button rect + palette uint32_t hli_change_id; }; @@ -300,21 +301,20 @@ static void read_sub_bitmaps(struct sd *sd, struct sub *sub) convert_pal(pal, 256, opts->sub_gray); // DVD navigation highlight - bool hli_active = priv->hli.show && - priv->hli.w > 0 && priv->hli.h > 0 && - r->x < priv->hli.x + priv->hli.w && - r->y < priv->hli.y + priv->hli.h && - r->x + r->w > priv->hli.x && - r->y + r->h > priv->hli.y; + struct mp_rect hlr = priv->hl.rect; + bool hli_active = priv->menu_active && + mp_rect_w(hlr) > 0 && mp_rect_h(hlr) > 0 && + r->x < hlr.x1 && r->y < hlr.y1 && + r->x + r->w > hlr.x0 && r->y + r->h > hlr.y0; uint32_t hli_pal[4] = {0}; if (hli_active) { - memcpy(hli_pal, priv->hli.palette, sizeof(hli_pal)); + memcpy(hli_pal, priv->hl.palette, sizeof(hli_pal)); convert_pal(hli_pal, 4, opts->sub_gray); } - int hli_x0 = priv->hli.x - r->x; - int hli_y0 = priv->hli.y - r->y; - int hli_x1 = hli_x0 + priv->hli.w; - int hli_y1 = hli_y0 + priv->hli.h; + int hli_x0 = hlr.x0 - r->x; + int hli_y0 = hlr.y0 - r->y; + int hli_x1 = hlr.x1 - r->x; + int hli_y1 = hlr.y1 - r->y; for (int y = -padding; y < b->h + padding; y++) { uint32_t *out = (uint32_t*)((char*)b->bitmap + y * b->stride); @@ -760,13 +760,20 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg) priv->video_params = *(struct mp_image_params *)arg; return CONTROL_OK; case SD_CTRL_APPLY_DVDNAV: { - struct mp_dvdnav_hli *hli = arg; - if (priv->hli_change_id == hli->change_id) - return CONTROL_OK; - priv->hli = *hli; - priv->hli_change_id = hli->change_id; + const struct stream_nav_state *nav = arg; + bool menu_closed = priv->menu_active && !nav->menu_active; + bool changed = priv->hli_change_id != nav->change_id; + priv->menu_active = nav->menu_active; + priv->hl = nav->hl; + priv->hli_change_id = nav->change_id; + // Don't let menu subpictures leak into title playback. + if (menu_closed) { + for (int n = 0; n < MAX_QUEUE; n++) + clear_sub(&priv->subs[n]); + } // Re-render any decoded subtitles, after style update. - rerender_queued_subs(sd); + if (changed) + rerender_queued_subs(sd); return CONTROL_OK; } default: