sub: cache subtitle state per track instead of per demuxer stream

Since commit 6d9cb893, subtitle state doesn't survive timeline switches
(ordered chapters etc.). So there is no point in caching the state per
sh_stream anymore (which would be required to deal with multiple
segments). Move the cache to struct track.

(Whether it's worth caching the subtitle state just for the situation
when subtitle tracks get reselected is questionable. But for now, it's
nice to have the subtitles immediately show up when reselecting a
subtitle.)
This commit is contained in:
wm4 2015-12-26 18:32:27 +01:00
parent 504286b006
commit ce8524cb47
6 changed files with 31 additions and 49 deletions

View File

@ -94,7 +94,6 @@ typedef struct sh_sub {
double frame_based; // timestamps are frame-based (and this is the
// fallback framerate used for timestamps)
char *charset; // assumed 8 bit subtitle charset (can be NULL)
struct dec_sub *dec_sub; // decoder context
} sh_sub_t;
#endif /* MPLAYER_STHEADER_H */

View File

@ -139,6 +139,9 @@ struct track {
// Invariant: !stream || stream->demuxer == demuxer
struct sh_stream *stream;
// Current subtitle state (or cached state if selected==false).
struct dec_sub *dec_sub;
// For external subtitles, which are read fully on init. Do not attempt
// to read packets from them.
bool preloaded;
@ -517,7 +520,6 @@ void mp_load_scripts(struct MPContext *mpctx);
// sub.c
void reset_subtitle_state(struct MPContext *mpctx);
void uninit_stream_sub_decoders(struct demuxer *demuxer);
void reinit_subs(struct MPContext *mpctx, int order);
void uninit_sub(struct MPContext *mpctx, int order);
void uninit_sub_all(struct MPContext *mpctx);

View File

@ -72,17 +72,15 @@ static void uninit_demuxer(struct MPContext *mpctx)
mpctx->chapters = NULL;
mpctx->num_chapters = 0;
// per-stream cached subtitle state
for (int i = 0; i < mpctx->num_sources; i++)
uninit_stream_sub_decoders(mpctx->sources[i]);
// close demuxers for external tracks
for (int n = mpctx->num_tracks - 1; n >= 0; n--) {
mpctx->tracks[n]->selected = false;
mp_remove_track(mpctx, mpctx->tracks[n]);
}
for (int i = 0; i < mpctx->num_tracks; i++)
for (int i = 0; i < mpctx->num_tracks; i++) {
sub_destroy(mpctx->tracks[i]->dec_sub);
talloc_free(mpctx->tracks[i]);
}
mpctx->num_tracks = 0;
mpctx->timeline = NULL;
@ -337,10 +335,15 @@ bool timeline_switch_to_time(struct MPContext *mpctx, double pts)
track->user_tid - 1);
}
if (track->type == STREAM_SUB && track->stream) {
struct dec_sub *dec = track->stream->sub->dec_sub;
if (dec)
sub_control(dec, SD_CTRL_CLEAR, NULL);
if (track->dec_sub) {
for (int order = 0; order < 2; order++) {
if (mpctx->d_sub[order] == track->dec_sub) {
mpctx->d_sub[order] = NULL;
osd_set_sub(mpctx->osd, OSDTYPE_SUB + order, NULL);
}
}
sub_destroy(track->dec_sub);
track->dec_sub = NULL;
}
}
}
@ -654,6 +657,8 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track)
struct demuxer *d = track->demuxer;
sub_destroy(track->dec_sub);
int index = 0;
while (index < mpctx->num_tracks && mpctx->tracks[index] != track)
index++;
@ -674,7 +679,6 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track)
break;
}
}
uninit_stream_sub_decoders(d);
free_demuxer_and_stream(d);
}

View File

@ -144,22 +144,11 @@ void reset_subtitle_state(struct MPContext *mpctx)
reset_subtitles(mpctx, 1);
}
void uninit_stream_sub_decoders(struct demuxer *demuxer)
{
for (int i = 0; i < demux_get_num_stream(demuxer); i++) {
struct sh_stream *sh = demux_get_stream(demuxer, i);
if (sh->sub) {
sub_destroy(sh->sub->dec_sub);
sh->sub->dec_sub = NULL;
}
}
}
void uninit_sub(struct MPContext *mpctx, int order)
{
if (mpctx->d_sub[order]) {
reset_subtitles(mpctx, order);
mpctx->d_sub[order] = NULL; // Note: not free'd.
mpctx->d_sub[order] = NULL; // not destroyed
osd_set_sub(mpctx->osd, OSDTYPE_SUB + order, NULL);
reselect_demux_streams(mpctx);
}
@ -211,8 +200,6 @@ static void update_subtitle(struct MPContext *mpctx, int order)
struct sh_stream *sh_stream = track->stream;
bool interleaved = is_interleaved(mpctx, track);
assert(sh_stream->sub->dec_sub == dec_sub);
while (1) {
if (interleaved && !demux_has_packet(sh_stream))
break;
@ -248,11 +235,12 @@ void update_subtitles(struct MPContext *mpctx)
update_subtitle(mpctx, 1);
}
static void reinit_subdec(struct MPContext *mpctx, struct track *track,
struct dec_sub *dec_sub)
static void reinit_subdec(struct MPContext *mpctx, struct track *track)
{
struct MPOpts *opts = mpctx->opts;
struct dec_sub *dec_sub = track->dec_sub;
if (sub_is_initialized(dec_sub))
return;
@ -288,13 +276,11 @@ void reinit_subs(struct MPContext *mpctx, int order)
if (!sh)
return;
// The decoder is cached in the stream header in order to make ordered
// chapters work better.
if (!sh->sub->dec_sub)
sh->sub->dec_sub = sub_create(mpctx->global);
mpctx->d_sub[order] = sh->sub->dec_sub;
if (!track->dec_sub)
track->dec_sub = sub_create(mpctx->global);
mpctx->d_sub[order] = track->dec_sub;
reinit_subdec(mpctx, track, sh->sub->dec_sub);
osd_set_sub(mpctx->osd, OSDTYPE_SUB + order, sh->sub->dec_sub);
sub_control(sh->sub->dec_sub, SD_CTRL_SET_TOP, &(bool){!!order});
reinit_subdec(mpctx, track);
osd_set_sub(mpctx->osd, OSDTYPE_SUB + order, track->dec_sub);
sub_control(track->dec_sub, SD_CTRL_SET_TOP, &(bool){!!order});
}

View File

@ -22,7 +22,6 @@ enum sd_ctrl {
SD_CTRL_SET_VIDEO_PARAMS,
SD_CTRL_GET_RESOLUTION,
SD_CTRL_SET_TOP,
SD_CTRL_CLEAR,
};
struct dec_sub *sub_create(struct mpv_global *global);

View File

@ -510,18 +510,13 @@ static void fill_plaintext(struct sd *sd, double pts)
track->styles[track->default_style].Alignment = ctx->on_top ? 6 : 2;
}
static void clear(struct sd *sd)
{
struct sd_ass_priv *ctx = sd->priv;
ass_flush_events(ctx->ass_track);
ctx->num_seen_packets = 0;
}
static void reset(struct sd *sd)
{
struct sd_ass_priv *ctx = sd->priv;
if (sd->opts->sub_clear_on_seek)
clear(sd);
if (sd->opts->sub_clear_on_seek) {
ass_flush_events(ctx->ass_track);
ctx->num_seen_packets = 0;
}
if (ctx->converter)
lavc_conv_reset(ctx->converter);
}
@ -554,9 +549,6 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
case SD_CTRL_SET_TOP:
ctx->on_top = *(bool *)arg;
return CONTROL_OK;
case SD_CTRL_CLEAR:
clear(sd);
return CONTROL_OK;
default:
return CONTROL_UNKNOWN;
}