diff --git a/demux/demux.c b/demux/demux.c index e901a9352b..8af76daa1f 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -820,6 +820,7 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src) dst->ts_resets_possible = src->ts_resets_possible; dst->rel_seeks = src->rel_seeks; dst->allow_refresh_seeks = src->allow_refresh_seeks; + dst->fully_read = src->fully_read; dst->start_time = src->start_time; dst->priv = src->priv; } diff --git a/demux/demux.h b/demux/demux.h index cd897be7e2..1d0038a5b0 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -192,6 +192,11 @@ typedef struct demuxer { // monotonically increasing // - seeking leaves packet positions invariant bool allow_refresh_seeks; + // The file data was fully read, and there is no need to keep the stream + // open, keep the cache active, or to run the demuxer thread. Generating + // packets is not slow either (unlike e.g. libavdevice pseudo-demuxers). + // Typical examples: text subtitles, playlists + bool fully_read; // Bitmask of DEMUX_EVENT_* int events; diff --git a/demux/demux_cue.c b/demux/demux_cue.c index 969c3ebb84..db70586b16 100644 --- a/demux/demux_cue.c +++ b/demux/demux_cue.c @@ -433,6 +433,7 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check) } struct priv *p = talloc_zero(demuxer, struct priv); demuxer->priv = p; + demuxer->fully_read = true; p->data = stream_read_complete(s, demuxer, 1000000); if (p->data.start == NULL) return -1; diff --git a/demux/demux_edl.c b/demux/demux_edl.c index c9f8f344be..f12ca2c8a1 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -311,6 +311,7 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check) { struct priv *p = talloc_zero(demuxer, struct priv); demuxer->priv = p; + demuxer->fully_read = true; struct stream *s = demuxer->stream; if (s->uncached_type == STREAMTYPE_EDL) { diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 98cb4df5e6..ca7004c43b 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -103,12 +103,14 @@ struct format_hack { bool ignore : 1; // blacklisted bool no_stream : 1; // do not wrap struct stream as AVIOContext bool use_stream_ids : 1; // export the native stream IDs + bool fully_read : 1; // set demuxer.fully_read flag // Do not confuse player's position estimation (position is into external // segment, with e.g. HLS, player knows about the playlist main file only). bool clear_filepos : 1; }; #define BLACKLIST(fmt) {fmt, .ignore = true} +#define TEXTSUB(fmt) {fmt, .fully_read = true} static const struct format_hack format_hacks[] = { // for webradios @@ -123,6 +125,11 @@ static const struct format_hack format_hacks[] = { {"mpeg", .use_stream_ids = true}, {"mpegts", .use_stream_ids = true}, + TEXTSUB("aqtitle"), TEXTSUB("ass"), TEXTSUB("jacosub"), TEXTSUB("microdvd"), + TEXTSUB("mpl2"), TEXTSUB("mpsub"), TEXTSUB("pjs"), TEXTSUB("realtext"), + TEXTSUB("sami"), TEXTSUB("srt"), TEXTSUB("stl"), TEXTSUB("subviewer"), + TEXTSUB("subviewer1"), TEXTSUB("vplayer"), TEXTSUB("webvtt"), + // Useless non-sense, sometimes breaks MLP2 subreader.c fallback BLACKLIST("tty"), // Image demuxers, disabled in favor of demux_mf (for now): @@ -815,6 +822,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) 0 : (double)priv->avfc->start_time / AV_TIME_BASE; demuxer->allow_refresh_seeks = matches_avinputformat_name(priv, "mp4"); + demuxer->fully_read = priv->format_hack.fully_read; return 0; } diff --git a/demux/demux_libass.c b/demux/demux_libass.c index a528f73459..b83408b21b 100644 --- a/demux/demux_libass.c +++ b/demux/demux_libass.c @@ -99,6 +99,7 @@ static int d_check_file(struct demuxer *demuxer, enum demux_check check) sh->sub->extradata_len = cbuf.len; demuxer->seekable = true; + demuxer->fully_read = true; return 0; } diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index 516632af0f..381b50f269 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -273,6 +273,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) playlist_add_base_path(p->pl, mp_dirname(demuxer->filename)); demuxer->playlist = talloc_steal(demuxer, p->pl); demuxer->filetype = fmt->name; + demuxer->fully_read = true; talloc_free(p); return ok ? 0 : -1; } diff --git a/demux/demux_subreader.c b/demux/demux_subreader.c index 145754be6d..4ea5bb9c43 100644 --- a/demux/demux_subreader.c +++ b/demux/demux_subreader.c @@ -791,6 +791,7 @@ static int d_open_file(struct demuxer *demuxer, enum demux_check check) subdata_free(sd); demuxer->seekable = true; + demuxer->fully_read = true; return 0; } diff --git a/player/loadfile.c b/player/loadfile.c index aba8b6c7df..bbfff46fe2 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -291,8 +291,8 @@ static void enable_demux_thread(struct MPContext *mpctx) demux_start_thread(mpctx->demuxer); for (int n = 0; n < mpctx->num_tracks; n++) { struct track *track = mpctx->tracks[n]; - if (track->is_external && track->stream && - track->stream->type != STREAM_SUB) + if (track->is_external && track->stream && !track->preloaded && + !track->demuxer->fully_read) { demux_set_wakeup_cb(track->demuxer, wakeup_demux, mpctx); demux_start_thread(track->demuxer); @@ -689,6 +689,7 @@ struct track *mp_add_external_file(struct MPContext *mpctx, char *filename, struct stream *stream = stream_open(filename, mpctx->global); if (!stream) goto err_out; + stream_enable_cache(&stream, &opts->stream_cache); char *demuxer_name = NULL; switch (filter) { @@ -697,7 +698,6 @@ struct track *mp_add_external_file(struct MPContext *mpctx, char *filename, break; case STREAM_AUDIO: demuxer_name = opts->audio_demuxer_name; - stream_enable_cache(&stream, &opts->stream_cache); break; } @@ -731,6 +731,8 @@ struct track *mp_add_external_file(struct MPContext *mpctx, char *filename, } MP_TARRAY_APPEND(NULL, mpctx->sources, mpctx->num_sources, demuxer); + if (mpctx->playback_initialized) + enable_demux_thread(mpctx); return first; err_out: diff --git a/player/sub.c b/player/sub.c index 16affc4448..f4c9e7822b 100644 --- a/player/sub.c +++ b/player/sub.c @@ -321,6 +321,8 @@ static void reinit_subdec(struct MPContext *mpctx, struct track *track, if (!track->preloaded && track->is_external && !opts->sub_clear_on_seek) { demux_seek(track->demuxer, 0, SEEK_ABSOLUTE); track->preloaded = sub_read_all_packets(dec_sub, track->stream); + if (track->preloaded) + demux_stop_thread(track->demuxer); } }