summaryrefslogtreecommitdiffstats
path: root/player/audio.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-02-05 23:19:56 +0100
committerwm4 <wm4@nowhere>2016-02-05 23:19:56 +0100
commitc0de087ba191a4daf3a152e0ab09b5687fab8449 (patch)
treeb00043c5e4055ef777a0afdba6b4a321e87864de /player/audio.c
parent45345d9c41f1491e9809153dc3b3950fba560d89 (diff)
downloadmpv-c0de087ba191a4daf3a152e0ab09b5687fab8449.tar.bz2
mpv-c0de087ba191a4daf3a152e0ab09b5687fab8449.tar.xz
player: add complex filter graph support
See --lavfi-complex option. This is still quite rough. There's no support for dynamic configuration of any kind. There are probably corner cases where playback might freeze or burn 100% CPU (due to dataflow problems when interaction with libavfilter). Future possible plans might include: - freely switch tracks by providing some sort of default track graph label - automatically enabling audio visualization - automatically mix audio or stack video when multiple tracks are selected at once (similar to how multiple sub tracks can be selected)
Diffstat (limited to 'player/audio.c')
-rw-r--r--player/audio.c76
1 files changed, 54 insertions, 22 deletions
diff --git a/player/audio.c b/player/audio.c
index 5ecbab5ad1..18f2818fe5 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -49,6 +49,7 @@ enum {
AD_EOF = -2,
AD_NEW_FMT = -3,
AD_WAIT = -4,
+ AD_NO_PROGRESS = -5,
};
// Use pitch correction only for speed adjustments by the user, not minor sync
@@ -204,6 +205,18 @@ void uninit_audio_out(struct MPContext *mpctx)
static void ao_chain_uninit(struct ao_chain *ao_c)
{
+ struct track *track = ao_c->track;
+ if (track) {
+ assert(track->ao_c == ao_c);
+ track->ao_c = NULL;
+ assert(track->d_audio == ao_c->audio_src);
+ track->d_audio = NULL;
+ audio_uninit(ao_c->audio_src);
+ }
+
+ if (ao_c->filter_src)
+ lavfi_set_connected(ao_c->filter_src, false);
+
af_destroy(ao_c->af);
talloc_free(ao_c->input_frame);
talloc_free(ao_c->ao_buffer);
@@ -213,18 +226,10 @@ static void ao_chain_uninit(struct ao_chain *ao_c)
void uninit_audio_chain(struct MPContext *mpctx)
{
if (mpctx->ao_chain) {
- struct track *track = mpctx->current_track[0][STREAM_AUDIO];
- assert(track);
- assert(track->d_audio == mpctx->ao_chain->audio_src);
-
mixer_uninit_audio(mpctx->mixer);
-
- audio_uninit(track->d_audio);
- track->d_audio = NULL;
- mpctx->ao_chain->audio_src = NULL;
-
ao_chain_uninit(mpctx->ao_chain);
mpctx->ao_chain = NULL;
+
mpctx->audio_status = STATUS_EOF;
reselect_demux_streams(mpctx);
@@ -379,6 +384,9 @@ int init_audio_decoder(struct MPContext *mpctx, struct track *track)
return 1;
init_error:
+ if (track->sink)
+ lavfi_set_connected(track->sink, false);
+ track->sink = NULL;
audio_uninit(track->d_audio);
track->d_audio = NULL;
error_on_track(mpctx, track);
@@ -387,14 +395,24 @@ init_error:
void reinit_audio_chain(struct MPContext *mpctx)
{
- assert(!mpctx->ao_chain);
+ reinit_audio_chain_src(mpctx, NULL);
+}
- struct track *track = mpctx->current_track[0][STREAM_AUDIO];
- struct sh_stream *sh = track ? track->stream : NULL;
- if (!sh) {
- uninit_audio_out(mpctx);
- goto no_audio;
+void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
+{
+ struct track *track = NULL;
+ struct sh_stream *sh = NULL;
+ if (!src) {
+ track = mpctx->current_track[0][STREAM_AUDIO];
+ if (!track)
+ return;
+ sh = track ? track->stream : NULL;
+ if (!sh) {
+ uninit_audio_out(mpctx);
+ goto no_audio;
+ }
}
+ assert(!mpctx->ao_chain);
mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL);
@@ -402,16 +420,21 @@ void reinit_audio_chain(struct MPContext *mpctx)
mpctx->ao_chain = ao_c;
ao_c->log = mpctx->log;
ao_c->af = af_new(mpctx->global);
- ao_c->af->replaygain_data = sh->codec->replaygain_data;
+ if (sh)
+ ao_c->af->replaygain_data = sh->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;
- if (!init_audio_decoder(mpctx, track))
- goto init_error;
-
- ao_c->audio_src = track->d_audio;
+ ao_c->filter_src = src;
+ if (!ao_c->filter_src) {
+ ao_c->track = track;
+ track->ao_c = ao_c;
+ if (!init_audio_decoder(mpctx, track))
+ goto init_error;
+ ao_c->audio_src = track->d_audio;
+ }
reset_audio_state(mpctx);
@@ -597,8 +620,10 @@ static int decode_new_frame(struct ao_chain *ao_c)
if (ao_c->input_frame)
return AD_OK;
- int res = DATA_AGAIN;
- while (res == DATA_AGAIN) {
+ int res = DATA_EOF;
+ if (ao_c->filter_src) {
+ res = lavfi_request_frame_a(ao_c->filter_src, &ao_c->input_frame);
+ } else if (ao_c->audio_src) {
audio_work(ao_c->audio_src);
res = audio_get_frame(ao_c->audio_src, &ao_c->input_frame);
}
@@ -606,6 +631,7 @@ static int decode_new_frame(struct ao_chain *ao_c)
switch (res) {
case DATA_OK: return AD_OK;
case DATA_WAIT: return AD_WAIT;
+ case DATA_AGAIN: return AD_NO_PROGRESS;
case DATA_EOF: return AD_EOF;
default: abort();
}
@@ -633,6 +659,8 @@ static int filter_audio(struct ao_chain *ao_c, struct mp_audio_buffer *outbuf,
break;
res = decode_new_frame(ao_c);
+ if (res == AD_NO_PROGRESS)
+ break;
if (res < 0) {
// drain filters first (especially for true EOF case)
copy_output(afs, outbuf, minsamples, true);
@@ -764,6 +792,10 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
status = filter_audio(mpctx->ao_chain, ao_c->ao_buffer, playsize);
if (status == AD_WAIT)
return;
+ if (status == AD_NO_PROGRESS) {
+ mpctx->sleeptime = 0;
+ return;
+ }
if (status == AD_NEW_FMT) {
/* The format change isn't handled too gracefully. A more precise
* implementation would require draining buffered old-format audio