summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-06-30 20:09:27 +0200
committerwm4 <wm4@nowhere>2019-09-19 20:37:05 +0200
commitb945952e0da1b476ce347932a151d9c01a15e742 (patch)
treed2403ffff2fbd52f38a028669a9649e2d4ce7a83 /demux
parentc942178c92321a99ddf079e55af85724fc74ee16 (diff)
downloadmpv-b945952e0da1b476ce347932a151d9c01a15e742.tar.bz2
mpv-b945952e0da1b476ce347932a151d9c01a15e742.tar.xz
demux: runtime option changing for cache and stream recording
Make most of the demuxer options runtime-changeable. This includes the cache options and stream recording. The manpage documents some of the possibly weird issues related to this. In particular, the disk cache isn't shuffled around if the setting changes at runtime.
Diffstat (limited to 'demux')
-rw-r--r--demux/demux.c125
1 files changed, 92 insertions, 33 deletions
diff --git a/demux/demux.c b/demux/demux.c
index f646158e22..d3bea4b841 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -149,8 +149,10 @@ const struct m_sub_options demux_conf = {
struct demux_internal {
struct mp_log *log;
+ struct mpv_global *global;
- struct demux_opts *opts;
+ bool can_cache; // not a slave demuxer; caching makes sense
+ bool can_record; // stream recording is allowed
// The demuxer runs potentially in another thread, so we keep two demuxer
// structs; the real demuxer can access the shadow struct only.
@@ -165,6 +167,9 @@ struct demux_internal {
// -- All the following fields are protected by lock.
+ struct demux_opts *opts;
+ struct m_config_cache *opts_cache;
+
bool thread_terminate;
bool threading;
bool shutdown_async;
@@ -190,6 +195,8 @@ struct demux_internal {
size_t max_bytes;
size_t max_bytes_bw;
bool seekable_cache;
+ bool using_network_cache_opts;
+ char *record_filename;
// At least one decoder actually requested data since init or the last seek.
// Do this to allow the decoder thread to select streams before starting.
@@ -1962,7 +1969,7 @@ static void add_packet_locked(struct sh_stream *stream, demux_packet_t *dp)
record_packet(in, dp);
- if (in->cache) {
+ if (in->cache && in->opts->disk_cache) {
int64_t pos = demux_cache_write(in->cache, dp);
if (pos >= 0) {
demux_packet_unref_contents(dp);
@@ -2327,9 +2334,73 @@ static void execute_seek(struct demux_internal *in)
in->seeking_in_progress = MP_NOPTS_VALUE;
}
+static void update_opts(struct demux_internal *in)
+{
+ struct demux_opts *opts = in->opts;
+
+ in->min_secs = opts->min_secs;
+ in->max_bytes = opts->max_bytes;
+ in->max_bytes_bw = opts->max_bytes_bw;
+
+ int seekable = opts->seekable_cache;
+ bool is_streaming = in->d_thread->is_network ||
+ (in->d_thread->stream && in->d_thread->stream->streaming);
+ bool use_cache = is_streaming;
+ if (opts->enable_cache >= 0)
+ use_cache = opts->enable_cache == 1;
+
+ if (use_cache) {
+ in->min_secs = MPMAX(in->min_secs, opts->min_secs_cache);
+ if (seekable < 0)
+ seekable = 1;
+ }
+ in->seekable_cache = seekable == 1;
+ in->using_network_cache_opts = is_streaming && use_cache;
+
+ if (!in->can_cache) {
+ in->seekable_cache = false;
+ in->min_secs = 0;
+ in->max_bytes = 1;
+ in->max_bytes_bw = 0;
+ in->using_network_cache_opts = false;
+ }
+
+ if (in->seekable_cache && opts->disk_cache && !in->cache) {
+ in->cache = demux_cache_create(in->global, in->log);
+ if (!in->cache)
+ MP_ERR(in, "Failed to create file cache.\n");
+ }
+
+ // The filename option really decides whether recording should be active.
+ // So if the filename changes, act upon it.
+ char *old = in->record_filename ? in->record_filename : "";
+ char *new = opts->record_file ? opts->record_file : "";
+ if (strcmp(old, new) != 0) {
+ if (in->recorder) {
+ MP_WARN(in, "Stopping recording.\n");
+ mp_recorder_destroy(in->recorder);
+ in->recorder = NULL;
+ }
+ in->record_filename = talloc_strdup(in, opts->record_file);
+ talloc_free(in->record_filename);
+ // Note: actual recording only starts once packets are read. It may be
+ // important to delay creating in->recorder to that point, because the
+ // demuxer might detect more streams until finding the first packet.
+ in->enable_recording = in->can_record;
+ }
+
+ // In case the cache was reduced in size.
+ prune_old_packets(in);
+
+ // In case the seekable cache was disabled.
+ free_empty_cached_ranges(in);
+}
+
// Make demuxing progress. Return whether progress was made.
static bool thread_work(struct demux_internal *in)
{
+ if (m_config_cache_update(in->opts_cache))
+ update_opts(in);
if (in->tracks_switched) {
execute_trackswitch(in);
return true;
@@ -2994,11 +3065,10 @@ static void demux_init_ccs(struct demuxer *demuxer, struct demux_opts *opts)
bool demux_is_network_cached(demuxer_t *demuxer)
{
struct demux_internal *in = demuxer->in;
- bool use_cache = demuxer->is_network ||
- (demuxer->stream && demuxer->stream->streaming);
- if (in->opts->enable_cache >= 0)
- use_cache = in->opts->enable_cache == 1;
- return use_cache;
+ pthread_mutex_lock(&in->lock);
+ bool r = in->using_network_cache_opts;
+ pthread_mutex_unlock(&in->lock);
+ return r;
}
struct parent_stream_info {
@@ -3020,7 +3090,9 @@ 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);
+ struct m_config_cache *opts_cache =
+ m_config_cache_alloc(demuxer, global, &demux_conf);
+ struct demux_opts *opts = opts_cache->opts;
*demuxer = (struct demuxer) {
.desc = desc,
.stream = stream,
@@ -3039,19 +3111,19 @@ static struct demuxer *open_given_type(struct mpv_global *global,
struct demux_internal *in = demuxer->in = talloc_ptrtype(demuxer, in);
*in = (struct demux_internal){
+ .global = global,
.log = demuxer->log,
+ .can_cache = params && params->is_top_level,
+ .can_record = params && params->stream_record,
.opts = opts,
+ .opts_cache = opts_cache,
.d_thread = talloc(demuxer, struct demuxer),
.d_user = demuxer,
- .min_secs = opts->min_secs,
- .max_bytes = opts->max_bytes,
- .max_bytes_bw = opts->max_bytes_bw,
.after_seek = true, // (assumed identical to initial demuxer state)
.after_seek_to_start = true,
.highest_av_pts = MP_NOPTS_VALUE,
.seeking_in_progress = MP_NOPTS_VALUE,
.demux_ts = MP_NOPTS_VALUE,
- .enable_recording = params && params->stream_record,
};
pthread_mutex_init(&in->lock, NULL);
pthread_cond_init(&in->wakeup, NULL);
@@ -3085,13 +3157,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
in->duration = in->d_thread->duration;
demuxer_sort_chapters(demuxer);
in->events = DEMUX_EVENT_ALL;
- int seekable = opts->seekable_cache;
- if (demux_is_network_cached(demuxer)) {
- in->min_secs = MPMAX(in->min_secs, opts->min_secs_cache);
- if (seekable < 0)
- seekable = 1;
- }
- in->seekable_cache = seekable == 1;
+
struct demuxer *sub = NULL;
if (!(params && params->disable_timeline)) {
struct timeline *tl = timeline_load(global, log, demuxer);
@@ -3103,26 +3169,19 @@ static struct demuxer *open_given_type(struct mpv_global *global,
sub =
open_given_type(global, log, &demuxer_desc_timeline,
NULL, sinfo, &params2, DEMUX_CHECK_FORCE);
- if (!sub)
+ if (sub) {
+ in->can_cache = false;
+ in->can_record = false;
+ } else {
timeline_destroy(tl);
+ }
}
}
- if (!(params && params->is_top_level) || sub) {
- in->seekable_cache = false;
- in->min_secs = 0;
- in->max_bytes = 1;
- in->enable_recording = false;
- }
-
- if (in->seekable_cache && opts->disk_cache) {
- in->cache = demux_cache_create(global, log);
- if (!in->cache)
- MP_ERR(in, "Failed to create file cache.\n");
- }
-
switch_to_fresh_cache_range(in);
+ update_opts(in);
+
demux_update(demuxer, MP_NOPTS_VALUE);
demuxer = sub ? sub : demuxer;