diff --git a/player/playloop.c b/player/playloop.c index aa3eb637ee..2a4509ab95 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -1095,7 +1095,7 @@ void run_playloop(struct MPContext *mpctx) handle_dummy_ticks(mpctx); update_osd_msg(mpctx); - if (!mpctx->video_out) + if (!mpctx->vo_chain) update_subtitles(mpctx, mpctx->playback_pts); handle_eof(mpctx); diff --git a/player/sub.c b/player/sub.c index c4a24fe011..04af1e1e15 100644 --- a/player/sub.c +++ b/player/sub.c @@ -112,6 +112,19 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts, if (mpctx->current_track[0][STREAM_SUB] == track && !mpctx->video_out) term_osd_set_subs(mpctx, sub_get_text(dec_sub, video_pts)); + // Handle displaying subtitles on VO with no video being played. This is + // quite differently, because normally subtitles are redrawn on new video + // frames, using the video frames' timestamps. + if (mpctx->video_out && !mpctx->vo_chain) { + if (osd_get_force_video_pts(mpctx->osd) != video_pts) { + osd_set_force_video_pts(mpctx->osd, video_pts); + osd_query_and_reset_want_redraw(mpctx->osd); + vo_redraw(mpctx->video_out); + } + // Force an arbitrary minimum FPS + mp_set_timeout(mpctx, 0.1); + } + return true; } diff --git a/player/video.c b/player/video.c index 21babe016e..7a76f4dc8e 100644 --- a/player/video.c +++ b/player/video.c @@ -482,6 +482,9 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src) update_window_title(mpctx, true); + // Undo what the subtitle path does if mpctx->vo_chain is unset. + osd_set_force_video_pts(mpctx->osd, MP_NOPTS_VALUE); + struct vo_chain *vo_c = talloc_zero(NULL, struct vo_chain); mpctx->vo_chain = vo_c; vo_c->log = mpctx->log; diff --git a/sub/osd.c b/sub/osd.c index dfe75b7698..bf6233a0b1 100644 --- a/sub/osd.c +++ b/sub/osd.c @@ -119,6 +119,7 @@ struct osd_state *osd_create(struct mpv_global *global) .opts = global->opts, .global = global, .log = mp_log_new(osd, global->log, "osd"), + .force_video_pts = MP_NOPTS_VALUE, }; pthread_mutex_init(&osd->lock, NULL); @@ -190,6 +191,21 @@ void osd_set_render_subs_in_filter(struct osd_state *osd, bool s) pthread_mutex_unlock(&osd->lock); } +void osd_set_force_video_pts(struct osd_state *osd, double video_pts) +{ + pthread_mutex_lock(&osd->lock); + osd->force_video_pts = video_pts; + pthread_mutex_unlock(&osd->lock); +} + +double osd_get_force_video_pts(struct osd_state *osd) +{ + pthread_mutex_lock(&osd->lock); + double pts = osd->force_video_pts; + pthread_mutex_unlock(&osd->lock); + return pts; +} + void osd_set_progbar(struct osd_state *osd, struct osd_progbar_state *s) { pthread_mutex_lock(&osd->lock); @@ -288,6 +304,9 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res, { pthread_mutex_lock(&osd->lock); + if (osd->force_video_pts != MP_NOPTS_VALUE) + video_pts = osd->force_video_pts; + if (draw_flags & OSD_DRAW_SUB_FILTER) draw_flags |= OSD_DRAW_SUB_ONLY; diff --git a/sub/osd.h b/sub/osd.h index cf66392904..755aca9969 100644 --- a/sub/osd.h +++ b/sub/osd.h @@ -155,6 +155,8 @@ void osd_set_sub(struct osd_state *osd, int index, struct dec_sub *dec_sub); bool osd_get_render_subs_in_filter(struct osd_state *osd); void osd_set_render_subs_in_filter(struct osd_state *osd, bool s); +void osd_set_force_video_pts(struct osd_state *osd, double video_pts); +double osd_get_force_video_pts(struct osd_state *osd); struct osd_progbar_state { int type; // <0: disabled, 1-255: symbol, else: no symbol diff --git a/sub/osd_state.h b/sub/osd_state.h index fbccd85e70..cce415a1b9 100644 --- a/sub/osd_state.h +++ b/sub/osd_state.h @@ -67,6 +67,7 @@ struct osd_state { struct osd_object *objs[MAX_OSD_PARTS]; bool render_subs_in_filter; + double force_video_pts; bool want_redraw; bool want_redraw_notification;