sub: fix UPDATE_SUB_HARD for converted and external subtitles

Upon an option update with an UPDATE_SUB_HARD flag,
the ass_track that stores all the decoded
subtitle packets/events is destroyed and recreated, which means
the packets need to be read and decoded again to refill
the ass_track. This caused issues (no subs displayed) in 2 cases:
1. external sub files
  Previously, external sub files were read and decoded only
  once when loaded. Since this meant all decoded events were lost
  forever when recreating the ass_track, we need to change this
  and trigger a new preload during sub reinits.
2. converted subs (non-ASS text subs like srt)
  For converted subs, we maintain a list of previously
  seen packets to avoid decoding and adding duplicate events
  to the ass_track. Previously this list wasn’t synchronized with
  the corresponding ass_track, so the sub decoder would reject
  any previously seen sub packets, usually meaning only subs sometime
  after the current pts would be displayed after sub reinits.
  Fix this by resetting the list upon ass_track recreation.
This commit is contained in:
Lypheo 2023-03-08 19:05:59 +01:00 committed by Dudemanguy
parent c5211dbf4a
commit e928bd5fdb
2 changed files with 13 additions and 1 deletions

View File

@ -421,10 +421,18 @@ int sub_control(struct dec_sub *sub, enum sd_ctrl cmd, void *arg)
if (r == CONTROL_OK)
a[0] = pts_from_subtitle(sub, arg2[0]);
break;
case SD_CTRL_UPDATE_OPTS:
}
case SD_CTRL_UPDATE_OPTS: {
int flags = (uintptr_t)arg;
if (m_config_cache_update(sub->opts_cache))
update_subtitle_speed(sub);
propagate = true;
if (flags & UPDATE_SUB_HARD) {
// forget about the previous preload because
// UPDATE_SUB_HARD will cause a sub reinit
// that clears all preloaded sub packets
sub->preload_attempted = false;
}
break;
}
default:

View File

@ -824,6 +824,10 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
ctx->clear_once = true; // allow reloading on seeks
}
if (flags & UPDATE_SUB_HARD) {
// ass_track will be recreated, so clear duplicate cache
ctx->clear_once = true;
reset(sd);
assobjects_destroy(sd);
assobjects_init(sd);
}