player: rearrange how subtitle context and stream headers are used

Use sh_stream over sh_sub. Use dec_sub (and mpctx->d_sub) instead of the
stream header. This aligns the subtitle code with the recent audio and
video refactoring.

sh_sub still has the decoder context, though. This is because we want to
avoid reinit when switching segments with ordered chapters. (Reinit is
fast, except for creating the ASS_Renderer, which in turn triggers
fontconfig.) Not sure how much this matters, though, because the initial
segment switch will lazily initialize the decoder anyway.
This commit is contained in:
wm4 2013-11-23 21:37:15 +01:00
parent 3486302514
commit 639e672bd1
5 changed files with 57 additions and 54 deletions

View File

@ -80,9 +80,10 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
if (mask & INITIALIZED_SUB) { if (mask & INITIALIZED_SUB) {
mpctx->initialized_flags &= ~INITIALIZED_SUB; mpctx->initialized_flags &= ~INITIALIZED_SUB;
if (mpctx->sh_sub) if (mpctx->d_sub)
sub_reset(mpctx->sh_sub->dec_sub); sub_reset(mpctx->d_sub);
cleanup_demux_stream(mpctx, STREAM_SUB); cleanup_demux_stream(mpctx, STREAM_SUB);
mpctx->d_sub = NULL; // Note: not free'd.
mpctx->osd->dec_sub = NULL; mpctx->osd->dec_sub = NULL;
reset_subtitles(mpctx); reset_subtitles(mpctx);
} }
@ -108,13 +109,15 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
if (mask & INITIALIZED_DEMUXER) { if (mask & INITIALIZED_DEMUXER) {
mpctx->initialized_flags &= ~INITIALIZED_DEMUXER; mpctx->initialized_flags &= ~INITIALIZED_DEMUXER;
assert(!(mpctx->initialized_flags &
(INITIALIZED_VCODEC | INITIALIZED_ACODEC | INITIALIZED_SUB)));
for (int i = 0; i < mpctx->num_tracks; i++) { for (int i = 0; i < mpctx->num_tracks; i++) {
talloc_free(mpctx->tracks[i]); talloc_free(mpctx->tracks[i]);
} }
mpctx->num_tracks = 0; mpctx->num_tracks = 0;
for (int t = 0; t < STREAM_TYPE_COUNT; t++) for (int t = 0; t < STREAM_TYPE_COUNT; t++)
mpctx->current_track[t] = NULL; mpctx->current_track[t] = NULL;
assert(!mpctx->d_video && !mpctx->d_audio && !mpctx->sh_sub); assert(!mpctx->d_video && !mpctx->d_audio && !mpctx->d_sub);
mpctx->master_demuxer = NULL; mpctx->master_demuxer = NULL;
for (int i = 0; i < mpctx->num_sources; i++) { for (int i = 0; i < mpctx->num_sources; i++) {
uninit_subs(mpctx->sources[i]); uninit_subs(mpctx->sources[i]);
@ -264,22 +267,12 @@ static void print_file_properties(struct MPContext *mpctx)
} }
} }
static void set_demux_field(struct MPContext *mpctx, enum stream_type type,
struct sh_stream *s)
{
mpctx->sh[type] = s;
// redundant fields for convenience access
switch(type) {
case STREAM_SUB: mpctx->sh_sub = s ? s->sub : NULL; break;
}
}
struct sh_stream *init_demux_stream(struct MPContext *mpctx, struct sh_stream *init_demux_stream(struct MPContext *mpctx,
enum stream_type type) enum stream_type type)
{ {
struct track *track = mpctx->current_track[type]; struct track *track = mpctx->current_track[type];
set_demux_field(mpctx, type, track ? track->stream : NULL); struct sh_stream *stream = track ? track->stream : NULL;
struct sh_stream *stream = mpctx->sh[type]; mpctx->sh[type] = stream;
if (stream) { if (stream) {
demuxer_switch_track(stream->demuxer, type, stream); demuxer_switch_track(stream->demuxer, type, stream);
if (track->is_external) { if (track->is_external) {
@ -295,7 +288,7 @@ void cleanup_demux_stream(struct MPContext *mpctx, enum stream_type type)
struct sh_stream *stream = mpctx->sh[type]; struct sh_stream *stream = mpctx->sh[type];
if (stream) if (stream)
demuxer_switch_track(stream->demuxer, type, NULL); demuxer_switch_track(stream->demuxer, type, NULL);
set_demux_field(mpctx, type, NULL); mpctx->sh[type] = NULL;
} }
// Switch the demuxers to current track selection. This is possibly important // Switch the demuxers to current track selection. This is possibly important
@ -1051,7 +1044,7 @@ static void play_current_file(struct MPContext *mpctx)
assert(mpctx->demuxer == NULL); assert(mpctx->demuxer == NULL);
assert(mpctx->d_audio == NULL); assert(mpctx->d_audio == NULL);
assert(mpctx->d_video == NULL); assert(mpctx->d_video == NULL);
assert(mpctx->sh_sub == NULL); assert(mpctx->d_sub == NULL);
char *stream_filename = mpctx->filename; char *stream_filename = mpctx->filename;
mpctx->resolve_result = resolve_url(stream_filename, opts); mpctx->resolve_result = resolve_url(stream_filename, opts);

View File

@ -199,10 +199,10 @@ typedef struct MPContext {
struct track *current_track[STREAM_TYPE_COUNT]; struct track *current_track[STREAM_TYPE_COUNT];
struct sh_stream *sh[STREAM_TYPE_COUNT]; struct sh_stream *sh[STREAM_TYPE_COUNT];
struct sh_sub *sh_sub; // same as sh[STREAM_SUB]->sub
struct dec_video *d_video; struct dec_video *d_video;
struct dec_audio *d_audio; struct dec_audio *d_audio;
struct dec_sub *d_sub;
// Uses: accessing metadata (consider ordered chapters case, where the main // Uses: accessing metadata (consider ordered chapters case, where the main
// demuxer defines metadata), or special purpose demuxers like TV. // demuxer defines metadata), or special purpose demuxers like TV.

View File

@ -67,8 +67,8 @@ static bool is_interleaved(struct MPContext *mpctx, struct track *track)
void reset_subtitles(struct MPContext *mpctx) void reset_subtitles(struct MPContext *mpctx)
{ {
if (mpctx->sh_sub) if (mpctx->d_sub)
sub_reset(mpctx->sh_sub->dec_sub); sub_reset(mpctx->d_sub);
set_osd_subtitle(mpctx, NULL); set_osd_subtitle(mpctx, NULL);
osd_changed(mpctx->osd, OSDTYPE_SUB); osd_changed(mpctx->osd, OSDTYPE_SUB);
} }
@ -80,9 +80,8 @@ void update_subtitles(struct MPContext *mpctx)
return; return;
struct track *track = mpctx->current_track[STREAM_SUB]; struct track *track = mpctx->current_track[STREAM_SUB];
struct sh_sub *sh_sub = mpctx->sh_sub; struct dec_sub *dec_sub = mpctx->d_sub;
assert(track && sh_sub); assert(track && dec_sub);
struct dec_sub *dec_sub = sh_sub->dec_sub;
if (mpctx->d_video && mpctx->d_video->vf_input) { if (mpctx->d_video && mpctx->d_video->vf_input) {
struct mp_image_params params = *mpctx->d_video->vf_input; struct mp_image_params params = *mpctx->d_video->vf_input;
@ -94,14 +93,17 @@ void update_subtitles(struct MPContext *mpctx)
double refpts_s = mpctx->playback_pts - mpctx->osd->video_offset; double refpts_s = mpctx->playback_pts - mpctx->osd->video_offset;
double curpts_s = refpts_s + opts->sub_delay; double curpts_s = refpts_s + opts->sub_delay;
if (!track->preloaded) { if (!track->preloaded && track->stream) {
struct sh_stream *sh_stream = track->stream;
bool interleaved = is_interleaved(mpctx, track); bool interleaved = is_interleaved(mpctx, track);
assert(sh_stream->sub->dec_sub == dec_sub);
while (1) { while (1) {
if (interleaved && !demux_has_packet(sh_sub->gsh)) if (interleaved && !demux_has_packet(sh_stream))
break; break;
double subpts_s = demux_get_next_pts(sh_sub->gsh); double subpts_s = demux_get_next_pts(sh_stream);
if (!demux_has_packet(sh_sub->gsh)) if (!demux_has_packet(sh_stream))
break; break;
if (subpts_s > curpts_s) { if (subpts_s > curpts_s) {
mp_dbg(MSGT_CPLAYER, MSGL_DBG2, mp_dbg(MSGT_CPLAYER, MSGL_DBG2,
@ -114,7 +116,7 @@ void update_subtitles(struct MPContext *mpctx)
if (subpts_s > curpts_s + 1 && !interleaved) if (subpts_s > curpts_s + 1 && !interleaved)
break; break;
} }
struct demux_packet *pkt = demux_read_packet(sh_sub->gsh); struct demux_packet *pkt = demux_read_packet(sh_stream);
mp_dbg(MSGT_CPLAYER, MSGL_V, "Sub: c_pts=%5.3f s_pts=%5.3f " mp_dbg(MSGT_CPLAYER, MSGL_V, "Sub: c_pts=%5.3f s_pts=%5.3f "
"duration=%5.3f len=%d\n", curpts_s, pkt->pts, pkt->duration, "duration=%5.3f len=%d\n", curpts_s, pkt->pts, pkt->duration,
pkt->len); pkt->len);
@ -177,21 +179,27 @@ void reinit_subs(struct MPContext *mpctx)
assert(!(mpctx->initialized_flags & INITIALIZED_SUB)); assert(!(mpctx->initialized_flags & INITIALIZED_SUB));
init_demux_stream(mpctx, STREAM_SUB); init_demux_stream(mpctx, STREAM_SUB);
if (!mpctx->sh_sub) struct sh_stream *sh = mpctx->sh[STREAM_SUB];
// No track selected, or lazily added DVD track (will actually be created
// on first sub packet)
if (!sh)
return; return;
if (!mpctx->sh_sub->dec_sub) if (!sh->sub->dec_sub) {
mpctx->sh_sub->dec_sub = sub_create(opts); assert(!mpctx->d_sub);
sh->sub->dec_sub = sub_create(opts);
}
assert(track->demuxer); assert(!mpctx->d_sub || sh->sub->dec_sub == mpctx->d_sub);
// Lazily added DVD track - will be created on first sub packet
if (!track->stream) // The decoder is kept in the stream header in order to make ordered
return; // chapters work well.
mpctx->d_sub = sh->sub->dec_sub;
mpctx->initialized_flags |= INITIALIZED_SUB; mpctx->initialized_flags |= INITIALIZED_SUB;
struct sh_sub *sh_sub = mpctx->sh_sub; struct dec_sub *dec_sub = mpctx->d_sub;
struct dec_sub *dec_sub = sh_sub->dec_sub;
assert(dec_sub); assert(dec_sub);
if (!sub_is_initialized(dec_sub)) { if (!sub_is_initialized(dec_sub)) {
@ -206,14 +214,14 @@ void reinit_subs(struct MPContext *mpctx)
sub_set_video_fps(dec_sub, fps); sub_set_video_fps(dec_sub, fps);
sub_set_ass_renderer(dec_sub, mpctx->osd->ass_library, sub_set_ass_renderer(dec_sub, mpctx->osd->ass_library,
mpctx->osd->ass_renderer); mpctx->osd->ass_renderer);
sub_init_from_sh(dec_sub, sh_sub); sub_init_from_sh(dec_sub, sh);
// Don't do this if the file has video/audio streams. Don't do it even // 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 // if it has only sub streams, because reading packets will change the
// demuxer position. // demuxer position.
if (!track->preloaded && track->is_external) { if (!track->preloaded && track->is_external) {
demux_seek(track->demuxer, 0, SEEK_ABSOLUTE); demux_seek(track->demuxer, 0, SEEK_ABSOLUTE);
track->preloaded = sub_read_all_packets(dec_sub, sh_sub); track->preloaded = sub_read_all_packets(dec_sub, sh);
} }
} }

View File

@ -162,15 +162,16 @@ static int sub_init_decoder(struct dec_sub *sub, struct sd *sd)
return 0; return 0;
} }
void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh) void sub_init_from_sh(struct dec_sub *sub, struct sh_stream *sh)
{ {
assert(!sub->num_sd); assert(!sub->num_sd);
assert(sh && sh->sub);
if (sh->extradata && !sub->init_sd.extradata) if (sh->sub->extradata && !sub->init_sd.extradata)
sub_set_extradata(sub, sh->extradata, sh->extradata_len); sub_set_extradata(sub, sh->sub->extradata, sh->sub->extradata_len);
struct sd init_sd = sub->init_sd; struct sd init_sd = sub->init_sd;
init_sd.codec = sh->gsh->codec; init_sd.codec = sh->codec;
init_sd.ass_track = sh->track; init_sd.ass_track = sh->sub->track;
while (sub->num_sd < MAX_NUM_SD) { while (sub->num_sd < MAX_NUM_SD) {
struct sd *sd = talloc(NULL, struct sd); struct sd *sd = talloc(NULL, struct sd);
@ -199,7 +200,7 @@ void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh)
sub_uninit(sub); sub_uninit(sub);
mp_msg(MSGT_OSD, MSGL_ERR, "Could not find subtitle decoder for format '%s'.\n", mp_msg(MSGT_OSD, MSGL_ERR, "Could not find subtitle decoder for format '%s'.\n",
sh->gsh->codec ? sh->gsh->codec : "<unknown>"); sh->codec ? sh->codec : "<unknown>");
} }
static struct demux_packet *get_decoded_packet(struct sd *sd) static struct demux_packet *get_decoded_packet(struct sd *sd)
@ -362,11 +363,12 @@ static void add_packet(struct packet_list *subs, struct demux_packet *pkt)
// Read all packets from the demuxer and decode/add them. Returns false if // Read all packets from the demuxer and decode/add them. Returns false if
// there are circumstances which makes this not possible. // there are circumstances which makes this not possible.
bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh) bool sub_read_all_packets(struct dec_sub *sub, struct sh_stream *sh)
{ {
assert(sh && sh->sub);
struct MPOpts *opts = sub->opts; struct MPOpts *opts = sub->opts;
if (!sub_accept_packets_in_advance(sub) || sh->track || sub->num_sd < 1) if (!sub_accept_packets_in_advance(sub) || sh->sub->track || sub->num_sd < 1)
return false; return false;
struct packet_list *subs = talloc_zero(NULL, struct packet_list); struct packet_list *subs = talloc_zero(NULL, struct packet_list);
@ -385,7 +387,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
preprocess = 1; preprocess = 1;
for (;;) { for (;;) {
struct demux_packet *pkt = demux_read_packet(sh->gsh); struct demux_packet *pkt = demux_read_packet(sh);
if (!pkt) if (!pkt)
break; break;
if (preprocess) { if (preprocess) {
@ -403,7 +405,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
} }
} }
if (opts->sub_cp && !sh->is_utf8) if (opts->sub_cp && !sh->sub->is_utf8)
sub->charset = guess_sub_cp(subs, opts->sub_cp); sub->charset = guess_sub_cp(subs, opts->sub_cp);
if (sub->charset && sub->charset[0] && !mp_charset_is_utf8(sub->charset)) if (sub->charset && sub->charset[0] && !mp_charset_is_utf8(sub->charset))
@ -412,7 +414,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
double sub_speed = 1.0; double sub_speed = 1.0;
// 23.976 FPS is used as default timebase for frame based formats // 23.976 FPS is used as default timebase for frame based formats
if (sub->video_fps && sh->frame_based) if (sub->video_fps && sh->sub->frame_based)
sub_speed *= sub->video_fps / 23.976; sub_speed *= sub->video_fps / 23.976;
if (opts->sub_fps && sub->video_fps) if (opts->sub_fps && sub->video_fps)
@ -426,7 +428,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
if (!opts->suboverlap_enabled) if (!opts->suboverlap_enabled)
fix_overlaps_and_gaps(subs); fix_overlaps_and_gaps(subs);
if (sh->gsh->codec && strcmp(sh->gsh->codec, "microdvd") == 0) { if (sh->codec && strcmp(sh->codec, "microdvd") == 0) {
// The last subtitle event in MicroDVD subs can have duration unset, // The last subtitle event in MicroDVD subs can have duration unset,
// which means show the subtitle until end of video. // which means show the subtitle until end of video.
// See FFmpeg FATE MicroDVD_capability_tester.sub // See FFmpeg FATE MicroDVD_capability_tester.sub

View File

@ -6,7 +6,7 @@
#include "sub/sub.h" #include "sub/sub.h"
struct sh_sub; struct sh_stream;
struct ass_track; struct ass_track;
struct MPOpts; struct MPOpts;
struct demux_packet; struct demux_packet;
@ -29,11 +29,11 @@ void sub_set_video_fps(struct dec_sub *sub, double fps);
void sub_set_extradata(struct dec_sub *sub, void *data, int data_len); void sub_set_extradata(struct dec_sub *sub, void *data, int data_len);
void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library, void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library,
struct ass_renderer *ass_renderer); struct ass_renderer *ass_renderer);
void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh); void sub_init_from_sh(struct dec_sub *sub, struct sh_stream *sh);
bool sub_is_initialized(struct dec_sub *sub); bool sub_is_initialized(struct dec_sub *sub);
bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh); bool sub_read_all_packets(struct dec_sub *sub, struct sh_stream *sh);
bool sub_accept_packets_in_advance(struct dec_sub *sub); bool sub_accept_packets_in_advance(struct dec_sub *sub);
void sub_decode(struct dec_sub *sub, struct demux_packet *packet); void sub_decode(struct dec_sub *sub, struct demux_packet *packet);
void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts, void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts,