0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

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.
This commit is contained in:
wm4 2013-12-24 17:46:14 +01:00
parent 9292f537d6
commit 3720b3f17d
15 changed files with 220 additions and 106 deletions

View File

@ -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``

View File

@ -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.

View File

@ -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),

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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 =======================

View File

@ -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])

View File

@ -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;

View File

@ -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, &params);
}
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;
reinit_subdec(mpctx, track, dec_sub);
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);
}
}
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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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: