diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 82c51fc503..d4cef55bf3 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -267,6 +267,26 @@ Playback Control Note that ``--playlist`` always loads all entries, so you use that instead if you really have the need for this functionality. +``--access-references=`` + Follow any references in the file being opened (default: yes). Disabling + this is helpful if the file is automatically scanned (e.g. thumbnail + generation). If the thumbnail scanner for example encounters a playlist + file, which contains network URLs, and the scanner should not open these, + enabling this option will prevent it. This option also disables ordered + chapters, mov reference files, opening of archives, and a number of other + features. + + On older FFmpeg versions, this will not work in some cases. Some FFmpeg + demuxers might not respect this option. + + This option does not prevent opening of paired subtitle files and such. Use + ``--autoload-files=no`` to prevent this. + + This option does not always work if you open non-files (for example using + ``dvd://directory`` would open a whole bunch of files in the given + directory). Prefixing the filename with ``./`` if it doesn't start with + a ``/`` will avoid this. + ``--loop-file=`` Loop a single file N times. ``inf`` means forever, ``no`` means normal playback. For compatibility, ``--loop-file`` and ``--loop-file=yes`` are diff --git a/demux/demux.c b/demux/demux.c index 8aa9989de3..18c9b3b5c1 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -89,6 +89,7 @@ struct demux_opts { double min_secs; int force_seekable; double min_secs_cache; + int access_references; }; #define OPT_BASE_STRUCT struct demux_opts @@ -100,6 +101,7 @@ const struct m_sub_options demux_conf = { OPT_INTRANGE("demuxer-max-bytes", max_bytes, 0, 0, INT_MAX), OPT_FLAG("force-seekable", force_seekable, 0), OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0), + OPT_FLAG("access-references", access_references, 0), {0} }, .size = sizeof(struct demux_opts), @@ -108,6 +110,7 @@ const struct m_sub_options demux_conf = { .max_bytes = 400 * 1024 * 1024, .min_secs = 1.0, .min_secs_cache = 10.0, + .access_references = 1, }, }; @@ -1213,6 +1216,7 @@ static struct demuxer *open_given_type(struct mpv_global *global, return NULL; struct demuxer *demuxer = talloc_ptrtype(NULL, demuxer); + struct demux_opts *opts = mp_get_config_group(demuxer, global, &demux_conf); *demuxer = (struct demuxer) { .desc = desc, .stream = stream, @@ -1223,6 +1227,7 @@ static struct demuxer *open_given_type(struct mpv_global *global, .glog = log, .filename = talloc_strdup(demuxer, stream->url), .is_network = stream->is_network, + .access_references = opts->access_references, .events = DEMUX_EVENT_ALL, }; demuxer->seekable = stream->seekable; @@ -1230,8 +1235,6 @@ static struct demuxer *open_given_type(struct mpv_global *global, !demuxer->stream->uncached_stream->seekable) demuxer->seekable = false; - struct demux_opts *opts = mp_get_config_group(demuxer, global, &demux_conf); - struct demux_internal *in = demuxer->in = talloc_ptrtype(demuxer, in); *in = (struct demux_internal){ .log = demuxer->log, diff --git a/demux/demux.h b/demux/demux.h index 18f52d463d..0e5a5e15c6 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -186,6 +186,7 @@ typedef struct demuxer { // Typical examples: text subtitles, playlists bool fully_read; bool is_network; // opened directly from a network stream + bool access_references; // allow opening other files/URLs // Bitmask of DEMUX_EVENT_* int events; diff --git a/demux/demux_cue.c b/demux/demux_cue.c index 673e8b9f27..ba97ca0c1b 100644 --- a/demux/demux_cue.c +++ b/demux/demux_cue.c @@ -253,6 +253,9 @@ out: static int try_open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + struct stream *s = demuxer->stream; if (check >= DEMUX_CHECK_UNSAFE) { bstr d = stream_peek(s, PROBE_SIZE); diff --git a/demux/demux_edl.c b/demux/demux_edl.c index 67a4290303..623cae35b3 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -295,6 +295,9 @@ static void build_mpv_edl_timeline(struct timeline *tl) static int try_open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + struct priv *p = talloc_zero(demuxer, struct priv); demuxer->priv = p; demuxer->fully_read = true; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index d5598a942b..94bcd3fff6 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "config.h" @@ -754,6 +755,14 @@ static int interrupt_cb(void *ctx) return mp_cancel_test(priv->stream->cancel); } +static int block_io_open(struct AVFormatContext *s, AVIOContext **pb, + const char *url, int flags, AVDictionary **options) +{ + struct demuxer *demuxer = s->opaque; + MP_ERR(demuxer, "Not opening '%s' due to --access-references=no.\n", url); + return AVERROR(EACCES); +} + static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) { AVFormatContext *avfc; @@ -855,6 +864,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) .opaque = demuxer, }; +#if HAVE_AVFORMAT_IOOPEN + avfc->opaque = demuxer; + if (!demuxer->access_references) + avfc->io_open = block_io_open; +#endif + mp_set_avdict(&dopts, lavfdopts->avopts); if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) { diff --git a/demux/demux_libarchive.c b/demux/demux_libarchive.c index dcdbe65fc0..41b05368ca 100644 --- a/demux/demux_libarchive.c +++ b/demux/demux_libarchive.c @@ -32,6 +32,9 @@ static int cmp_filename(const void *a, const void *b) static int open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + int flags = 0; int probe_size = STREAM_BUFFER_SIZE; if (check <= DEMUX_CHECK_REQUEST) { diff --git a/demux/demux_mkv_timeline.c b/demux/demux_mkv_timeline.c index 15f9a5d594..476551c58b 100644 --- a/demux/demux_mkv_timeline.c +++ b/demux/demux_mkv_timeline.c @@ -519,7 +519,7 @@ void build_ordered_chapter_timeline(struct timeline *tl) .opts = mp_get_config_group(ctx, tl->global, NULL), }; - if (!ctx->opts->ordered_chapters) { + if (!ctx->opts->ordered_chapters || !demuxer->access_references) { MP_INFO(demuxer, "File uses ordered chapters, but " "you have disabled support for them. Ignoring.\n"); talloc_free(ctx); diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index 7479db149f..0f2ebedd76 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -283,6 +283,8 @@ static int parse_dir(struct pl_parser *p) return 0; char *path = mp_file_get_path(p, bstr0(p->real_stream->url)); + if (!path) + return -1; char **files = NULL; int num_files = 0; @@ -339,6 +341,9 @@ static const struct pl_format *probe_pl(struct pl_parser *p) static int open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + bool force = check < DEMUX_CHECK_UNSAFE || check == DEMUX_CHECK_REQUEST; struct pl_parser *p = talloc_zero(NULL, struct pl_parser); diff --git a/demux/demux_rar.c b/demux/demux_rar.c index f35c2ccf66..7d9adfc28a 100644 --- a/demux/demux_rar.c +++ b/demux/demux_rar.c @@ -23,6 +23,9 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + if (RarProbe(demuxer->stream)) return -1; diff --git a/stream/stream.c b/stream/stream.c index c936c5c77e..4c7aa04844 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -230,6 +230,12 @@ static int open_internal(const stream_info_t *sinfo, const char *url, int flags, s->is_network = sinfo->is_network; s->mode = flags & (STREAM_READ | STREAM_WRITE); + if (global->config) { + int opt; + mp_read_option_raw(global, "access-references", &m_option_type_flag, &opt); + s->access_references = opt; + } + MP_VERBOSE(s, "Opening %s\n", url); if ((s->mode & STREAM_WRITE) && !sinfo->can_write) { diff --git a/stream/stream.h b/stream/stream.h index 4444da8ed3..7d44e30eae 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -197,6 +197,7 @@ typedef struct stream { bool fast_skip : 1; // consider stream fast enough to fw-seek by skipping bool is_network : 1; // original stream_info_t.is_network flag bool allow_caching : 1; // stream cache makes sense + bool access_references : 1; // open other streams struct mp_log *log; struct mpv_global *global; diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c index 26a78e5f21..5f083954c2 100644 --- a/stream/stream_bluray.c +++ b/stream/stream_bluray.c @@ -569,6 +569,9 @@ static int bdmv_dir_stream_open(stream_t *stream) .cfg_title = BLURAY_DEFAULT_TITLE, }; + if (!stream->access_references) + goto unsupported; + char *path = mp_file_get_path(priv, bstr0(stream->url)); if (!path) goto unsupported; diff --git a/stream/stream_dvd.c b/stream/stream_dvd.c index 4b423de630..338c23633c 100644 --- a/stream/stream_dvd.c +++ b/stream/stream_dvd.c @@ -951,6 +951,9 @@ static int ifo_stream_open(stream_t *stream) dvd_priv_t *priv = talloc_zero(stream, dvd_priv_t); stream->priv = priv; + if (!stream->access_references) + goto unsupported; + char *path = mp_file_get_path(priv, bstr0(stream->url)); if (!path) goto unsupported; diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c index ec15c83b20..1178f50857 100644 --- a/stream/stream_dvdnav.c +++ b/stream/stream_dvdnav.c @@ -562,6 +562,9 @@ static int ifo_dvdnav_stream_open(stream_t *stream) struct priv *priv = talloc_zero(stream, struct priv); stream->priv = priv; + if (!stream->access_references) + goto unsupported; + priv->track = TITLE_LONGEST; char *path = mp_file_get_path(priv, bstr0(stream->url)); diff --git a/wscript b/wscript index caa5570dd5..b098099cc1 100644 --- a/wscript +++ b/wscript @@ -528,6 +528,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ 'func': check_statement('libavutil/frame.h', 'AV_FRAME_DATA_MASTERING_DISPLAY_METADATA', use='libav'), + }, { + 'name': 'avformat-ioopen', + 'desc': 'libavformat io_open callback', + 'func': check_statement('libavformat/avformat.h', + 'offsetof(AVFormatContext, io_open)', + use='libav'), } ]