From 639e672bd153e06cfc01ced6c2a48b45870e8f31 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 23 Nov 2013 21:37:15 +0100 Subject: 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. --- mpvcore/player/loadfile.c | 27 ++++++++++--------------- mpvcore/player/mp_core.h | 2 +- mpvcore/player/sub.c | 50 +++++++++++++++++++++++++++-------------------- sub/dec_sub.c | 26 ++++++++++++------------ sub/dec_sub.h | 6 +++--- 5 files changed, 57 insertions(+), 54 deletions(-) diff --git a/mpvcore/player/loadfile.c b/mpvcore/player/loadfile.c index 51d3f2ec7e..33ee770b08 100644 --- a/mpvcore/player/loadfile.c +++ b/mpvcore/player/loadfile.c @@ -80,9 +80,10 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mask & INITIALIZED_SUB) { mpctx->initialized_flags &= ~INITIALIZED_SUB; - if (mpctx->sh_sub) - sub_reset(mpctx->sh_sub->dec_sub); + if (mpctx->d_sub) + sub_reset(mpctx->d_sub); cleanup_demux_stream(mpctx, STREAM_SUB); + mpctx->d_sub = NULL; // Note: not free'd. mpctx->osd->dec_sub = NULL; reset_subtitles(mpctx); } @@ -108,13 +109,15 @@ 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))); for (int i = 0; i < mpctx->num_tracks; i++) { talloc_free(mpctx->tracks[i]); } mpctx->num_tracks = 0; for (int t = 0; t < STREAM_TYPE_COUNT; t++) 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; for (int i = 0; i < mpctx->num_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, enum stream_type type) { struct track *track = mpctx->current_track[type]; - set_demux_field(mpctx, type, track ? track->stream : NULL); - struct sh_stream *stream = mpctx->sh[type]; + struct sh_stream *stream = track ? track->stream : NULL; + mpctx->sh[type] = stream; if (stream) { demuxer_switch_track(stream->demuxer, type, stream); 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]; if (stream) 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 @@ -1051,7 +1044,7 @@ static void play_current_file(struct MPContext *mpctx) assert(mpctx->demuxer == NULL); assert(mpctx->d_audio == NULL); assert(mpctx->d_video == NULL); - assert(mpctx->sh_sub == NULL); + assert(mpctx->d_sub == NULL); char *stream_filename = mpctx->filename; mpctx->resolve_result = resolve_url(stream_filename, opts); diff --git a/mpvcore/player/mp_core.h b/mpvcore/player/mp_core.h index f372c4e137..0be7e1df1f 100644 --- a/mpvcore/player/mp_core.h +++ b/mpvcore/player/mp_core.h @@ -199,10 +199,10 @@ typedef struct MPContext { struct track *current_track[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_audio *d_audio; + struct dec_sub *d_sub; // Uses: accessing metadata (consider ordered chapters case, where the main // demuxer defines metadata), or special purpose demuxers like TV. diff --git a/mpvcore/player/sub.c b/mpvcore/player/sub.c index d659e74851..bdcb9def09 100644 --- a/mpvcore/player/sub.c +++ b/mpvcore/player/sub.c @@ -67,8 +67,8 @@ static bool is_interleaved(struct MPContext *mpctx, struct track *track) void reset_subtitles(struct MPContext *mpctx) { - if (mpctx->sh_sub) - sub_reset(mpctx->sh_sub->dec_sub); + if (mpctx->d_sub) + sub_reset(mpctx->d_sub); set_osd_subtitle(mpctx, NULL); osd_changed(mpctx->osd, OSDTYPE_SUB); } @@ -80,9 +80,8 @@ void update_subtitles(struct MPContext *mpctx) return; struct track *track = mpctx->current_track[STREAM_SUB]; - struct sh_sub *sh_sub = mpctx->sh_sub; - assert(track && sh_sub); - struct dec_sub *dec_sub = sh_sub->dec_sub; + struct dec_sub *dec_sub = mpctx->d_sub; + assert(track && dec_sub); if (mpctx->d_video && 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 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); + assert(sh_stream->sub->dec_sub == dec_sub); + while (1) { - if (interleaved && !demux_has_packet(sh_sub->gsh)) + if (interleaved && !demux_has_packet(sh_stream)) break; - double subpts_s = demux_get_next_pts(sh_sub->gsh); - if (!demux_has_packet(sh_sub->gsh)) + double subpts_s = demux_get_next_pts(sh_stream); + if (!demux_has_packet(sh_stream)) break; if (subpts_s > curpts_s) { mp_dbg(MSGT_CPLAYER, MSGL_DBG2, @@ -114,7 +116,7 @@ void update_subtitles(struct MPContext *mpctx) if (subpts_s > curpts_s + 1 && !interleaved) 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 " "duration=%5.3f len=%d\n", curpts_s, pkt->pts, pkt->duration, pkt->len); @@ -177,21 +179,27 @@ void reinit_subs(struct MPContext *mpctx) assert(!(mpctx->initialized_flags & INITIALIZED_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; - if (!mpctx->sh_sub->dec_sub) - mpctx->sh_sub->dec_sub = sub_create(opts); + if (!sh->sub->dec_sub) { + assert(!mpctx->d_sub); + sh->sub->dec_sub = sub_create(opts); + } - assert(track->demuxer); - // Lazily added DVD track - will be created on first sub packet - if (!track->stream) - return; + assert(!mpctx->d_sub || sh->sub->dec_sub == mpctx->d_sub); + + // The decoder is kept in the stream header in order to make ordered + // chapters work well. + mpctx->d_sub = sh->sub->dec_sub; mpctx->initialized_flags |= INITIALIZED_SUB; - struct sh_sub *sh_sub = mpctx->sh_sub; - struct dec_sub *dec_sub = sh_sub->dec_sub; + struct dec_sub *dec_sub = mpctx->d_sub; assert(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_ass_renderer(dec_sub, mpctx->osd->ass_library, 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 // 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_sub); + track->preloaded = sub_read_all_packets(dec_sub, sh); } } diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 1a6cc6b0aa..cb76acc248 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -162,15 +162,16 @@ static int sub_init_decoder(struct dec_sub *sub, struct sd *sd) 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(sh && sh->sub); - if (sh->extradata && !sub->init_sd.extradata) - sub_set_extradata(sub, sh->extradata, sh->extradata_len); + if (sh->sub->extradata && !sub->init_sd.extradata) + sub_set_extradata(sub, sh->sub->extradata, sh->sub->extradata_len); struct sd init_sd = sub->init_sd; - init_sd.codec = sh->gsh->codec; - init_sd.ass_track = sh->track; + init_sd.codec = sh->codec; + init_sd.ass_track = sh->sub->track; while (sub->num_sd < MAX_NUM_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); mp_msg(MSGT_OSD, MSGL_ERR, "Could not find subtitle decoder for format '%s'.\n", - sh->gsh->codec ? sh->gsh->codec : ""); + sh->codec ? sh->codec : ""); } 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 // 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; - 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; 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; for (;;) { - struct demux_packet *pkt = demux_read_packet(sh->gsh); + struct demux_packet *pkt = demux_read_packet(sh); if (!pkt) break; 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); 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; // 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; 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) 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, // which means show the subtitle until end of video. // See FFmpeg FATE MicroDVD_capability_tester.sub diff --git a/sub/dec_sub.h b/sub/dec_sub.h index b269326cac..9ff2b366bd 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -6,7 +6,7 @@ #include "sub/sub.h" -struct sh_sub; +struct sh_stream; struct ass_track; struct MPOpts; 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_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library, 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_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); 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, -- cgit v1.2.3