From fbcced5bf068afcb4bc0a2bf1dea80ba9eac2169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Mon, 8 Jun 2026 04:45:17 +0200 Subject: [PATCH] stream_bluray: lock all controls that read cached disc state We cache some state like title properties, in some cases during deinit player thread may actually try to read it during demuxer thead read. Just add a lock, it shouldn't be called frequently to cause too much synchronization. --- stream/stream_bluray.c | 172 ++++++++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 72 deletions(-) diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c index 9e3348dfb4..79a450b401 100644 --- a/stream/stream_bluray.c +++ b/stream/stream_bluray.c @@ -127,7 +127,7 @@ struct bluray_priv_s { bool hdmv_mode; struct bd_overlay_plane ig; struct bd_overlay_plane pg; - mp_mutex overlay_lock; // guards plane fields + visibility flags + mp_mutex overlay_lock; bool menu_event_active; // BD_EVENT_MENU == 1 bool popup_supported; // BD_EVENT_POPUP == 1 @@ -452,8 +452,7 @@ static void bluray_stream_close(stream_t *s) } bd_close(priv->bd); } - if (priv->hdmv_mode) - mp_mutex_destroy(&priv->overlay_lock); + mp_mutex_destroy(&priv->overlay_lock); } static void handle_event(stream_t *s, const BD_EVENT *ev) @@ -480,75 +479,80 @@ static void handle_event(stream_t *s, const BD_EVENT *ev) break; case BD_EVENT_END_OF_TITLE: break; - case BD_EVENT_PLAYLIST: - b->current_playlist = ev->param; - b->current_title = bd_get_current_title(b->bd); + case BD_EVENT_PLAYLIST: { + int playlist = ev->param; + int title = bd_get_current_title(b->bd); if (b->title_to_playlist) { for (int i = 0; i < b->num_titles; i++) { if (b->title_to_playlist[i] == (uint32_t)ev->param) { - b->current_title = i; + title = i; break; } } } + mp_mutex_lock(&b->overlay_lock); + int cur_angle = b->current_angle; + mp_mutex_unlock(&b->overlay_lock); + BLURAY_TITLE_INFO *ti = bd_get_playlist_info(b->bd, playlist, cur_angle); + mp_mutex_lock(&b->overlay_lock); if (b->title_info) bd_free_title_info(b->title_info); - b->title_info = bd_get_playlist_info(b->bd, b->current_playlist, - b->current_angle); - if (b->hdmv_mode) { - mp_mutex_lock(&b->overlay_lock); + b->title_info = ti; + b->current_playlist = playlist; + b->current_title = title; + if (b->hdmv_mode) b->discontinuity_id++; - mp_mutex_unlock(&b->overlay_lock); - } + mp_mutex_unlock(&b->overlay_lock); break; - case BD_EVENT_TITLE: - b->current_title = bd_get_current_title(b->bd); + } + case BD_EVENT_TITLE: { + int title = bd_get_current_title(b->bd); + mp_mutex_lock(&b->overlay_lock); if (b->title_info) { bd_free_title_info(b->title_info); b->title_info = NULL; } - if (b->hdmv_mode) { - mp_mutex_lock(&b->overlay_lock); + b->current_title = title; + if (b->hdmv_mode) b->discontinuity_id++; - mp_mutex_unlock(&b->overlay_lock); - } + mp_mutex_unlock(&b->overlay_lock); break; - case BD_EVENT_ANGLE: - b->current_angle = MPMAX(0, (int)ev->param - 1); - if (b->title_info) { + } + case BD_EVENT_ANGLE: { + int angle = MPMAX(0, (int)ev->param - 1); + BLURAY_TITLE_INFO *ti = b->title_info ? bd_get_playlist_info(b->bd, b->current_playlist, angle) + : NULL; + mp_mutex_lock(&b->overlay_lock); + b->current_angle = angle; + if (ti) { bd_free_title_info(b->title_info); - b->title_info = bd_get_playlist_info(b->bd, b->current_playlist, - b->current_angle); + b->title_info = ti; } - if (b->hdmv_mode) { - mp_mutex_lock(&b->overlay_lock); + if (b->hdmv_mode) b->nav_change_id++; - mp_mutex_unlock(&b->overlay_lock); - } + mp_mutex_unlock(&b->overlay_lock); break; + } case BD_EVENT_AUDIO_STREAM: + mp_mutex_lock(&b->overlay_lock); b->audio_stream_num = ev->param; - if (b->hdmv_mode) { - mp_mutex_lock(&b->overlay_lock); + if (b->hdmv_mode) b->nav_change_id++; - mp_mutex_unlock(&b->overlay_lock); - } + mp_mutex_unlock(&b->overlay_lock); break; case BD_EVENT_PG_TEXTST_STREAM: + mp_mutex_lock(&b->overlay_lock); b->sub_stream_num = ev->param; - if (b->hdmv_mode) { - mp_mutex_lock(&b->overlay_lock); + if (b->hdmv_mode) b->nav_change_id++; - mp_mutex_unlock(&b->overlay_lock); - } + mp_mutex_unlock(&b->overlay_lock); break; case BD_EVENT_PG_TEXTST: + mp_mutex_lock(&b->overlay_lock); b->sub_visible = ev->param != 0; - if (b->hdmv_mode) { - mp_mutex_lock(&b->overlay_lock); + if (b->hdmv_mode) b->nav_change_id++; - mp_mutex_unlock(&b->overlay_lock); - } + mp_mutex_unlock(&b->overlay_lock); break; case BD_EVENT_POPUP: // ev->param: 1 if popup menu is currently available, 0 otherwise. @@ -629,24 +633,31 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) switch (cmd) { case STREAM_CTRL_GET_NUM_CHAPTERS: { + mp_mutex_lock(&b->overlay_lock); const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - *((unsigned int *) arg) = ti->chapter_count; - return STREAM_OK; + if (ti) + *((unsigned int *) arg) = ti->chapter_count; + mp_mutex_unlock(&b->overlay_lock); + return ti ? STREAM_OK : STREAM_UNSUPPORTED; } case STREAM_CTRL_GET_CHAPTER_TIME: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; int chapter = *(double *)arg; - double time = MP_NOPTS_VALUE; - if (chapter >= 0 && chapter < ti->chapter_count) - time = BD_TIME_TO_MP(ti->chapters[chapter].start); - if (time == MP_NOPTS_VALUE) - return STREAM_ERROR; - *(double *)arg = time; - return STREAM_OK; + mp_mutex_lock(&b->overlay_lock); + const BLURAY_TITLE_INFO *ti = b->title_info; + int rc = STREAM_UNSUPPORTED; + if (ti) { + double time = MP_NOPTS_VALUE; + if (chapter >= 0 && chapter < ti->chapter_count) + time = BD_TIME_TO_MP(ti->chapters[chapter].start); + if (time != MP_NOPTS_VALUE) { + *(double *)arg = time; + rc = STREAM_OK; + } else { + rc = STREAM_ERROR; + } + } + mp_mutex_unlock(&b->overlay_lock); + return rc; } case STREAM_CTRL_SET_CURRENT_TITLE: { const uint32_t title = *((unsigned int*)arg); @@ -658,11 +669,15 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) } if (title >= b->num_titles || !play_title(b, title)) return STREAM_UNSUPPORTED; + mp_mutex_lock(&b->overlay_lock); b->current_title = title; + mp_mutex_unlock(&b->overlay_lock); return STREAM_OK; } case STREAM_CTRL_GET_CURRENT_TITLE: { + mp_mutex_lock(&b->overlay_lock); *((unsigned int *) arg) = b->current_title; + mp_mutex_unlock(&b->overlay_lock); return STREAM_OK; } case STREAM_CTRL_GET_NUM_TITLES: { @@ -670,11 +685,12 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) return STREAM_OK; } case STREAM_CTRL_GET_TIME_LENGTH: { + mp_mutex_lock(&b->overlay_lock); const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - *((double *) arg) = BD_TIME_TO_MP(ti->duration); - return STREAM_OK; + if (ti) + *((double *) arg) = BD_TIME_TO_MP(ti->duration); + mp_mutex_unlock(&b->overlay_lock); + return ti ? STREAM_OK : STREAM_UNSUPPORTED; } case STREAM_CTRL_GET_CURRENT_TIME: { *((double *) arg) = BD_TIME_TO_MP(bd_tell_time(b->bd)); @@ -688,25 +704,31 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) return STREAM_OK; } case STREAM_CTRL_GET_NUM_ANGLES: { + mp_mutex_lock(&b->overlay_lock); const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - *((int *) arg) = ti->angle_count; - return STREAM_OK; + if (ti) + *((int *) arg) = ti->angle_count; + mp_mutex_unlock(&b->overlay_lock); + return ti ? STREAM_OK : STREAM_UNSUPPORTED; } case STREAM_CTRL_GET_ANGLE: { + mp_mutex_lock(&b->overlay_lock); *((int *) arg) = b->current_angle + 1; + mp_mutex_unlock(&b->overlay_lock); return STREAM_OK; } case STREAM_CTRL_SET_ANGLE: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; int angle = *((int *) arg); - if (angle < 1 || angle > ti->angle_count) + mp_mutex_lock(&b->overlay_lock); + const BLURAY_TITLE_INFO *ti = b->title_info; + bool ok = ti && angle >= 1 && angle <= ti->angle_count; + if (ok) + b->current_angle = angle - 1; + int cur = b->current_angle; + mp_mutex_unlock(&b->overlay_lock); + if (!ok) return STREAM_UNSUPPORTED; - b->current_angle = angle - 1; - bd_seamless_angle_change(b->bd, b->current_angle); + bd_seamless_angle_change(b->bd, cur); return STREAM_OK; } case STREAM_CTRL_GET_TITLE_LENGTH: { @@ -732,6 +754,8 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) return STREAM_OK; } case STREAM_CTRL_GET_LANG: { + int rc = STREAM_ERROR; + mp_mutex_lock(&b->overlay_lock); const BLURAY_TITLE_INFO *ti = b->title_info; if (ti && ti->clip_count) { struct stream_lang_req *req = arg; @@ -751,11 +775,13 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) BLURAY_STREAM_INFO *i = &si[n]; if (i->pid == req->id) { snprintf(req->name, sizeof(req->name), "%.4s", i->lang); - return STREAM_OK; + rc = STREAM_OK; + break; } } } - return STREAM_ERROR; + mp_mutex_unlock(&b->overlay_lock); + return rc; } case STREAM_CTRL_GET_DISC_NAME: { const struct meta_dl *meta = bd_get_meta(b->bd); @@ -816,6 +842,7 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) int audio_pid = -1; int sub_pid = -1; bool no_audio = false; + mp_mutex_lock(&b->overlay_lock); const BLURAY_TITLE_INFO *ti = b->title_info; if (ti && ti->clip_count) { const BLURAY_CLIP_INFO *ci = &ti->clips[0]; @@ -843,9 +870,9 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) .angle = b->current_angle + 1, .num_angles = ti ? ti->angle_count : 0, }; + mp_mutex_unlock(&b->overlay_lock); return STREAM_OK; } - mp_mutex_lock(&b->overlay_lock); // BD_EVENT_MENU isn't fired by BD-J (it's HDMV-only), so treat any // visible BD-J plane as an active menu too. bool any_overlay = b->ig.visible || b->pg.visible; @@ -1008,6 +1035,8 @@ static int bluray_stream_open_internal(stream_t *s) b->opts_cache = opts_cache; b->opts = opts_cache->opts; + mp_mutex_init(&b->overlay_lock); + int ret = 0; char *device = NULL; /* find the requested device */ @@ -1101,7 +1130,6 @@ static int bluray_stream_open_internal(stream_t *s) MP_VERBOSE(s, "bdnav: cfg_title=%d hdmv_mode=%d\n", b->cfg_title, b->hdmv_mode); if (b->hdmv_mode) { - mp_mutex_init(&b->overlay_lock); bd_register_overlay_proc(bd, b, bd_yuv_overlay_cb); if (info->bdj_detected) bd_register_argb_overlay_proc(bd, b, bd_argb_overlay_cb, NULL);