demux: do not access global options

Don't access MPOpts directly, and always use the new m_config.h
functions for accessing them in a thread-safe way.

The goal is eventually removing the mpv_global.opts field, and the
demuxer/stream-layer specific hack that copies MPOpts to deal with
thread-safety issues.

This moves around a lot of options. For one, we often change the
physical storage location of options to make them more localized,
but these changes are not user-visible (or should not be). For
shared options on the other hand it's better to do messy direct
access, which is worrying as in that somehow renaming an option
or changing its type would break code reading them manually,
without causing a compilation error.
This commit is contained in:
wm4 2016-09-06 20:09:56 +02:00
parent 9f0e7bb998
commit d4d8b3a4fc
13 changed files with 241 additions and 168 deletions

View File

@ -20,6 +20,7 @@
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <limits.h>
#include <pthread.h>
#include <math.h>
@ -28,7 +29,8 @@
#include <sys/stat.h>
#include "config.h"
#include "options/options.h"
#include "options/m_config.h"
#include "options/m_option.h"
#include "mpv_talloc.h"
#include "common/msg.h"
#include "common/global.h"
@ -81,6 +83,34 @@ const demuxer_desc_t *const demuxer_list[] = {
NULL
};
struct demux_opts {
int max_packs;
int max_bytes;
double min_secs;
int force_seekable;
double min_secs_cache;
};
#define OPT_BASE_STRUCT struct demux_opts
const struct m_sub_options demux_conf = {
.opts = (const struct m_option[]){
OPT_DOUBLE("demuxer-readahead-secs", min_secs, M_OPT_MIN, .min = 0),
OPT_INTRANGE("demuxer-max-packets", max_packs, 0, 0, INT_MAX),
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),
{0}
},
.size = sizeof(struct demux_opts),
.defaults = &(const struct demux_opts){
.max_packs = 16000,
.max_bytes = 400 * 1024 * 1024,
.min_secs = 1.0,
.min_secs_cache = 10.0,
},
};
struct demux_internal {
struct mp_log *log;
@ -1185,7 +1215,6 @@ static struct demuxer *open_given_type(struct mpv_global *global,
.stream = stream,
.seekable = stream->seekable,
.filepos = -1,
.opts = global->opts,
.global = global,
.log = mp_log_new(demuxer, log, desc->name),
.glog = log,
@ -1198,22 +1227,24 @@ 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,
.d_thread = talloc(demuxer, struct demuxer),
.d_buffer = talloc(demuxer, struct demuxer),
.d_user = demuxer,
.min_secs = demuxer->opts->demuxer_min_secs,
.max_packs = demuxer->opts->demuxer_max_packs,
.max_bytes = demuxer->opts->demuxer_max_bytes,
.min_secs = opts->min_secs,
.max_packs = opts->max_packs,
.max_bytes = opts->max_bytes,
.initial_state = true,
};
pthread_mutex_init(&in->lock, NULL);
pthread_cond_init(&in->wakeup, NULL);
if (stream->uncached_stream)
in->min_secs = MPMAX(in->min_secs, demuxer->opts->demuxer_min_secs_cache);
in->min_secs = MPMAX(in->min_secs, opts->min_secs_cache);
*in->d_thread = *demuxer;
*in->d_buffer = *demuxer;
@ -1244,7 +1275,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
mp_verbose(log, "Detected file format: %s\n", desc->desc);
if (!in->d_thread->seekable)
mp_verbose(log, "Stream is not seekable.\n");
if (!in->d_thread->seekable && demuxer->opts->force_seekable) {
if (!in->d_thread->seekable && opts->force_seekable) {
mp_warn(log, "Not seekable, but enabling seeking on user request.\n");
in->d_thread->seekable = true;
in->d_thread->partially_seekable = true;
@ -1336,7 +1367,6 @@ struct demuxer *demux_open_url(const char *url,
struct mp_cancel *cancel,
struct mpv_global *global)
{
struct MPOpts *opts = global->opts;
struct demuxer_params dummy = {0};
if (!params)
params = &dummy;
@ -1344,10 +1374,14 @@ struct demuxer *demux_open_url(const char *url,
cancel, global);
if (!s)
return NULL;
if (params->allow_capture)
stream_set_capture_file(s, opts->stream_capture);
if (params->allow_capture) {
char *f;
mp_read_option_raw(global, "stream-capture", &m_option_type_string, &f);
stream_set_capture_file(s, f);
talloc_free(f);
}
if (!params->disable_cache)
stream_enable_cache(&s, &opts->stream_cache);
stream_enable_cache_defaults(&s);
struct demuxer *d = demux_open(s, params, global);
if (d) {
demux_maybe_replace_stream(d);

View File

@ -207,7 +207,6 @@ typedef struct demuxer {
struct mp_tags *metadata;
void *priv; // demuxer-specific internal data
struct MPOpts *opts;
struct mpv_global *global;
struct mp_log *log, *glog;
struct demuxer_params *params;

View File

@ -35,7 +35,6 @@
#include <libavutil/display.h>
#include <libavutil/opt.h>
#include "options/options.h"
#include "common/msg.h"
#include "common/tags.h"
#include "common/av_common.h"
@ -45,6 +44,7 @@
#include "stream/stream.h"
#include "demux.h"
#include "stheader.h"
#include "options/m_config.h"
#include "options/m_option.h"
#include "options/path.h"
@ -69,22 +69,32 @@ struct demux_lavf_opts {
char **avopts;
int hacks;
int genptsmode;
char *sub_cp;
int rtsp_transport;
};
const struct m_sub_options demux_lavf_conf = {
.opts = (const m_option_t[]) {
OPT_INTRANGE("probesize", probesize, 0, 32, INT_MAX),
OPT_STRING("format", format, 0),
OPT_FLOATRANGE("analyzeduration", analyzeduration, 0, 0, 3600),
OPT_INTRANGE("buffersize", buffersize, 0, 1, 10 * 1024 * 1024,
OPTDEF_INT(BIO_BUFFER_SIZE)),
OPT_FLAG("allow-mimetype", allow_mimetype, 0),
OPT_INTRANGE("probescore", probescore, 0, 1, AVPROBE_SCORE_MAX),
OPT_STRING("cryptokey", cryptokey, 0),
OPT_FLAG("hacks", hacks, 0),
OPT_CHOICE("genpts-mode", genptsmode, 0,
OPT_INTRANGE("demuxer-lavf-probesize", probesize, 0, 32, INT_MAX),
OPT_STRING("demuxer-lavf-format", format, 0),
OPT_FLOATRANGE("demuxer-lavf-analyzeduration", analyzeduration, 0,
0, 3600),
OPT_INTRANGE("demuxer-lavf-buffersize", buffersize, 0, 1,
10 * 1024 * 1024, OPTDEF_INT(BIO_BUFFER_SIZE)),
OPT_FLAG("demuxer-lavf-allow-mimetype", allow_mimetype, 0),
OPT_INTRANGE("demuxer-lavf-probescore", probescore, 0,
1, AVPROBE_SCORE_MAX),
OPT_STRING("demuxer-lavf-cryptokey", cryptokey, 0),
OPT_FLAG("demuxer-lavf-hacks", hacks, 0),
OPT_CHOICE("demuxer-lavf-genpts-mode", genptsmode, 0,
({"lavf", 1}, {"no", 0})),
OPT_KEYVALUELIST("o", avopts, 0),
OPT_KEYVALUELIST("demuxer-lavf-o", avopts, 0),
OPT_STRING("sub-codepage", sub_cp, 0),
OPT_CHOICE("rtsp-transport", rtsp_transport, 0,
({"lavf", 0},
{"udp", 1},
{"tcp", 2},
{"http", 3})),
{0}
},
.size = sizeof(struct demux_lavf_opts),
@ -95,6 +105,8 @@ const struct m_sub_options demux_lavf_conf = {
// user is supposed to retry with larger probe sizes until a higher
// value is reached.
.probescore = AVPROBE_SCORE_MAX/4 + 1,
.sub_cp = "auto",
.rtsp_transport = 2,
},
};
@ -174,6 +186,9 @@ typedef struct lavf_priv {
int cur_program;
char *mime_type;
double seek_delay;
struct demux_lavf_opts *opts;
double mf_fps;
} lavf_priv_t;
// At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name
@ -271,7 +286,7 @@ static void list_formats(struct demuxer *demuxer)
static void convert_charset(struct demuxer *demuxer)
{
lavf_priv_t *priv = demuxer->priv;
char *cp = demuxer->opts->sub_cp;
char *cp = priv->opts->sub_cp;
if (!cp || mp_charset_is_utf8(cp))
return;
bstr data = stream_read_complete(priv->stream, NULL, 128 * 1024 * 1024);
@ -313,9 +328,8 @@ static const char *const prefixes[] =
static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
{
struct MPOpts *opts = demuxer->opts;
struct demux_lavf_opts *lavfdopts = opts->demux_lavf;
lavf_priv_t *priv = demuxer->priv;
struct demux_lavf_opts *lavfdopts = priv->opts;
struct stream *s = priv->stream;
priv->filename = remove_prefix(s->url, prefixes);
@ -606,7 +620,7 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
if (st->avg_frame_rate.num)
sh->codec->fps = av_q2d(st->avg_frame_rate);
if (priv->format_hack.image_format)
sh->codec->fps = demuxer->opts->mf_fps;
sh->codec->fps = priv->mf_fps;
sh->codec->par_w = st->sample_aspect_ratio.num;
sh->codec->par_h = st->sample_aspect_ratio.den;
@ -736,8 +750,6 @@ static int interrupt_cb(void *ctx)
static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
{
struct MPOpts *opts = demuxer->opts;
struct demux_lavf_opts *lavfdopts = opts->demux_lavf;
AVFormatContext *avfc;
AVDictionaryEntry *t = NULL;
float analyze_duration = 0;
@ -745,6 +757,15 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
demuxer->priv = priv;
priv->stream = demuxer->stream;
priv->opts = mp_get_config_group(priv, demuxer->global, &demux_lavf_conf);
struct demux_lavf_opts *lavfdopts = priv->opts;
int index_mode;
mp_read_option_raw(demuxer->global, "index", &m_option_type_choice,
&index_mode);
mp_read_option_raw(demuxer->global, "mf-fps", &m_option_type_double,
&priv->mf_fps);
if (lavf_check_file(demuxer, check) < 0)
return -1;
@ -756,7 +777,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
parse_cryptokey(avfc, lavfdopts->cryptokey);
if (lavfdopts->genptsmode)
avfc->flags |= AVFMT_FLAG_GENPTS;
if (opts->index_mode != 1)
if (index_mode != 1)
avfc->flags |= AVFMT_FLAG_IGNIDX;
#if LIBAVFORMAT_VERSION_MICRO >= 100
@ -789,7 +810,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
priv->stream->type == STREAMTYPE_AVDEVICE ||
priv->format_hack.no_stream)
{
mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log, opts);
mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log);
// This might be incorrect.
demuxer->seekable = true;
} else {
@ -812,7 +833,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
if (matches_avinputformat_name(priv, "rtsp")) {
const char *transport = NULL;
switch (opts->network_rtsp_transport) {
switch (lavfdopts->rtsp_transport) {
case 1: transport = "udp"; break;
case 2: transport = "tcp"; break;
case 3: transport = "http"; break;

View File

@ -27,6 +27,7 @@
#include "mpv_talloc.h"
#include "common/msg.h"
#include "options/options.h"
#include "options/m_config.h"
#include "options/path.h"
#include "misc/ctype.h"
@ -304,10 +305,15 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check)
if (!mf || mf->nr_of_files < 1)
goto error;
char *force_type = demuxer->opts->mf_type;
double mf_fps;
char *mf_type;
mp_read_option_raw(demuxer->global, "mf-fps", &m_option_type_double, &mf_fps);
mp_read_option_raw(demuxer->global, "mf-type", &m_option_type_string, &mf_type);
const char *codec = mp_map_mimetype_to_video_codec(demuxer->stream->mime_type);
if (!codec || (force_type && force_type[0]))
codec = probe_format(mf, force_type, check);
if (!codec || (mf_type && mf_type[0]))
codec = probe_format(mf, mf_type, check);
talloc_free(mf_type);
if (!codec)
goto error;
@ -320,7 +326,7 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check)
c->codec = codec;
c->disp_w = 0;
c->disp_h = 0;
c->fps = demuxer->opts->mf_fps;
c->fps = mf_fps;
c->reliable_fps = true;
demux_add_sh_stream(demuxer, sh);

View File

@ -43,7 +43,7 @@
#include "mpv_talloc.h"
#include "common/av_common.h"
#include "options/options.h"
#include "options/m_config.h"
#include "options/m_option.h"
#include "misc/bstr.h"
#include "stream/stream.h"
@ -162,6 +162,8 @@ struct block_info {
};
typedef struct mkv_demuxer {
struct demux_mkv_opts *opts;
int64_t segment_start, segment_end;
double duration;
@ -179,6 +181,9 @@ typedef struct mkv_demuxer {
mkv_index_t *indexes;
size_t num_indexes;
bool index_complete;
int index_mode;
int edition_id;
struct header_elem {
int32_t id;
@ -747,11 +752,10 @@ static void add_block_position(demuxer_t *demuxer, struct mkv_track *track,
static int demux_mkv_read_cues(demuxer_t *demuxer)
{
struct MPOpts *opts = demuxer->opts;
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
stream_t *s = demuxer->stream;
if (opts->index_mode != 1 || mkv_d->index_complete) {
if (mkv_d->index_mode != 1 || mkv_d->index_complete) {
ebml_read_skip(demuxer->log, -1, s);
return 0;
}
@ -810,9 +814,9 @@ done:
static int demux_mkv_read_chapters(struct demuxer *demuxer)
{
struct MPOpts *opts = demuxer->opts;
mkv_demuxer_t *mkv_d = demuxer->priv;
stream_t *s = demuxer->stream;
int wanted_edition = opts->edition_id;
int wanted_edition = mkv_d->edition_id;
uint64_t wanted_edition_uid = demuxer->matroska_data.uid.edition;
/* A specific edition UID was requested; ignore the user option which is
@ -1191,10 +1195,9 @@ static int read_deferred_element(struct demuxer *demuxer,
static void read_deferred_cues(demuxer_t *demuxer)
{
struct MPOpts *opts = demuxer->opts;
mkv_demuxer_t *mkv_d = demuxer->priv;
if (mkv_d->index_complete || opts->index_mode != 1)
if (mkv_d->index_complete || mkv_d->index_mode != 1)
return;
for (int n = 0; n < mkv_d->num_headers; n++) {
@ -1855,7 +1858,6 @@ static int read_mkv_segment_header(demuxer_t *demuxer, int64_t *segment_end)
static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
{
stream_t *s = demuxer->stream;
struct MPOpts *opts = demuxer->opts;
mkv_demuxer_t *mkv_d;
int64_t start_pos;
int64_t end_pos;
@ -1882,6 +1884,12 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
mkv_d->a_skip_preroll = 1;
mkv_d->skip_to_timecode = INT64_MIN;
mp_read_option_raw(demuxer->global, "index", &m_option_type_choice,
&mkv_d->index_mode);
mp_read_option_raw(demuxer->global, "edition", &m_option_type_choice,
&mkv_d->edition_id);
mkv_d->opts = mp_get_config_group(mkv_d, demuxer->global, &demux_mkv_conf);
if (demuxer->params && demuxer->params->matroska_was_valid)
*demuxer->params->matroska_was_valid = true;
@ -1941,7 +1949,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
process_tags(demuxer);
probe_first_timestamp(demuxer);
if (opts->demux_mkv->probe_duration)
if (mkv_d->opts->probe_duration)
probe_last_timestamp(demuxer, start_pos);
return 0;
@ -2730,7 +2738,6 @@ static int create_index_until(struct demuxer *demuxer, int64_t timecode)
static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
int64_t target_timecode, int flags)
{
struct MPOpts *opts = demuxer->opts;
struct mkv_demuxer *mkv_d = demuxer->priv;
struct mkv_index *index = NULL;
@ -2758,9 +2765,9 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
if (flags & FLAG_SUBPREROLL) {
// Find the cluster with the highest filepos, that has a timestamp
// still lower than min_tc.
double secs = opts->demux_mkv->subtitle_preroll_secs;
double secs = mkv_d->opts->subtitle_preroll_secs;
if (mkv_d->index_has_durations)
secs = MPMAX(secs, opts->demux_mkv->subtitle_preroll_secs_index);
secs = MPMAX(secs, mkv_d->opts->subtitle_preroll_secs_index);
int64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale);
int64_t min_tc = pre < index->timecode ? index->timecode - pre : 0;
uint64_t prev_target = 0;
@ -2823,7 +2830,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double seek_pts, int flags)
int cueflags = (flags & SEEK_BACKWARD) ? FLAG_BACKWARD : 0;
mkv_d->subtitle_preroll = NUM_SUB_PREROLL_PACKETS;
int preroll_opt = demuxer->opts->demux_mkv->subtitle_preroll;
int preroll_opt = mkv_d->opts->subtitle_preroll;
if (((flags & SEEK_HR) || preroll_opt == 1 ||
(preroll_opt == 2 && mkv_d->index_has_durations))
&& st_active[STREAM_SUB] && st_active[STREAM_VIDEO])
@ -2917,7 +2924,7 @@ static void probe_last_timestamp(struct demuxer *demuxer, int64_t start_pos)
// In full mode, we start reading data from the current file position,
// which works because this function is called after headers are parsed.
if (demuxer->opts->demux_mkv->probe_duration != 2) {
if (mkv_d->opts->probe_duration != 2) {
read_deferred_cues(demuxer);
if (mkv_d->index_complete) {
// Find last cluster that still has video packets
@ -2974,7 +2981,7 @@ static void probe_first_timestamp(struct demuxer *demuxer)
{
mkv_demuxer_t *mkv_d = demuxer->priv;
if (!demuxer->opts->demux_mkv->probe_start_time)
if (!mkv_d->opts->probe_start_time)
return;
struct block_info block;

View File

@ -32,10 +32,10 @@
#include "mpv_talloc.h"
#include "common/msg.h"
#include "common/global.h"
#include "demux/demux.h"
#include "demux/timeline.h"
#include "demux/matroska.h"
#include "options/m_config.h"
#include "options/options.h"
#include "options/path.h"
#include "misc/bstr.h"
@ -46,6 +46,7 @@
struct tl_ctx {
struct mp_log *log;
struct mpv_global *global;
struct MPOpts *opts;
struct timeline *tl;
struct demuxer *demuxer;
@ -209,8 +210,7 @@ static bool check_file_seg(struct tl_ctx *ctx, char *filename, int segment)
MP_TARRAY_APPEND(NULL, ctx->sources, ctx->num_sources, NULL);
}
if (stream_wants_cache(d->stream, &ctx->global->opts->stream_cache))
{
if (stream_wants_cache(d->stream, ctx->opts->stream_cache)) {
free_demuxer_and_stream(d);
params.disable_cache = false;
params.matroska_wanted_uids = ctx->uids; // potentially reallocated, same data
@ -247,7 +247,7 @@ static bool missing(struct tl_ctx *ctx)
static void find_ordered_chapter_sources(struct tl_ctx *ctx)
{
struct MPOpts *opts = ctx->global->opts;
struct MPOpts *opts = ctx->opts;
void *tmp = talloc_new(NULL);
int num_filenames = 0;
char **filenames = NULL;
@ -317,7 +317,7 @@ static int64_t add_timeline_part(struct tl_ctx *ctx,
* early; we don't want to try seeking over a one frame gap. */
int64_t join_diff = start - ctx->last_end_time;
if (ctx->num_parts == 0
|| FFABS(join_diff) > ctx->global->opts->chapter_merge_threshold * 1e6
|| FFABS(join_diff) > ctx->opts->chapter_merge_threshold * 1e6
|| source != ctx->timeline[ctx->num_parts - 1].source)
{
struct timeline_part new = {
@ -505,20 +505,22 @@ void build_ordered_chapter_timeline(struct timeline *tl)
if (!demuxer->matroska_data.ordered_chapters)
return;
if (!demuxer->global->opts->ordered_chapters) {
MP_INFO(demuxer, "File uses ordered chapters, but "
"you have disabled support for them. Ignoring.\n");
return;
}
struct tl_ctx *ctx = talloc_ptrtype(tl, ctx);
*ctx = (struct tl_ctx){
.log = tl->log,
.global = tl->global,
.tl = tl,
.demuxer = demuxer,
.opts = mp_get_config_group(ctx, tl->global, NULL),
};
if (!ctx->opts->ordered_chapters) {
MP_INFO(demuxer, "File uses ordered chapters, but "
"you have disabled support for them. Ignoring.\n");
talloc_free(ctx);
return;
}
MP_INFO(ctx, "File uses ordered chapters, will build edit timeline.\n");
struct matroska_data *m = &demuxer->matroska_data;

View File

@ -22,8 +22,8 @@
#include <unistd.h>
#include <string.h>
#include "options/m_config.h"
#include "options/m_option.h"
#include "options/options.h"
#include "stream/stream.h"
#include "demux.h"
@ -129,7 +129,8 @@ struct priv {
static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
{
struct demux_rawaudio_opts *opts = demuxer->opts->demux_rawaudio;
struct demux_rawaudio_opts *opts =
mp_get_config_group(demuxer, demuxer->global, &demux_rawaudio_conf);
if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE)
return -1;
@ -169,7 +170,8 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check)
{
struct demux_rawvideo_opts *opts = demuxer->opts->demux_rawvideo;
struct demux_rawvideo_opts *opts =
mp_get_config_group(demuxer, demuxer->global, &demux_rawvideo_conf);
if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE)
return -1;

View File

@ -76,6 +76,8 @@ extern const struct m_sub_options encode_config;
extern const struct m_sub_options gl_video_conf;
extern const struct m_sub_options ao_alsa_conf;
extern const struct m_sub_options demux_conf;
extern const struct m_obj_list vf_obj_list;
extern const struct m_obj_list af_obj_list;
extern const struct m_obj_list vo_obj_list;
@ -105,6 +107,35 @@ static const struct m_sub_options screenshot_conf = {
.defaults = &image_writer_opts_defaults,
};
#define OPT_BASE_STRUCT struct mp_cache_opts
const struct m_sub_options stream_cache_conf = {
.opts = (const struct m_option[]){
OPT_CHOICE_OR_INT("cache", size, 0, 32, 0x7fffffff,
({"no", 0},
{"auto", -1},
{"yes", -2})),
OPT_CHOICE_OR_INT("cache-default", def_size, 0, 32, 0x7fffffff,
({"no", 0})),
OPT_INTRANGE("cache-initial", initial, 0, 0, 0x7fffffff),
OPT_INTRANGE("cache-seek-min", seek_min, 0, 0, 0x7fffffff),
OPT_INTRANGE("cache-backbuffer", back_buffer, 0, 0, 0x7fffffff),
OPT_STRING("cache-file", file, M_OPT_FILE),
OPT_INTRANGE("cache-file-size", file_max, 0, 0, 0x7fffffff),
{0}
},
.size = sizeof(struct mp_cache_opts),
.defaults = &(const struct mp_cache_opts){
.size = -1,
.def_size = 75000,
.initial = 0,
.seek_min = 500,
.back_buffer = 75000,
.file_max = 1024 * 1024,
},
};
#undef OPT_BASE_STRUCT
#define OPT_BASE_STRUCT struct mp_vo_opts
static const m_option_t mp_vo_opt_list[] = {
@ -240,17 +271,7 @@ const m_option_t mp_opts[] = {
// ------------------------- stream options --------------------
OPT_CHOICE_OR_INT("cache", stream_cache.size, 0, 32, 0x7fffffff,
({"no", 0},
{"auto", -1},
{"yes", -2})),
OPT_CHOICE_OR_INT("cache-default", stream_cache.def_size, 0, 32, 0x7fffffff,
({"no", 0})),
OPT_INTRANGE("cache-initial", stream_cache.initial, 0, 0, 0x7fffffff),
OPT_INTRANGE("cache-seek-min", stream_cache.seek_min, 0, 0, 0x7fffffff),
OPT_INTRANGE("cache-backbuffer", stream_cache.back_buffer, 0, 0, 0x7fffffff),
OPT_STRING("cache-file", stream_cache.file, M_OPT_FILE),
OPT_INTRANGE("cache-file-size", stream_cache.file_max, 0, 0, 0x7fffffff),
OPT_SUBSTRUCT("", stream_cache, stream_cache_conf, 0),
#if HAVE_DVDREAD || HAVE_DVDNAV
OPT_STRING("dvd-device", dvd_device, M_OPT_FILE),
@ -265,22 +286,6 @@ const m_option_t mp_opts[] = {
OPT_INTRANGE("bluray-angle", bluray_angle, 0, 0, 999),
#endif /* HAVE_LIBBLURAY */
OPT_STRINGLIST("http-header-fields", network_http_header_fields, 0),
OPT_STRING("user-agent", network_useragent, 0),
OPT_STRING("referrer", network_referrer, 0),
OPT_FLAG("cookies", network_cookies_enabled, 0),
OPT_STRING("cookies-file", network_cookies_file, M_OPT_FILE),
OPT_CHOICE("rtsp-transport", network_rtsp_transport, 0,
({"lavf", 0},
{"udp", 1},
{"tcp", 2},
{"http", 3})),
OPT_FLAG("tls-verify", network_tls_verify, 0),
OPT_STRING("tls-ca-file", network_tls_ca_file, M_OPT_FILE),
OPT_STRING("tls-cert-file", network_tls_cert_file, M_OPT_FILE),
OPT_STRING("tls-key-file", network_tls_key_file, M_OPT_FILE),
OPT_DOUBLE("network-timeout", network_timeout, M_OPT_MIN, .min = 0),
// ------------------------- demuxer options --------------------
OPT_CHOICE_OR_INT("frames", play_frames, M_OPT_FIXED, 0, INT_MAX,
@ -342,13 +347,6 @@ const m_option_t mp_opts[] = {
OPT_STRING("audio-demuxer", audio_demuxer_name, 0),
OPT_STRING("sub-demuxer", sub_demuxer_name, 0),
OPT_FLAG("demuxer-thread", demuxer_thread, 0),
OPT_DOUBLE("demuxer-readahead-secs", demuxer_min_secs, M_OPT_MIN, .min = 0),
OPT_INTRANGE("demuxer-max-packets", demuxer_max_packs, 0, 0, INT_MAX),
OPT_INTRANGE("demuxer-max-bytes", demuxer_max_bytes, 0, 0, INT_MAX),
OPT_FLAG("force-seekable", force_seekable, 0),
OPT_DOUBLE("cache-secs", demuxer_min_secs_cache, M_OPT_MIN, .min = 0),
OPT_FLAG("cache-pause", cache_pausing, 0),
OPT_DOUBLE("mf-fps", mf_fps, 0),
@ -417,7 +415,7 @@ const m_option_t mp_opts[] = {
OPT_SUBSTRUCT("vd-lavc", vd_lavc_params, vd_lavc_conf, 0),
OPT_SUBSTRUCT("ad-lavc", ad_lavc_params, ad_lavc_conf, 0),
OPT_SUBSTRUCT("demuxer-lavf", demux_lavf, demux_lavf_conf, 0),
OPT_SUBSTRUCT("", demux_lavf, demux_lavf_conf, 0),
OPT_SUBSTRUCT("demuxer-rawaudio", demux_rawaudio, demux_rawaudio_conf, 0),
OPT_SUBSTRUCT("demuxer-rawvideo", demux_rawvideo, demux_rawvideo_conf, 0),
OPT_SUBSTRUCT("demuxer-mkv", demux_mkv, demux_mkv_conf, 0),
@ -429,7 +427,6 @@ const m_option_t mp_opts[] = {
OPT_PATHLIST("audio-file-paths", audiofile_paths, 0),
OPT_STRING_APPEND_LIST("external-file", external_files, M_OPT_FILE),
OPT_FLAG("autoload-files", autoload_files, 0),
OPT_STRING("sub-codepage", sub_cp, 0),
OPT_FLOAT("sub-delay", sub_delay, 0),
OPT_FLOAT("sub-fps", sub_fps, 0),
OPT_FLOAT("sub-speed", sub_speed, 0),
@ -652,6 +649,7 @@ const m_option_t mp_opts[] = {
OPT_PRINT("V", print_version),
OPT_SUBSTRUCT("", vo, vo_sub_opts, 0),
OPT_SUBSTRUCT("", demux_opts, demux_conf, 0),
#if HAVE_GL
OPT_SUBSTRUCT("", gl_video_opts, gl_video_conf, 0),
@ -799,22 +797,8 @@ const struct MPOpts mp_default_opts = {
.load_config = 1,
.position_resume = 1,
.autoload_files = 1,
.stream_cache = {
.size = -1,
.def_size = 75000,
.initial = 0,
.seek_min = 500,
.back_buffer = 75000,
.file_max = 1024 * 1024,
},
.demuxer_max_packs = 16000,
.demuxer_max_bytes = 400 * 1024 * 1024,
.demuxer_thread = 1,
.demuxer_min_secs = 1.0,
.network_rtsp_transport = 2,
.network_timeout = 0.0,
.hls_bitrate = INT_MAX,
.demuxer_min_secs_cache = 10.0,
.cache_pausing = 1,
.chapterrange = {-1, -1},
.ab_loop = {MP_NOPTS_VALUE, MP_NOPTS_VALUE},
@ -863,7 +847,6 @@ const struct MPOpts mp_default_opts = {
.ass_shaper = 1,
.use_embedded_fonts = 1,
.sub_fix_timing = 1,
.sub_cp = "auto",
.screenshot_template = "mpv-shot%n",
.hwdec_codecs = "h264,vc1,wmv3,hevc,mpeg2video,vp9",

View File

@ -149,9 +149,8 @@ typedef struct MPOpts {
int load_config;
char *force_configdir;
int use_filedir_conf;
int network_rtsp_transport;
int hls_bitrate;
struct mp_cache_opts stream_cache;
struct mp_cache_opts *stream_cache;
int chapterrange[2];
int edition_id;
int correct_pts;
@ -211,19 +210,13 @@ typedef struct MPOpts {
int stretch_image_subs;
int sub_fix_timing;
char *sub_cp;
char **audio_files;
char *demuxer_name;
int demuxer_max_packs;
int demuxer_max_bytes;
int demuxer_thread;
double demuxer_min_secs;
char *audio_demuxer_name;
char *sub_demuxer_name;
int force_seekable;
double demuxer_min_secs_cache;
int cache_pausing;
struct image_writer_opts *screenshot_image_opts;
@ -290,17 +283,6 @@ typedef struct MPOpts {
int w32_priority;
int network_cookies_enabled;
char *network_cookies_file;
char *network_useragent;
char *network_referrer;
char **network_http_header_fields;
int network_tls_verify;
char *network_tls_ca_file;
char *network_tls_cert_file;
char *network_tls_key_file;
double network_timeout;
struct tv_params *tv_params;
struct pvr_params *stream_pvr_opts;
struct cdda_params *stream_cdda_opts;
@ -323,6 +305,8 @@ typedef struct MPOpts {
struct demux_lavf_opts *demux_lavf;
struct demux_mkv_opts *demux_mkv;
struct demux_opts *demux_opts;
struct vd_lavc_params *vd_lavc_params;
struct ad_lavc_params *ad_lavc_params;
@ -340,5 +324,6 @@ typedef struct MPOpts {
extern const m_option_t mp_opts[];
extern const struct MPOpts mp_default_opts;
extern const struct m_sub_options vo_sub_opts;
extern const struct m_sub_options stream_cache_conf;
#endif

View File

@ -374,13 +374,9 @@ struct MPContext *mp_create(void)
mpctx->log = mp_log_new(mpctx, mpctx->global->log, "!cplayer");
mpctx->statusline = mp_log_new(mpctx, mpctx->log, "!statusline");
struct MPOpts *def_opts = talloc_ptrtype(mpctx, def_opts);
*def_opts = mp_default_opts;
def_opts->network_useragent = (char *)mpv_version;
// Create the config context and register the options
mpctx->mconfig = m_config_new(mpctx, mpctx->log, sizeof(struct MPOpts),
def_opts, mp_opts);
&mp_default_opts, mp_opts);
mpctx->opts = mpctx->mconfig->optstruct;
mpctx->mconfig->includefunc = cfg_include;
mpctx->mconfig->includefunc_ctx = mpctx;

View File

@ -784,7 +784,7 @@ bool stream_wants_cache(stream_t *stream, struct mp_cache_opts *opts)
// return 1 on success, 0 if the cache is disabled/not needed, and -1 on error
// or if the cache is disabled
int stream_enable_cache(stream_t **stream, struct mp_cache_opts *opts)
static int stream_enable_cache(stream_t **stream, struct mp_cache_opts *opts)
{
stream_t *orig = *stream;
struct mp_cache_opts use_opts = check_cache_opts(*stream, opts);
@ -815,6 +815,20 @@ int stream_enable_cache(stream_t **stream, struct mp_cache_opts *opts)
return res;
}
// Do some crazy stuff to call stream_enable_cache() with the global options.
int stream_enable_cache_defaults(stream_t **stream)
{
struct mpv_global *global = (*stream)->global;
if (!global)
return 0;
void *tmp = talloc_new(NULL);
struct mp_cache_opts *opts =
mp_get_config_group(tmp, global, &stream_cache_conf);
int r = stream_enable_cache(stream, opts);
talloc_free(tmp);
return r;
}
static uint16_t stream_read_word_endian(stream_t *s, bool big_endian)
{
unsigned int y = stream_read_char(s);

View File

@ -223,7 +223,7 @@ void stream_set_capture_file(stream_t *s, const char *filename);
struct mp_cache_opts;
bool stream_wants_cache(stream_t *stream, struct mp_cache_opts *opts);
int stream_enable_cache(stream_t **stream, struct mp_cache_opts *opts);
int stream_enable_cache_defaults(stream_t **stream);
// Internal
int stream_cache_init(stream_t *cache, stream_t *stream,
@ -294,8 +294,7 @@ char *mp_file_get_path(void *talloc_ctx, bstr url);
struct AVDictionary;
void mp_setup_av_network_options(struct AVDictionary **dict,
struct mpv_global *global,
struct mp_log *log,
struct MPOpts *opts);
struct mp_log *log);
void stream_print_proto_list(struct mp_log *log);
char **stream_get_proto_list(void);

View File

@ -19,12 +19,13 @@
#include <libavformat/avio.h>
#include <libavutil/opt.h>
#include "options/options.h"
#include "options/path.h"
#include "common/common.h"
#include "common/msg.h"
#include "common/tags.h"
#include "common/av_common.h"
#include "stream.h"
#include "options/m_config.h"
#include "options/m_option.h"
#include "cookies.h"
@ -35,14 +36,37 @@
#define OPT_BASE_STRUCT struct stream_lavf_params
struct stream_lavf_params {
char **avopts;
int cookies_enabled;
char *cookies_file;
char *useragent;
char *referrer;
char **http_header_fields;
int tls_verify;
char *tls_ca_file;
char *tls_cert_file;
char *tls_key_file;
double timeout;
};
const struct m_sub_options stream_lavf_conf = {
.opts = (const m_option_t[]) {
OPT_KEYVALUELIST("stream-lavf-o", avopts, 0),
OPT_STRINGLIST("http-header-fields", http_header_fields, 0),
OPT_STRING("user-agent", useragent, 0),
OPT_STRING("referrer", referrer, 0),
OPT_FLAG("cookies", cookies_enabled, 0),
OPT_STRING("cookies-file", cookies_file, M_OPT_FILE),
OPT_FLAG("tls-verify", tls_verify, 0),
OPT_STRING("tls-ca-file", tls_ca_file, M_OPT_FILE),
OPT_STRING("tls-cert-file", tls_cert_file, M_OPT_FILE),
OPT_STRING("tls-key-file", tls_key_file, M_OPT_FILE),
OPT_DOUBLE("network-timeout", timeout, M_OPT_MIN, .min = 0),
{0}
},
.size = sizeof(struct stream_lavf_params),
.defaults = &(const struct stream_lavf_params){
.useragent = (char *)mpv_version,
},
};
static const char *const http_like[];
@ -150,50 +174,52 @@ static int interrupt_cb(void *ctx)
static const char * const prefix[] = { "lavf://", "ffmpeg://" };
void mp_setup_av_network_options(AVDictionary **dict, struct mpv_global *global,
struct mp_log *log, struct MPOpts *opts)
struct mp_log *log)
{
void *temp = talloc_new(NULL);
struct stream_lavf_params *opts =
mp_get_config_group(temp, global, &stream_lavf_conf);
// HTTP specific options (other protocols ignore them)
if (opts->network_useragent)
av_dict_set(dict, "user-agent", opts->network_useragent, 0);
if (opts->network_cookies_enabled) {
char *file = opts->network_cookies_file;
if (opts->useragent)
av_dict_set(dict, "user-agent", opts->useragent, 0);
if (opts->cookies_enabled) {
char *file = opts->cookies_file;
if (file && file[0])
file = mp_get_user_path(temp, global, file);
char *cookies = cookies_lavf(temp, log, file);
if (cookies && cookies[0])
av_dict_set(dict, "cookies", cookies, 0);
}
av_dict_set(dict, "tls_verify", opts->network_tls_verify ? "1" : "0", 0);
if (opts->network_tls_ca_file)
av_dict_set(dict, "ca_file", opts->network_tls_ca_file, 0);
if (opts->network_tls_cert_file)
av_dict_set(dict, "cert_file", opts->network_tls_cert_file, 0);
if (opts->network_tls_key_file)
av_dict_set(dict, "key_file", opts->network_tls_key_file, 0);
av_dict_set(dict, "tls_verify", opts->tls_verify ? "1" : "0", 0);
if (opts->tls_ca_file)
av_dict_set(dict, "ca_file", opts->tls_ca_file, 0);
if (opts->tls_cert_file)
av_dict_set(dict, "cert_file", opts->tls_cert_file, 0);
if (opts->tls_key_file)
av_dict_set(dict, "key_file", opts->tls_key_file, 0);
char *cust_headers = talloc_strdup(temp, "");
if (opts->network_referrer) {
if (opts->referrer) {
cust_headers = talloc_asprintf_append(cust_headers, "Referer: %s\r\n",
opts->network_referrer);
opts->referrer);
}
if (opts->network_http_header_fields) {
for (int n = 0; opts->network_http_header_fields[n]; n++) {
if (opts->http_header_fields) {
for (int n = 0; opts->http_header_fields[n]; n++) {
cust_headers = talloc_asprintf_append(cust_headers, "%s\r\n",
opts->network_http_header_fields[n]);
opts->http_header_fields[n]);
}
}
if (strlen(cust_headers))
av_dict_set(dict, "headers", cust_headers, 0);
av_dict_set(dict, "icy", "1", 0);
// So far, every known protocol uses microseconds for this
if (opts->network_timeout > 0) {
if (opts->timeout > 0) {
char buf[80];
snprintf(buf, sizeof(buf), "%lld", (long long)(opts->network_timeout * 1e6));
snprintf(buf, sizeof(buf), "%lld", (long long)(opts->timeout * 1e6));
av_dict_set(dict, "timeout", buf, 0);
}
mp_set_avdict(dict, opts->stream_lavf_opts->avopts);
mp_set_avdict(dict, opts->avopts);
talloc_free(temp);
}
@ -215,7 +241,6 @@ static char *normalize_url(void *ta_parent, const char *filename)
static int open_f(stream_t *stream)
{
struct MPOpts *opts = stream->opts;
AVIOContext *avio = NULL;
int res = STREAM_ERROR;
AVDictionary *dict = NULL;
@ -255,7 +280,7 @@ static int open_f(stream_t *stream)
filename = talloc_asprintf(temp, "mmsh://%.*s", BSTR_P(b_filename));
}
mp_setup_av_network_options(&dict, stream->global, stream->log, opts);
mp_setup_av_network_options(&dict, stream->global, stream->log);
AVIOInterruptCB cb = {
.callback = interrupt_cb,