diff options
author | wm4 <wm4@nowhere> | 2013-12-24 17:46:14 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2013-12-24 17:46:14 +0100 |
commit | 3720b3f17d4951ab839418b5cbfd1a85eb74adba (patch) | |
tree | 819b311b4c224ba2fd3dcd0efe8008a83f2cc938 | |
parent | 9292f537d661af16321fd35eb0016e830594863b (diff) | |
download | mpv-3720b3f17d4951ab839418b5cbfd1a85eb74adba.tar.bz2 mpv-3720b3f17d4951ab839418b5cbfd1a85eb74adba.tar.xz |
player: add --secondary-sid for displaying a second subtitle stream
This is relatively hacky, but it's Christmas, so it's ok. This does two
things: 1. allow selecting two subtitle tracks, and 2. include a hack
that renders the second subtitle always as toptitle. See manpage
additions how to use this.
-rw-r--r-- | DOCS/man/en/input.rst | 1 | ||||
-rw-r--r-- | DOCS/man/en/options.rst | 22 | ||||
-rw-r--r-- | options/options.c | 1 | ||||
-rw-r--r-- | options/options.h | 1 | ||||
-rw-r--r-- | player/command.c | 49 | ||||
-rw-r--r-- | player/core.h | 7 | ||||
-rw-r--r-- | player/dvdnav.c | 4 | ||||
-rw-r--r-- | player/loadfile.c | 51 | ||||
-rw-r--r-- | player/osd.c | 4 | ||||
-rw-r--r-- | player/playloop.c | 6 | ||||
-rw-r--r-- | player/sub.c | 125 | ||||
-rw-r--r-- | player/video.c | 3 | ||||
-rw-r--r-- | sub/osd.c | 27 | ||||
-rw-r--r-- | sub/osd.h | 16 | ||||
-rw-r--r-- | sub/osd_libass.c | 9 |
15 files changed, 220 insertions, 106 deletions
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index aca35177a6..a5de6df18d 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -595,6 +595,7 @@ Name W Comment ``video-unscaled`` x see ``--video-unscaled`` ``program`` x switch TS program (write-only) ``sid`` x current subtitle track (similar to ``--sid``) +``secondary-sid`` x secondary subtitle track (``--secondary-sid``) ``sub`` x alias for ``sid`` ``sub-delay`` x see ``--sub-delay`` ``sub-pos`` x see ``--sub-pos`` diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index a1f48d32a1..b2f9d30b68 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -2017,6 +2017,28 @@ OPTIONS Specify the screen width for video output drivers which do not know the screen resolution, like ``x11`` and TV-out. +``--secondary-sid=<ID|auto|no>`` + Select a secondary subtitle stream. This is similar to ``--sid``. If a + secondary subtitle is selected, it will be rendered as toptitle (i.e. on + the top of the screen) alongside the normal subtitle, and provides a way + to render two subtitles at once. + + there are some caveats associated with this feature. For example, secondary + subtitles are never shown on the terminal if video is disabled. + + .. note:: + + Styling and interpretation of any formatting tags is disabled for the + secondary subtitle. Internally, the same mechanism as ``--no-ass`` is + used to strip the styling. + + .. note:: + + If the main subtitle stream contains formatting tags which display the + subtitle at the top of the screen, it will overlap with the secondary + subtitle. To prevent this, you could use ``--no-ass`` to disable + styling in the main subtitle stream. + ``--show-profile=<profile>`` Show the description and content of a profile. diff --git a/options/options.c b/options/options.c index ea1de3e3f6..5693a34cd0 100644 --- a/options/options.c +++ b/options/options.c @@ -301,6 +301,7 @@ const m_option_t mp_opts[] = { OPT_TRACKCHOICE("aid", audio_id), OPT_TRACKCHOICE("vid", video_id), OPT_TRACKCHOICE("sid", sub_id), + OPT_TRACKCHOICE("secondary-sid", sub2_id), OPT_FLAG_STORE("no-sub", sub_id, 0, -2), OPT_FLAG_STORE("no-video", video_id, 0, -2), OPT_FLAG_STORE("no-audio", audio_id, 0, -2), diff --git a/options/options.h b/options/options.h index 1d997d363b..4889201b93 100644 --- a/options/options.h +++ b/options/options.h @@ -147,6 +147,7 @@ typedef struct MPOpts { int audio_id; int video_id; int sub_id; + int sub2_id; char **audio_lang; char **sub_lang; int audio_display; diff --git a/player/command.c b/player/command.c index 3d15d96676..e59a2d50e8 100644 --- a/player/command.c +++ b/player/command.c @@ -980,14 +980,23 @@ static int mp_property_balance(m_option_t *prop, int action, void *arg, return M_PROPERTY_NOT_IMPLEMENTED; } -static struct track* track_next(struct MPContext *mpctx, enum stream_type type, - int direction, struct track *track) +static struct track* track_next(struct MPContext *mpctx, int order, + enum stream_type type, int direction, + struct track *track) { assert(direction == -1 || direction == +1); struct track *prev = NULL, *next = NULL; bool seen = track == NULL; for (int n = 0; n < mpctx->num_tracks; n++) { struct track *cur = mpctx->tracks[n]; + // One track can be selected only one time - pretend already selected + // tracks don't exist. + for (int r = 0; r < NUM_PTRACKS; r++) { + if (r != order && mpctx->current_track[r][type] == cur) + cur = NULL; + } + if (!cur) + continue; if (cur->type == type) { if (cur == track) { seen = true; @@ -1005,11 +1014,12 @@ static struct track* track_next(struct MPContext *mpctx, enum stream_type type, } static int property_switch_track(m_option_t *prop, int action, void *arg, - MPContext *mpctx, enum stream_type type) + MPContext *mpctx, int order, + enum stream_type type) { if (!mpctx->num_sources) return M_PROPERTY_UNAVAILABLE; - struct track *track = mpctx->current_track[0][type]; + struct track *track = mpctx->current_track[order][type]; switch (action) { case M_PROPERTY_GET: @@ -1034,12 +1044,13 @@ static int property_switch_track(m_option_t *prop, int action, void *arg, case M_PROPERTY_SWITCH: { struct m_property_switch_arg *sarg = arg; - mp_switch_track(mpctx, type, - track_next(mpctx, type, sarg->inc >= 0 ? +1 : -1, track)); + mp_switch_track_n(mpctx, order, type, + track_next(mpctx, order, type, sarg->inc >= 0 ? +1 : -1, track)); return M_PROPERTY_OK; } case M_PROPERTY_SET: - mp_switch_track(mpctx, type, mp_track_by_tid(mpctx, type, *(int *)arg)); + track = mp_track_by_tid(mpctx, type, *(int *)arg); + mp_switch_track_n(mpctx, order, type, track); return M_PROPERTY_OK; } return mp_property_generic_option(prop, action, arg, mpctx); @@ -1102,14 +1113,14 @@ static int property_list_tracks(m_option_t *prop, int action, void *arg, static int mp_property_audio(m_option_t *prop, int action, void *arg, MPContext *mpctx) { - return property_switch_track(prop, action, arg, mpctx, STREAM_AUDIO); + return property_switch_track(prop, action, arg, mpctx, 0, STREAM_AUDIO); } /// Selected video id (RW) static int mp_property_video(m_option_t *prop, int action, void *arg, MPContext *mpctx) { - return property_switch_track(prop, action, arg, mpctx, STREAM_VIDEO); + return property_switch_track(prop, action, arg, mpctx, 0, STREAM_VIDEO); } static struct track *find_track_by_demuxer_id(MPContext *mpctx, @@ -1623,7 +1634,13 @@ static int property_osd_helper(m_option_t *prop, int action, void *arg, static int mp_property_sub(m_option_t *prop, int action, void *arg, MPContext *mpctx) { - return property_switch_track(prop, action, arg, mpctx, STREAM_SUB); + return property_switch_track(prop, action, arg, mpctx, 0, STREAM_SUB); +} + +static int mp_property_sub2(m_option_t *prop, int action, void *arg, + MPContext *mpctx) +{ + return property_switch_track(prop, action, arg, mpctx, 1, STREAM_SUB); } /// Subtitle delay (RW) @@ -1997,6 +2014,7 @@ static const m_option_t mp_properties[] = { // Subs M_OPTION_PROPERTY_CUSTOM("sid", mp_property_sub), + M_OPTION_PROPERTY_CUSTOM("secondary-sid", mp_property_sub2), M_OPTION_PROPERTY_CUSTOM("sub-delay", mp_property_sub_delay), M_OPTION_PROPERTY_CUSTOM("sub-pos", mp_property_sub_pos), M_OPTION_PROPERTY_CUSTOM("sub-visibility", property_osd_helper), @@ -2109,6 +2127,7 @@ static struct property_osd_display { { "angle", "Angle" }, // subs { "sub", "Subtitles" }, + { "secondary-sid", "Secondary subtitles" }, { "sub-pos", "Sub position" }, { "sub-delay", "Sub delay", .osd_id = OSD_MSG_SUB_DELAY }, { "sub-visibility", "Subtitles" }, @@ -2714,12 +2733,13 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) } case MP_CMD_SUB_STEP: - case MP_CMD_SUB_SEEK: - if (mpctx->osd->dec_sub) { + case MP_CMD_SUB_SEEK: { + struct osd_object *obj = mpctx->osd->objs[OSDTYPE_SUB]; + if (obj->dec_sub) { double a[2]; - a[0] = mpctx->video_pts - mpctx->osd->video_offset + opts->sub_delay; + a[0] = mpctx->video_pts - obj->video_offset + opts->sub_delay; a[1] = cmd->args[0].v.i; - if (sub_control(mpctx->osd->dec_sub, SD_CTRL_SUB_STEP, a) > 0) { + if (sub_control(obj->dec_sub, SD_CTRL_SUB_STEP, a) > 0) { if (cmd->id == MP_CMD_SUB_STEP) { opts->sub_delay += a[0]; osd_changed_all(mpctx->osd); @@ -2742,6 +2762,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) } } break; + } case MP_CMD_OSD: { int v = cmd->args[0].v.i; diff --git a/player/core.h b/player/core.h index cad18a6b36..c016dcf4f7 100644 --- a/player/core.h +++ b/player/core.h @@ -35,6 +35,7 @@ #define INITIALIZED_ACODEC 1024 #define INITIALIZED_VCODEC 2048 #define INITIALIZED_SUB 4096 +#define INITIALIZED_SUB2 8192 #define INITIALIZED_ALL 0xFFFF @@ -208,7 +209,7 @@ typedef struct MPContext { struct dec_video *d_video; struct dec_audio *d_audio; - struct dec_sub *d_sub; + struct dec_sub *d_sub[2]; // Uses: accessing metadata (consider ordered chapters case, where the main // demuxer defines metadata), or special purpose demuxers like TV. @@ -439,9 +440,9 @@ void handle_force_window(struct MPContext *mpctx, bool reconfig); void add_frame_pts(struct MPContext *mpctx, double pts); // sub.c -void reset_subtitles(struct MPContext *mpctx); +void reset_subtitles(struct MPContext *mpctx, int order); void uninit_subs(struct demuxer *demuxer); -void reinit_subs(struct MPContext *mpctx); +void reinit_subs(struct MPContext *mpctx, int order); void update_osd_msg(struct MPContext *mpctx); void update_subtitles(struct MPContext *mpctx); diff --git a/player/dvdnav.c b/player/dvdnav.c index e90a65e035..bc14e7c35f 100644 --- a/player/dvdnav.c +++ b/player/dvdnav.c @@ -222,8 +222,8 @@ void mp_nav_get_highlight(struct osd_state *osd, struct mp_osd_res res, nav->hi_elem = sub; int sizes[2] = {0}; - if (mpctx->d_sub) - sub_control(mpctx->d_sub, SD_CTRL_GET_RESOLUTION, sizes); + if (mpctx->d_sub[0]) + sub_control(mpctx->d_sub[0], SD_CTRL_GET_RESOLUTION, sizes); if (sizes[0] < 1 || sizes[1] < 1) { struct mp_image_params vid = {0}; if (mpctx->d_video) diff --git a/player/loadfile.c b/player/loadfile.c index 8bf29f22f3..99b669f109 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -62,6 +62,16 @@ #include "stream/dvbin.h" #endif +static void uninit_sub(struct MPContext *mpctx, int order) +{ + if (mpctx->d_sub[order]) + sub_reset(mpctx->d_sub[order]); + mpctx->d_sub[order] = NULL; // Note: not free'd. + mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB]->dec_sub = NULL; + reset_subtitles(mpctx, order); + reselect_demux_streams(mpctx); +} + void uninit_player(struct MPContext *mpctx, unsigned int mask) { struct MPOpts *opts = mpctx->opts; @@ -80,12 +90,11 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mask & INITIALIZED_SUB) { mpctx->initialized_flags &= ~INITIALIZED_SUB; - if (mpctx->d_sub) - sub_reset(mpctx->d_sub); - mpctx->d_sub = NULL; // Note: not free'd. - mpctx->osd->dec_sub = NULL; - reset_subtitles(mpctx); - reselect_demux_streams(mpctx); + uninit_sub(mpctx, 0); + } + if (mask & INITIALIZED_SUB2) { + mpctx->initialized_flags &= ~INITIALIZED_SUB2; + uninit_sub(mpctx, 1); } if (mask & INITIALIZED_LIBASS) { @@ -110,7 +119,8 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mask & INITIALIZED_DEMUXER) { mpctx->initialized_flags &= ~INITIALIZED_DEMUXER; assert(!(mpctx->initialized_flags & - (INITIALIZED_VCODEC | INITIALIZED_ACODEC | INITIALIZED_SUB))); + (INITIALIZED_VCODEC | INITIALIZED_ACODEC | + INITIALIZED_SUB2 | INITIALIZED_SUB))); for (int i = 0; i < mpctx->num_tracks; i++) { talloc_free(mpctx->tracks[i]); } @@ -119,7 +129,8 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) for (int t = 0; t < STREAM_TYPE_COUNT; t++) mpctx->current_track[r][t] = NULL; } - assert(!mpctx->d_video && !mpctx->d_audio && !mpctx->d_sub); + assert(!mpctx->d_video && !mpctx->d_audio && + !mpctx->d_sub[0] && !mpctx->d_sub[1]); mpctx->master_demuxer = NULL; for (int i = 0; i < mpctx->num_sources; i++) { uninit_subs(mpctx->sources[i]); @@ -324,7 +335,7 @@ bool timeline_set_part(struct MPContext *mpctx, int i, bool force) enum stop_play_reason orig_stop_play = mpctx->stop_play; if (!mpctx->d_video && mpctx->stop_play == KEEP_PLAYING) mpctx->stop_play = AT_END_OF_FILE; // let audio uninit drain data - uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts->fixed_vo ? 0 : INITIALIZED_VO) | (mpctx->opts->gapless_audio ? 0 : INITIALIZED_AO) | INITIALIZED_ACODEC | INITIALIZED_SUB); + uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts->fixed_vo ? 0 : INITIALIZED_VO) | (mpctx->opts->gapless_audio ? 0 : INITIALIZED_AO) | INITIALIZED_ACODEC | INITIALIZED_SUB | INITIALIZED_SUB2); mpctx->stop_play = orig_stop_play; mpctx->demuxer = n->source; @@ -405,8 +416,10 @@ static struct track *add_stream_track(struct MPContext *mpctx, track->demuxer_id = stream->demuxer_id; // Initialize lazily selected track demuxer_select_track(track->demuxer, stream, track->selected); - if (track->selected) - reinit_subs(mpctx); + if (mpctx->current_track[0][STREAM_SUB] == track) + reinit_subs(mpctx, 0); + if (mpctx->current_track[1][STREAM_SUB] == track) + reinit_subs(mpctx, 1); return track; } } @@ -605,6 +618,9 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type } else if (type == STREAM_SUB) { uninit_player(mpctx, INITIALIZED_SUB); } + } else if (order == 1) { + if (type == STREAM_SUB) + uninit_player(mpctx, INITIALIZED_SUB2); } if (current) @@ -631,9 +647,14 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type mp_notify_property(mpctx, "aid"); } else if (type == STREAM_SUB) { mpctx->opts->sub_id = user_tid; - reinit_subs(mpctx); + reinit_subs(mpctx, 0); mp_notify_property(mpctx, "sid"); } + } else if (order == 1) { + if (type == STREAM_SUB) { + mpctx->opts->sub2_id = user_tid; + reinit_subs(mpctx, 1); + } } talloc_free(mpctx->track_layout_hash); @@ -1048,7 +1069,8 @@ static void play_current_file(struct MPContext *mpctx) assert(mpctx->demuxer == NULL); assert(mpctx->d_audio == NULL); assert(mpctx->d_video == NULL); - assert(mpctx->d_sub == NULL); + assert(mpctx->d_sub[0] == NULL); + assert(mpctx->d_sub[1] == NULL); char *stream_filename = mpctx->filename; mpctx->resolve_result = resolve_url(stream_filename, mpctx->global); @@ -1189,7 +1211,8 @@ goto_reopen_demuxer: ; reinit_video_chain(mpctx); reinit_audio_chain(mpctx); - reinit_subs(mpctx); + reinit_subs(mpctx, 0); + reinit_subs(mpctx, 1); //==================== START PLAYING ======================= diff --git a/player/osd.c b/player/osd.c index 607af6714e..d1af1a6e65 100644 --- a/player/osd.c +++ b/player/osd.c @@ -373,8 +373,8 @@ void set_osd_subtitle(struct MPContext *mpctx, const char *text) { if (!text) text = ""; - if (strcmp(mpctx->osd->sub_text, text) != 0) { - osd_set_sub(mpctx->osd, text); + if (strcmp(mpctx->osd->objs[OSDTYPE_SUB]->sub_text, text) != 0) { + osd_set_sub(mpctx->osd, mpctx->osd->objs[OSDTYPE_SUB], text); if (!mpctx->video_out) { rm_osd_msg(mpctx, OSD_MSG_SUB_BASE); if (text && text[0]) diff --git a/player/playloop.c b/player/playloop.c index dcbc1de9ba..6359803fcf 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -181,7 +181,8 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao) clear_audio_output_buffers(mpctx); } - reset_subtitles(mpctx); + reset_subtitles(mpctx, 0); + reset_subtitles(mpctx, 1); mpctx->video_pts = MP_NOPTS_VALUE; mpctx->video_next_pts = MP_NOPTS_VALUE; @@ -271,7 +272,8 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek, if (need_reset) { reinit_video_chain(mpctx); reinit_audio_chain(mpctx); - reinit_subs(mpctx); + reinit_subs(mpctx, 0); + reinit_subs(mpctx, 1); } int demuxer_style = 0; diff --git a/player/sub.c b/player/sub.c index 3593bab710..cc8f89a531 100644 --- a/player/sub.c +++ b/player/sub.c @@ -66,23 +66,32 @@ static bool is_interleaved(struct MPContext *mpctx, struct track *track) return false; } -void reset_subtitles(struct MPContext *mpctx) +void reset_subtitles(struct MPContext *mpctx, int order) { - if (mpctx->d_sub) - sub_reset(mpctx->d_sub); + struct osd_object *osd_obj = + mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB]; + if (mpctx->d_sub[order]) + sub_reset(mpctx->d_sub[order]); set_osd_subtitle(mpctx, NULL); - osd_changed(mpctx->osd, OSDTYPE_SUB); + osd_set_sub(mpctx->osd, osd_obj, NULL); } -void update_subtitles(struct MPContext *mpctx) +static void update_subtitle(struct MPContext *mpctx, int order) { struct MPOpts *opts = mpctx->opts; - if (!(mpctx->initialized_flags & INITIALIZED_SUB)) - return; + if (order == 0) { + if (!(mpctx->initialized_flags & INITIALIZED_SUB)) + return; + } else { + if (!(mpctx->initialized_flags & INITIALIZED_SUB2)) + return; + } - struct track *track = mpctx->current_track[0][STREAM_SUB]; - struct dec_sub *dec_sub = mpctx->d_sub; + struct track *track = mpctx->current_track[order][STREAM_SUB]; + struct dec_sub *dec_sub = mpctx->d_sub[order]; assert(track && dec_sub); + struct osd_object *osd_obj + = mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB]; if (mpctx->d_video) { struct mp_image_params params = mpctx->d_video->vf_input; @@ -90,9 +99,9 @@ void update_subtitles(struct MPContext *mpctx) sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms); } - mpctx->osd->video_offset = track->under_timeline ? mpctx->video_offset : 0; + osd_obj->video_offset = track->under_timeline ? mpctx->video_offset : 0; - double refpts_s = mpctx->playback_pts - mpctx->osd->video_offset; + double refpts_s = mpctx->playback_pts - osd_obj->video_offset; double curpts_s = refpts_s + opts->sub_delay; if (!track->preloaded && track->stream) { @@ -125,8 +134,19 @@ void update_subtitles(struct MPContext *mpctx) } } - if (!mpctx->osd->render_bitmap_subs || !mpctx->video_out) - set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s)); + // Handle displaying subtitles on terminal; never done for secondary subs + if (order == 0) { + if (!osd_obj->render_bitmap_subs || !mpctx->video_out) + set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s)); + } else if (order == 1) { + osd_set_sub(mpctx->osd, osd_obj, sub_get_text(dec_sub, curpts_s)); + } +} + +void update_subtitles(struct MPContext *mpctx) +{ + update_subtitle(mpctx, 0); + update_subtitle(mpctx, 1); } static void set_dvdsub_fake_extradata(struct dec_sub *dec_sub, struct stream *st, @@ -169,12 +189,42 @@ static void set_dvdsub_fake_extradata(struct dec_sub *dec_sub, struct stream *st talloc_free(s); } -void reinit_subs(struct MPContext *mpctx) +static void reinit_subdec(struct MPContext *mpctx, struct track *track, + struct dec_sub *dec_sub) +{ + if (sub_is_initialized(dec_sub)) + return; + + struct sh_video *sh_video = + mpctx->d_video ? mpctx->d_video->header->video : NULL; + int w = sh_video ? sh_video->disp_w : 0; + int h = sh_video ? sh_video->disp_h : 0; + float fps = sh_video ? sh_video->fps : 25; + + set_dvdsub_fake_extradata(dec_sub, track->demuxer->stream, w, h); + sub_set_video_res(dec_sub, w, h); + sub_set_video_fps(dec_sub, fps); + sub_set_ass_renderer(dec_sub, mpctx->ass_library, mpctx->ass_renderer); + sub_init_from_sh(dec_sub, track->stream); + + // Don't do this if the file has video/audio streams. Don't do it even + // if it has only sub streams, because reading packets will change the + // demuxer position. + if (!track->preloaded && track->is_external) { + demux_seek(track->demuxer, 0, SEEK_ABSOLUTE); + track->preloaded = sub_read_all_packets(dec_sub, track->stream); + } +} + +void reinit_subs(struct MPContext *mpctx, int order) { struct MPOpts *opts = mpctx->opts; - struct track *track = mpctx->current_track[0][STREAM_SUB]; + struct track *track = mpctx->current_track[order][STREAM_SUB]; + struct osd_object *osd_obj = + mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB]; + int init_flag = order ? INITIALIZED_SUB2 : INITIALIZED_SUB; - assert(!(mpctx->initialized_flags & INITIALIZED_SUB)); + assert(!(mpctx->initialized_flags & init_flag)); struct sh_stream *sh = init_demux_stream(mpctx, track); @@ -184,48 +234,33 @@ void reinit_subs(struct MPContext *mpctx) return; if (!sh->sub->dec_sub) { - assert(!mpctx->d_sub); + assert(!mpctx->d_sub[order]); sh->sub->dec_sub = sub_create(mpctx->global); } - assert(!mpctx->d_sub || sh->sub->dec_sub == mpctx->d_sub); + assert(!mpctx->d_sub[order] || sh->sub->dec_sub == mpctx->d_sub[order]); // The decoder is kept in the stream header in order to make ordered // chapters work well. - mpctx->d_sub = sh->sub->dec_sub; + mpctx->d_sub[order] = sh->sub->dec_sub; - mpctx->initialized_flags |= INITIALIZED_SUB; + mpctx->initialized_flags |= init_flag; - struct dec_sub *dec_sub = mpctx->d_sub; + struct dec_sub *dec_sub = mpctx->d_sub[order]; assert(dec_sub); - if (!sub_is_initialized(dec_sub)) { - struct sh_video *sh_video = - mpctx->d_video ? mpctx->d_video->header->video : NULL; - int w = sh_video ? sh_video->disp_w : 0; - int h = sh_video ? sh_video->disp_h : 0; - float fps = sh_video ? sh_video->fps : 25; - - set_dvdsub_fake_extradata(dec_sub, track->demuxer->stream, w, h); - sub_set_video_res(dec_sub, w, h); - sub_set_video_fps(dec_sub, fps); - sub_set_ass_renderer(dec_sub, mpctx->ass_library, mpctx->ass_renderer); - sub_init_from_sh(dec_sub, sh); - - // Don't do this if the file has video/audio streams. Don't do it even - // if it has only sub streams, because reading packets will change the - // demuxer position. - if (!track->preloaded && track->is_external) { - demux_seek(track->demuxer, 0, SEEK_ABSOLUTE); - track->preloaded = sub_read_all_packets(dec_sub, sh); - } - } + reinit_subdec(mpctx, track, dec_sub); - mpctx->osd->dec_sub = dec_sub; + osd_obj->dec_sub = dec_sub; // Decides whether to use OSD path or normal subtitle rendering path. - mpctx->osd->render_bitmap_subs = + osd_obj->render_bitmap_subs = opts->ass_enabled || !sub_has_get_text(dec_sub); - reset_subtitles(mpctx); + // Secondary subs are rendered with the "text" renderer to transform them + // to toptitles. + if (order == 1 && sub_has_get_text(dec_sub)) + osd_obj->render_bitmap_subs = false; + + reset_subtitles(mpctx, order); } diff --git a/player/video.c b/player/video.c index 9df3caa940..039248c1d0 100644 --- a/player/video.c +++ b/player/video.c @@ -199,7 +199,8 @@ int reinit_video_chain(struct MPContext *mpctx) mpctx->vo_pts_history_seek_ts++; vo_seek_reset(mpctx->video_out); - reset_subtitles(mpctx); + reset_subtitles(mpctx, 0); + reset_subtitles(mpctx, 1); if (opts->force_fps) { d_video->fps = opts->force_fps; @@ -88,21 +88,22 @@ struct osd_state *osd_create(struct mpv_global *global) .global = global, .log = mp_log_new(osd, global->log, "osd"), .osd_text = talloc_strdup(osd, ""), - .sub_text = talloc_strdup(osd, ""), .progbar_type = -1, }; for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osd_object *obj = talloc_struct(osd, struct osd_object, { + struct osd_object *obj = talloc(osd, struct osd_object); + *obj = (struct osd_object) { .type = n, - }); + .sub_text = talloc_strdup(obj, ""), + }; for (int i = 0; i < OSD_CONV_CACHE_MAX; i++) obj->cache[i] = talloc_steal(obj, osd_conv_cache_new()); osd->objs[n] = obj; } - osd->objs[OSDTYPE_SUB]->is_sub = true; // dec_sub.c - osd->objs[OSDTYPE_SUBTEXT]->is_sub = true; // osd_libass.c + osd->objs[OSDTYPE_SUB]->is_sub = true; + osd->objs[OSDTYPE_SUB2]->is_sub = true; osd_init_backend(osd); return osd; @@ -133,10 +134,10 @@ void osd_set_text(struct osd_state *osd, const char *text) osd_changed(osd, OSDTYPE_OSD); } -void osd_set_sub(struct osd_state *osd, const char *text) +void osd_set_sub(struct osd_state *osd, struct osd_object *obj, const char *text) { - if (!set_text(osd, &osd->sub_text, text)) - osd_changed(osd, OSDTYPE_SUBTEXT); + if (!set_text(obj, &obj->sub_text, text)) + osd_changed(osd, obj->type); } static void render_object(struct osd_state *osd, struct osd_object *obj, @@ -157,12 +158,14 @@ static void render_object(struct osd_state *osd, struct osd_object *obj, obj->force_redraw = true; obj->vo_res = res; - if (obj->type == OSDTYPE_SUB) { - if (osd->render_bitmap_subs && osd->dec_sub) { + if (obj->type == OSDTYPE_SUB || obj->type == OSDTYPE_SUB2) { + if (obj->render_bitmap_subs && obj->dec_sub) { double sub_pts = video_pts; if (sub_pts != MP_NOPTS_VALUE) - sub_pts -= osd->video_offset - opts->sub_delay; - sub_get_bitmaps(osd->dec_sub, obj->vo_res, sub_pts, out_imgs); + sub_pts -= obj->video_offset - opts->sub_delay; + sub_get_bitmaps(obj->dec_sub, obj->vo_res, sub_pts, out_imgs); + } else { + osd_object_get_bitmaps(osd, obj, out_imgs); } } else if (obj->type == OSDTYPE_EXTERNAL2) { if (osd->external2.format) { @@ -84,7 +84,7 @@ struct mp_osd_res { enum mp_osdtype { OSDTYPE_SUB, - OSDTYPE_SUBTEXT, + OSDTYPE_SUB2, OSDTYPE_NAV_HIGHLIGHT, // dvdnav fake highlights @@ -105,6 +105,12 @@ struct osd_object { bool force_redraw; + // OSDTYPE_SUB + struct dec_sub *dec_sub; + double video_offset; + bool render_bitmap_subs; + char *sub_text; + // caches for OSD conversion (internal to render_object()) struct osd_conv_cache *cache[OSD_CONV_CACHE_MAX]; struct sub_bitmaps cached; @@ -124,11 +130,9 @@ struct osd_object { struct osd_state { struct osd_object *objs[MAX_OSD_PARTS]; - double video_offset; double vo_pts; bool render_subs_in_filter; - bool render_bitmap_subs; struct mp_osd_res last_vo_res; @@ -136,8 +140,6 @@ struct osd_state { // OSDTYPE_OSD char *osd_text; - // OSDTYPE_SUBTEXT - char *sub_text; // OSDTYPE_PROGBAR int progbar_type; // <0: disabled, 1-255: symbol, else: no symbol float progbar_value; // range 0.0-1.0 @@ -148,8 +150,6 @@ struct osd_state { int external_res_x, external_res_y; // OSDTYPE_EXTERNAL2 struct sub_bitmaps external2; - // OSDTYPE_SUB - struct dec_sub *dec_sub; // OSDTYPE_NAV_HIGHLIGHT void *highlight_priv; @@ -206,7 +206,7 @@ extern const struct m_sub_options osd_style_conf; struct osd_state *osd_create(struct mpv_global *global); void osd_set_text(struct osd_state *osd, const char *text); -void osd_set_sub(struct osd_state *osd, const char *text); +void osd_set_sub(struct osd_state *osd, struct osd_object *obj, const char *text); void osd_changed(struct osd_state *osd, int new_value); void osd_changed_all(struct osd_state *osd); void osd_free(struct osd_state *osd); diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 48083bc71f..e43408829b 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -411,7 +411,7 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj) clear_obj(obj); - if (!osd->sub_text || !osd->sub_text[0]) + if (!obj->sub_text || !obj->sub_text[0] || obj->render_bitmap_subs) return; create_ass_renderer(osd, obj); @@ -423,12 +423,14 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj) ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style; mp_ass_set_style(style, obj->osd_track->PlayResY, &font); + if (obj->type == OSDTYPE_SUB2) + style->Alignment = 6; #if LIBASS_VERSION >= 0x01010000 ass_set_line_position(obj->osd_render, 100 - opts->sub_pos); #endif - char *escaped_text = mangle_ass(osd->sub_text); + char *escaped_text = mangle_ass(obj->sub_text); add_osd_ass_event(obj->osd_track, escaped_text); talloc_free(escaped_text); } @@ -439,7 +441,8 @@ static void update_object(struct osd_state *osd, struct osd_object *obj) case OSDTYPE_OSD: update_osd(osd, obj); break; - case OSDTYPE_SUBTEXT: + case OSDTYPE_SUB: + case OSDTYPE_SUB2: update_sub(osd, obj); break; case OSDTYPE_PROGBAR: |