summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-08-12 23:08:48 +0200
committerwm4 <wm4@nowhere>2017-08-12 23:10:40 +0200
commitf1d161d55f458cf47e63d1ab9ddf08859019dd8a (patch)
treeccd0fad41aefdf59b9ec00652edc829c3f81a424 /player
parentbaead23ea06307af0d0a7acd21307d8f723b3a1b (diff)
downloadmpv-f1d161d55f458cf47e63d1ab9ddf08859019dd8a.tar.bz2
mpv-f1d161d55f458cf47e63d1ab9ddf08859019dd8a.tar.xz
player: make --lavfi-complex changeable at runtime
Tends to be somewhat glitchy if subtitles are enabled, and you enable and disable tracks. On error, this will disable --lavfi-complex, which will result in whatever behavior.
Diffstat (limited to 'player')
-rw-r--r--player/audio.c34
-rw-r--r--player/command.c3
-rw-r--r--player/core.h9
-rw-r--r--player/lavfi.c13
-rw-r--r--player/lavfi.h4
-rw-r--r--player/loadfile.c177
-rw-r--r--player/playloop.c4
-rw-r--r--player/video.c35
8 files changed, 182 insertions, 97 deletions
diff --git a/player/audio.c b/player/audio.c
index 7891116c7e..7fef377dac 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -557,25 +557,19 @@ init_error:
void reinit_audio_chain(struct MPContext *mpctx)
{
- reinit_audio_chain_src(mpctx, NULL);
+ struct track *track = NULL;
+ track = mpctx->current_track[0][STREAM_AUDIO];
+ if (!track || !track->stream) {
+ uninit_audio_out(mpctx);
+ error_on_track(mpctx, track);
+ return;
+ }
+ reinit_audio_chain_src(mpctx, track);
}
-void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
+// (track=NULL creates a blank chain, used for lavfi-complex)
+void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track)
{
- struct track *track = NULL;
- struct sh_stream *sh = NULL;
- if (!src) {
- track = mpctx->current_track[0][STREAM_AUDIO];
- if (!track) {
- uninit_audio_out(mpctx);
- return;
- }
- sh = track->stream;
- if (!sh) {
- uninit_audio_out(mpctx);
- goto no_audio;
- }
- }
assert(!mpctx->ao_chain);
mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL);
@@ -584,15 +578,14 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
mpctx->ao_chain = ao_c;
ao_c->log = mpctx->log;
ao_c->af = af_new(mpctx->global);
- if (sh)
- ao_c->af->replaygain_data = sh->codec->replaygain_data;
+ if (track && track->stream)
+ ao_c->af->replaygain_data = track->stream->codec->replaygain_data;
ao_c->spdif_passthrough = true;
ao_c->pts = MP_NOPTS_VALUE;
ao_c->ao_buffer = mp_audio_buffer_create(NULL);
ao_c->ao = mpctx->ao;
- ao_c->filter_src = src;
- if (!ao_c->filter_src) {
+ if (track) {
ao_c->track = track;
track->ao_c = ao_c;
if (!init_audio_decoder(mpctx, track))
@@ -614,7 +607,6 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
init_error:
uninit_audio_chain(mpctx);
uninit_audio_out(mpctx);
-no_audio:
error_on_track(mpctx, track);
}
diff --git a/player/command.c b/player/command.c
index c282c5349f..b023e350c9 100644
--- a/player/command.c
+++ b/player/command.c
@@ -5901,6 +5901,9 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, int flags)
if (flags & UPDATE_VOL)
audio_update_volume(mpctx);
+
+ if (flags & UPDATE_LAVFI_COMPLEX)
+ update_lavfi_complex(mpctx);
}
void mp_notify_property(struct MPContext *mpctx, const char *property)
diff --git a/player/core.h b/player/core.h
index fbc4b1ec7a..d341aeb529 100644
--- a/player/core.h
+++ b/player/core.h
@@ -367,6 +367,8 @@ typedef struct MPContext {
double last_frame_duration;
// Video PTS, or audio PTS if video has ended.
double playback_pts;
+ // Last known "good" PTS
+ double canonical_pts;
// audio stats only
int64_t audio_stat_start;
double written_audio;
@@ -478,7 +480,7 @@ void update_playback_speed(struct MPContext *mpctx);
void uninit_audio_out(struct MPContext *mpctx);
void uninit_audio_chain(struct MPContext *mpctx);
int init_audio_decoder(struct MPContext *mpctx, struct track *track);
-void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src);
+void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track);
void audio_update_volume(struct MPContext *mpctx);
void audio_update_balance(struct MPContext *mpctx);
void reload_audio_output(struct MPContext *mpctx);
@@ -522,6 +524,7 @@ void prefetch_next(struct MPContext *mpctx);
void close_recorder(struct MPContext *mpctx);
void close_recorder_and_error(struct MPContext *mpctx);
void open_recorder(struct MPContext *mpctx, bool on_init);
+void update_lavfi_complex(struct MPContext *mpctx);
// main.c
int mp_initialize(struct MPContext *mpctx, char **argv);
@@ -611,8 +614,8 @@ int video_set_colors(struct vo_chain *vo_c, const char *item, int value);
int video_vf_vo_control(struct vo_chain *vo_c, int vf_cmd, void *data);
void reset_video_state(struct MPContext *mpctx);
int init_video_decoder(struct MPContext *mpctx, struct track *track);
-int reinit_video_chain(struct MPContext *mpctx);
-int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src);
+void reinit_video_chain(struct MPContext *mpctx);
+void reinit_video_chain_src(struct MPContext *mpctx, struct track *track);
int reinit_video_filters(struct MPContext *mpctx);
void write_video(struct MPContext *mpctx);
void mp_force_video_refresh(struct MPContext *mpctx);
diff --git a/player/lavfi.c b/player/lavfi.c
index c597387937..ee0ca281e4 100644
--- a/player/lavfi.c
+++ b/player/lavfi.c
@@ -249,12 +249,19 @@ struct lavfi *lavfi_create(struct mp_log *log, char *graph_string)
void lavfi_destroy(struct lavfi *c)
{
+ if (!c)
+ return;
free_graph(c);
clear_data(c);
av_frame_free(&c->tmp_frame);
talloc_free(c);
}
+const char *lavfi_get_graph(struct lavfi *c)
+{
+ return c->graph_string;
+}
+
struct lavfi_pad *lavfi_find_pad(struct lavfi *c, char *name)
{
for (int n = 0; n < c->num_pads; n++) {
@@ -484,9 +491,11 @@ static void dump_graph(struct lavfi *c)
#endif
}
-void lavfi_set_hwdec_devs(struct lavfi *c, struct mp_hwdec_devices *hwdevs)
+void lavfi_pad_set_hwdec_devs(struct lavfi_pad *pad,
+ struct mp_hwdec_devices *hwdevs)
{
- c->hwdec_devs = hwdevs;
+ // We don't actually treat this per-pad.
+ pad->main->hwdec_devs = hwdevs;
}
// Initialize the graph if all inputs have formats set. If it's already
diff --git a/player/lavfi.h b/player/lavfi.h
index 0f2ae7705f..ef19a14179 100644
--- a/player/lavfi.h
+++ b/player/lavfi.h
@@ -13,6 +13,7 @@ enum lavfi_direction {
};
struct lavfi *lavfi_create(struct mp_log *log, char *graph_string);
+const char *lavfi_get_graph(struct lavfi *c);
void lavfi_destroy(struct lavfi *c);
struct lavfi_pad *lavfi_find_pad(struct lavfi *c, char *name);
enum lavfi_direction lavfi_pad_direction(struct lavfi_pad *pad);
@@ -22,7 +23,8 @@ bool lavfi_get_connected(struct lavfi_pad *pad);
bool lavfi_process(struct lavfi *c);
bool lavfi_has_failed(struct lavfi *c);
void lavfi_seek_reset(struct lavfi *c);
-void lavfi_set_hwdec_devs(struct lavfi *c, struct mp_hwdec_devices *hwdevs);
+void lavfi_pad_set_hwdec_devs(struct lavfi_pad *pad,
+ struct mp_hwdec_devices *hwdevs);
int lavfi_request_frame_a(struct lavfi_pad *pad, struct mp_audio **out_aframe);
int lavfi_request_frame_v(struct lavfi_pad *pad, struct mp_image **out_vframe);
bool lavfi_needs_input(struct lavfi_pad *pad);
diff --git a/player/loadfile.c b/player/loadfile.c
index a2ef851617..f0bb582b4f 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -945,21 +945,83 @@ void prefetch_next(struct MPContext *mpctx)
}
}
-static bool init_complex_filters(struct MPContext *mpctx)
+// Destroy the complex filter, and remove the references to the filter pads.
+// (Call cleanup_deassociated_complex_filters() to close decoders/VO/AO
+// that are not connected anymore due to this.)
+static void deassociate_complex_filters(struct MPContext *mpctx)
{
- assert(!mpctx->lavfi);
+ for (int n = 0; n < mpctx->num_tracks; n++)
+ mpctx->tracks[n]->sink = NULL;
+ if (mpctx->vo_chain)
+ mpctx->vo_chain->filter_src = NULL;
+ if (mpctx->ao_chain)
+ mpctx->ao_chain->filter_src = NULL;
+ lavfi_destroy(mpctx->lavfi);
+ mpctx->lavfi = NULL;
+}
- char *graph = mpctx->opts->lavfi_complex;
+// Close all decoders and sinks (AO/VO) that are not connected to either
+// a track or a filter pad.
+static void cleanup_deassociated_complex_filters(struct MPContext *mpctx)
+{
+ for (int n = 0; n < mpctx->num_tracks; n++) {
+ struct track *track = mpctx->tracks[n];
+ if (!(track->sink || track->vo_c || track->ao_c)) {
+ if (track->d_video && !track->vo_c) {
+ video_uninit(track->d_video);
+ track->d_video = NULL;
+ }
+ if (track->d_audio && !track->ao_c) {
+ audio_uninit(track->d_audio);
+ track->d_audio = NULL;
+ }
+ track->selected = false;
+ }
+ }
- if (!graph || !graph[0])
- return true;
+ if (mpctx->vo_chain && !mpctx->vo_chain->video_src &&
+ !mpctx->vo_chain->filter_src)
+ {
+ uninit_video_chain(mpctx);
+ }
+ if (mpctx->ao_chain && !mpctx->ao_chain->audio_src &&
+ !mpctx->ao_chain->filter_src)
+ {
+ uninit_audio_chain(mpctx);
+ }
+}
+
+// >0: changed, 0: no change, -1: error
+static int reinit_complex_filters(struct MPContext *mpctx, bool force_uninit)
+{
+ char *graph = mpctx->opts->lavfi_complex;
+ bool have_graph = graph && graph[0] && !force_uninit;
+ if (have_graph && mpctx->lavfi &&
+ strcmp(graph, lavfi_get_graph(mpctx->lavfi)) == 0 &&
+ !lavfi_has_failed(mpctx->lavfi))
+ return 0;
+ if (!mpctx->lavfi && !have_graph)
+ return 0;
+
+ // Deassociate the old filter pads. We leave both sources (tracks) and
+ // sinks (AO/VO) "dangling", connected to neither track or filter pad.
+ // Later, we either reassociate them with new pads, or uninit them if
+ // they are still dangling. This avoids too interruptive actions like
+ // recreating the VO.
+ deassociate_complex_filters(mpctx);
+
+ bool success = false;
+ if (!have_graph) {
+ success = true; // normal full removal of graph
+ goto done;
+ }
mpctx->lavfi = lavfi_create(mpctx->log, graph);
if (!mpctx->lavfi)
- return false;
+ goto done;
if (lavfi_has_failed(mpctx->lavfi))
- return false;
+ goto done;
for (int n = 0; n < mpctx->num_tracks; n++) {
struct track *track = mpctx->tracks[n];
@@ -983,6 +1045,12 @@ static bool init_complex_filters(struct MPContext *mpctx)
if (lavfi_get_connected(pad))
continue;
+ assert(!track->sink);
+ if (track->vo_c || track->ao_c) {
+ MP_ERR(mpctx, "Pad %s tries to connect to already selected track.\n",
+ label);
+ goto done;
+ }
track->sink = pad;
lavfi_set_connected(pad, true);
track->selected = true;
@@ -992,66 +1060,81 @@ static bool init_complex_filters(struct MPContext *mpctx)
if (pad && lavfi_pad_type(pad) == STREAM_VIDEO &&
lavfi_pad_direction(pad) == LAVFI_OUT)
{
+ if (mpctx->vo_chain) {
+ if (mpctx->vo_chain->video_src) {
+ MP_ERR(mpctx, "Pad vo tries to connected to already used VO.\n");
+ goto done;
+ }
+ } else {
+ reinit_video_chain_src(mpctx, NULL);
+ if (!mpctx->vo_chain)
+ goto done;
+ }
lavfi_set_connected(pad, true);
- reinit_video_chain_src(mpctx, pad);
+ struct vo_chain *vo_c = mpctx->vo_chain;
+ vo_c->filter_src = pad;
+ lavfi_pad_set_hwdec_devs(vo_c->filter_src, vo_c->hwdec_devs);
}
pad = lavfi_find_pad(mpctx->lavfi, "ao");
if (pad && lavfi_pad_type(pad) == STREAM_AUDIO &&
lavfi_pad_direction(pad) == LAVFI_OUT)
{
+ if (mpctx->ao_chain) {
+ if (mpctx->ao_chain->audio_src) {
+ MP_ERR(mpctx, "Pad ao tries to connected to already used AO.\n");
+ goto done;
+ }
+ } else {
+ reinit_audio_chain_src(mpctx, NULL);
+ if (!mpctx->ao_chain)
+ goto done;
+ }
lavfi_set_connected(pad, true);
- reinit_audio_chain_src(mpctx, pad);
+ mpctx->ao_chain->filter_src = pad;
}
- return true;
-}
-
-static bool init_complex_filter_decoders(struct MPContext *mpctx)
-{
- if (!mpctx->lavfi)
- return true;
-
for (int n = 0; n < mpctx->num_tracks; n++) {
struct track *track = mpctx->tracks[n];
if (track->sink && track->type == STREAM_VIDEO) {
- if (!init_video_decoder(mpctx, track))
- return false;
+ if (!track->d_video && !init_video_decoder(mpctx, track))
+ goto done;
}
if (track->sink && track->type == STREAM_AUDIO) {
- if (!init_audio_decoder(mpctx, track))
- return false;
+ if (!track->d_audio && !init_audio_decoder(mpctx, track))
+ goto done;
}
}
- return true;
-}
+ success = true;
+done:
-static void uninit_complex_filters(struct MPContext *mpctx)
-{
- if (!mpctx->lavfi)
- return;
+ if (!success)
+ deassociate_complex_filters(mpctx);
- for (int n = 0; n < mpctx->num_tracks; n++) {
- struct track *track = mpctx->tracks[n];
+ cleanup_deassociated_complex_filters(mpctx);
- if (track->d_video && !track->vo_c) {
- video_uninit(track->d_video);
- track->d_video = NULL;
- }
- if (track->d_audio && !track->ao_c) {
- audio_uninit(track->d_audio);
- track->d_audio = NULL;
- }
+ if (mpctx->playback_initialized) {
+ for (int n = 0; n < mpctx->num_tracks; n++)
+ reselect_demux_stream(mpctx, mpctx->tracks[n]);
}
- if (mpctx->vo_chain && mpctx->vo_chain->filter_src)
- uninit_video_chain(mpctx);
- if (mpctx->ao_chain && mpctx->ao_chain->filter_src)
- uninit_audio_chain(mpctx);
+ mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL);
- lavfi_destroy(mpctx->lavfi);
- mpctx->lavfi = NULL;
+ return success ? 1 : -1;
+}
+
+void update_lavfi_complex(struct MPContext *mpctx)
+{
+ if (mpctx->playback_initialized) {
+ if (reinit_complex_filters(mpctx, false) != 0 &&
+ mpctx->canonical_pts != MP_NOPTS_VALUE)
+ {
+ // Refresh seek to avoid weird situations.
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->canonical_pts,
+ MPSEEK_EXACT, 0);
+ }
+ }
}
// Start playing the current playlist entry.
@@ -1083,6 +1166,7 @@ static void play_current_file(struct MPContext *mpctx)
mpctx->speed_factor_a = mpctx->speed_factor_v = 1.0;
mpctx->display_sync_error = 0.0;
mpctx->display_sync_active = false;
+ mpctx->canonical_pts = MP_NOPTS_VALUE;
mpctx->seek = (struct seek_params){ 0 };
reset_playback_state(mpctx);
@@ -1176,7 +1260,7 @@ reopen_file:
if (process_preloaded_hooks(mpctx))
goto terminate_playback;
- if (!init_complex_filters(mpctx))
+ if (reinit_complex_filters(mpctx, false) < 0)
goto terminate_playback;
assert(NUM_PTRACKS == 2); // opts->stream_id is hardcoded to 2
@@ -1223,9 +1307,6 @@ reopen_file:
update_playback_speed(mpctx);
- if (!init_complex_filter_decoders(mpctx))
- goto terminate_playback;
-
reinit_video_chain(mpctx);
reinit_audio_chain(mpctx);
reinit_sub_all(mpctx);
@@ -1307,7 +1388,7 @@ terminate_playback:
close_recorder(mpctx);
// time to uninit all, except global stuff:
- uninit_complex_filters(mpctx);
+ reinit_complex_filters(mpctx, true);
uninit_audio_chain(mpctx);
uninit_video_chain(mpctx);
uninit_sub_all(mpctx);
diff --git a/player/playloop.c b/player/playloop.c
index 736a8f5951..0d3409065b 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -376,6 +376,8 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
!hr_seek && !(demux_flags & SEEK_FORWARD);
mpctx->ab_loop_clip = mpctx->last_seek_pts < opts->ab_loop[1];
+
+ mpctx->canonical_pts = mpctx->last_seek_pts;
}
// This combines consecutive seek requests.
@@ -956,6 +958,8 @@ static void handle_playback_time(struct MPContext *mpctx)
{
mpctx->playback_pts = playing_audio_pts(mpctx);
}
+ if (mpctx->playback_pts != MP_NOPTS_VALUE)
+ mpctx->canonical_pts = mpctx->playback_pts;
}
// We always make sure audio and video buffers are filled before actually
diff --git a/player/video.c b/player/video.c
index 414629c3c2..5d5f7f1fac 100644
--- a/player/video.c
+++ b/player/video.c
@@ -456,23 +456,20 @@ err_out:
return 0;
}
-int reinit_video_chain(struct MPContext *mpctx)
+void reinit_video_chain(struct MPContext *mpctx)
{
- return reinit_video_chain_src(mpctx, NULL);
+ struct track *track = mpctx->current_track[0][STREAM_VIDEO];
+ if (!track || !track->stream) {
+ error_on_track(mpctx, track);
+ handle_force_window(mpctx, true);
+ return;
+ }
+ reinit_video_chain_src(mpctx, track);
}
-int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
+// (track=NULL creates a blank chain, used for lavfi-complex)
+void reinit_video_chain_src(struct MPContext *mpctx, struct track *track)
{
- struct track *track = NULL;
- struct sh_stream *sh = NULL;
- if (!src) {
- track = mpctx->current_track[0][STREAM_VIDEO];
- if (!track)
- return 0;
- sh = track->stream;
- if (!sh)
- goto no_video;
- }
assert(!mpctx->vo_chain);
if (!mpctx->video_out) {
@@ -504,11 +501,7 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
vo_c->hwdec_devs = vo_c->vo->hwdec_devs;
- if (mpctx->lavfi)
- lavfi_set_hwdec_devs(mpctx->lavfi, vo_c->hwdec_devs);
-
- vo_c->filter_src = src;
- if (!vo_c->filter_src) {
+ if (track) {
vo_c->track = track;
track->vo_c = vo_c;
if (!init_video_decoder(mpctx, track))
@@ -516,7 +509,7 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
vo_c->video_src = track->d_video;
vo_c->container_fps = vo_c->video_src->fps;
- vo_c->is_coverart = !!sh->attached_picture;
+ vo_c->is_coverart = !!track->stream->attached_picture;
track->vo_c = vo_c;
vo_c->track = track;
@@ -540,14 +533,12 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
reset_video_state(mpctx);
reset_subtitle_state(mpctx);
- return 1;
+ return;
err_out:
-no_video:
uninit_video_chain(mpctx);
error_on_track(mpctx, track);
handle_force_window(mpctx, true);
- return 0;
}
// Try to refresh the video by doing a precise seek to the currently displayed