Skip to content

Commit c0de087

Browse files
author
wm4
committed
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)
1 parent 45345d9 commit c0de087

File tree

11 files changed

+1121
-53
lines changed

11 files changed

+1121
-53
lines changed

DOCS/man/options.rst

+43-1
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ Subtitles
13961396
.. admonition:: Warning
13971397

13981398
Enabling hinting can lead to mispositioned text (in situations it's
1399-
supposed to match up with video background), or reduce the smoothness
1399+
supposed to match up video background), or reduce the smoothness
14001400
of animations with some badly authored ASS scripts. It is recommended
14011401
to not use this option, unless really needed.
14021402

@@ -3553,3 +3553,45 @@ Miscellaneous
35533553
Force the contents of the ``media-title`` property to this value. Useful
35543554
for scripts which want to set a title, without overriding the user's
35553555
setting in ``--title``.
3556+
3557+
``--lavfi-complex=<string>``
3558+
Set a "complex" libavfilter filter, which means a single filter graph can
3559+
take input from multiple source audio and video tracks. The graph can result
3560+
in a single audio or video output (or both).
3561+
3562+
Currently, the filter graph labels are used to select the participating
3563+
input tracks and audio/video output. The following rules apply:
3564+
3565+
- A label of the form ``aidN`` selects audio track N as input (e.g.
3566+
``aid1``).
3567+
- A label of the form ``vidN`` selects video track N as input.
3568+
- A label named ``ao`` will be connected to the audio input.
3569+
- A label named ``vo`` will be connected to the video output.
3570+
3571+
Each label can be used only once. If you want to use e.g. an audio stream
3572+
for multiple filters, you need to use the ``asplit`` filter. Multiple
3573+
video or audio outputs are not possible, but you can use filters to merge
3574+
them into one.
3575+
3576+
The complex filter can not be changed yet during playback. It's also not
3577+
possible to change the tracks connected to the filter at runtime. Other
3578+
tracks, as long as they're not connected to the filter, and the
3579+
corresponding output is not connected to the filter, can still be freely
3580+
changed.
3581+
3582+
.. admonition:: Examples
3583+
3584+
- ``--lavfi-complex='[aid1] asplit [ao] [t] ; [t] aphasemeter [vo]'``
3585+
Play audio track 1, and visualize it as video using the ``aphasemeter``
3586+
filter.
3587+
- ``--lavfi-complex='[vid1] [vid2] vstack [vo]'``
3588+
Stack video track 1 and 2 and play them at the same time. Note that
3589+
both tracks need to have the same width, or filter initialization
3590+
will fail (you can add ``scale`` filters before the ``vstack`` filter
3591+
to fix the size).
3592+
- ``--lavfi-complex='[aid1] asplit [ao] [t] ; [t] aphasemeter [t2] ; [vid1] [t2] overlay [vo]'``
3593+
Play audio track 1, and overlay its visualization over video track 1.
3594+
3595+
See the Ffmpeg libavfilter documentation for details on the filter.
3596+
3597+

options/options.c

+2
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ const m_option_t mp_opts[] = {
226226
OPT_STRINGLIST("alang", stream_lang[STREAM_AUDIO], 0),
227227
OPT_STRINGLIST("slang", stream_lang[STREAM_SUB], 0),
228228

229+
OPT_STRING("lavfi-complex", lavfi_complex, 0),
230+
229231
OPT_CHOICE("audio-display", audio_display, 0,
230232
({"no", 0}, {"attachment", 1})),
231233

options/options.h

+1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ typedef struct MPOpts {
186186
int ignore_path_in_watch_later_config;
187187
int pause;
188188
int keep_open;
189+
char *lavfi_complex;
189190
int stream_id[2][STREAM_TYPE_COUNT];
190191
int stream_id_ff[STREAM_TYPE_COUNT];
191192
char **stream_lang[STREAM_TYPE_COUNT];

player/audio.c

+54-22
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ enum {
4949
AD_EOF = -2,
5050
AD_NEW_FMT = -3,
5151
AD_WAIT = -4,
52+
AD_NO_PROGRESS = -5,
5253
};
5354

5455
// Use pitch correction only for speed adjustments by the user, not minor sync
@@ -204,6 +205,18 @@ void uninit_audio_out(struct MPContext *mpctx)
204205

205206
static void ao_chain_uninit(struct ao_chain *ao_c)
206207
{
208+
struct track *track = ao_c->track;
209+
if (track) {
210+
assert(track->ao_c == ao_c);
211+
track->ao_c = NULL;
212+
assert(track->d_audio == ao_c->audio_src);
213+
track->d_audio = NULL;
214+
audio_uninit(ao_c->audio_src);
215+
}
216+
217+
if (ao_c->filter_src)
218+
lavfi_set_connected(ao_c->filter_src, false);
219+
207220
af_destroy(ao_c->af);
208221
talloc_free(ao_c->input_frame);
209222
talloc_free(ao_c->ao_buffer);
@@ -213,18 +226,10 @@ static void ao_chain_uninit(struct ao_chain *ao_c)
213226
void uninit_audio_chain(struct MPContext *mpctx)
214227
{
215228
if (mpctx->ao_chain) {
216-
struct track *track = mpctx->current_track[0][STREAM_AUDIO];
217-
assert(track);
218-
assert(track->d_audio == mpctx->ao_chain->audio_src);
219-
220229
mixer_uninit_audio(mpctx->mixer);
221-
222-
audio_uninit(track->d_audio);
223-
track->d_audio = NULL;
224-
mpctx->ao_chain->audio_src = NULL;
225-
226230
ao_chain_uninit(mpctx->ao_chain);
227231
mpctx->ao_chain = NULL;
232+
228233
mpctx->audio_status = STATUS_EOF;
229234
reselect_demux_streams(mpctx);
230235

@@ -379,6 +384,9 @@ int init_audio_decoder(struct MPContext *mpctx, struct track *track)
379384
return 1;
380385

381386
init_error:
387+
if (track->sink)
388+
lavfi_set_connected(track->sink, false);
389+
track->sink = NULL;
382390
audio_uninit(track->d_audio);
383391
track->d_audio = NULL;
384392
error_on_track(mpctx, track);
@@ -387,31 +395,46 @@ int init_audio_decoder(struct MPContext *mpctx, struct track *track)
387395

388396
void reinit_audio_chain(struct MPContext *mpctx)
389397
{
390-
assert(!mpctx->ao_chain);
398+
reinit_audio_chain_src(mpctx, NULL);
399+
}
391400

392-
struct track *track = mpctx->current_track[0][STREAM_AUDIO];
393-
struct sh_stream *sh = track ? track->stream : NULL;
394-
if (!sh) {
395-
uninit_audio_out(mpctx);
396-
goto no_audio;
401+
void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
402+
{
403+
struct track *track = NULL;
404+
struct sh_stream *sh = NULL;
405+
if (!src) {
406+
track = mpctx->current_track[0][STREAM_AUDIO];
407+
if (!track)
408+
return;
409+
sh = track ? track->stream : NULL;
410+
if (!sh) {
411+
uninit_audio_out(mpctx);
412+
goto no_audio;
413+
}
397414
}
415+
assert(!mpctx->ao_chain);
398416

399417
mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL);
400418

401419
struct ao_chain *ao_c = ao_c = talloc_zero(NULL, struct ao_chain);
402420
mpctx->ao_chain = ao_c;
403421
ao_c->log = mpctx->log;
404422
ao_c->af = af_new(mpctx->global);
405-
ao_c->af->replaygain_data = sh->codec->replaygain_data;
423+
if (sh)
424+
ao_c->af->replaygain_data = sh->codec->replaygain_data;
406425
ao_c->spdif_passthrough = true;
407426
ao_c->pts = MP_NOPTS_VALUE;
408427
ao_c->ao_buffer = mp_audio_buffer_create(NULL);
409428
ao_c->ao = mpctx->ao;
410429

411-
if (!init_audio_decoder(mpctx, track))
412-
goto init_error;
413-
414-
ao_c->audio_src = track->d_audio;
430+
ao_c->filter_src = src;
431+
if (!ao_c->filter_src) {
432+
ao_c->track = track;
433+
track->ao_c = ao_c;
434+
if (!init_audio_decoder(mpctx, track))
435+
goto init_error;
436+
ao_c->audio_src = track->d_audio;
437+
}
415438

416439
reset_audio_state(mpctx);
417440

@@ -597,15 +620,18 @@ static int decode_new_frame(struct ao_chain *ao_c)
597620
if (ao_c->input_frame)
598621
return AD_OK;
599622

600-
int res = DATA_AGAIN;
601-
while (res == DATA_AGAIN) {
623+
int res = DATA_EOF;
624+
if (ao_c->filter_src) {
625+
res = lavfi_request_frame_a(ao_c->filter_src, &ao_c->input_frame);
626+
} else if (ao_c->audio_src) {
602627
audio_work(ao_c->audio_src);
603628
res = audio_get_frame(ao_c->audio_src, &ao_c->input_frame);
604629
}
605630

606631
switch (res) {
607632
case DATA_OK: return AD_OK;
608633
case DATA_WAIT: return AD_WAIT;
634+
case DATA_AGAIN: return AD_NO_PROGRESS;
609635
case DATA_EOF: return AD_EOF;
610636
default: abort();
611637
}
@@ -633,6 +659,8 @@ static int filter_audio(struct ao_chain *ao_c, struct mp_audio_buffer *outbuf,
633659
break;
634660

635661
res = decode_new_frame(ao_c);
662+
if (res == AD_NO_PROGRESS)
663+
break;
636664
if (res < 0) {
637665
// drain filters first (especially for true EOF case)
638666
copy_output(afs, outbuf, minsamples, true);
@@ -764,6 +792,10 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
764792
status = filter_audio(mpctx->ao_chain, ao_c->ao_buffer, playsize);
765793
if (status == AD_WAIT)
766794
return;
795+
if (status == AD_NO_PROGRESS) {
796+
mpctx->sleeptime = 0;
797+
return;
798+
}
767799
if (status == AD_NEW_FMT) {
768800
/* The format change isn't handled too gracefully. A more precise
769801
* implementation would require draining buffered old-format audio

player/core.h

+17
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "video/mp_image.h"
3232
#include "video/out/vo.h"
3333

34+
#include "lavfi.h"
35+
3436
// definitions used internally by the core player code
3537

3638
enum stop_play_reason {
@@ -149,6 +151,11 @@ struct track {
149151
struct dec_video *d_video;
150152
struct dec_audio *d_audio;
151153

154+
// Where the decoded result goes to (one of them is not NULL if active)
155+
struct vo_chain *vo_c;
156+
struct ao_chain *ao_c;
157+
struct lavfi_pad *sink;
158+
152159
// For external subtitles, which are read fully on init. Do not attempt
153160
// to read packets from them.
154161
bool preloaded;
@@ -170,6 +177,8 @@ struct vo_chain {
170177
// Last known input_mpi format (so vf can be reinitialized any time).
171178
struct mp_image_params input_format;
172179

180+
struct track *track;
181+
struct lavfi_pad *filter_src;
173182
struct dec_video *video_src;
174183

175184
// - video consists of a single picture, which should be shown only once
@@ -195,6 +204,8 @@ struct ao_chain {
195204
// Last known input_mpi format (so vf can be reinitialized any time).
196205
struct mp_audio input_format;
197206

207+
struct track *track;
208+
struct lavfi_pad *filter_src;
198209
struct dec_audio *audio_src;
199210
};
200211

@@ -294,6 +305,8 @@ typedef struct MPContext {
294305
// Currently, this is used for the secondary subtitle track only.
295306
struct track *current_track[NUM_PTRACKS][STREAM_TYPE_COUNT];
296307

308+
struct lavfi *lavfi;
309+
297310
// Uses: accessing metadata (consider ordered chapters case, where the main
298311
// demuxer defines metadata), or special purpose demuxers like TV.
299312
struct demuxer *master_demuxer;
@@ -438,6 +451,8 @@ void clear_audio_output_buffers(struct MPContext *mpctx);
438451
void update_playback_speed(struct MPContext *mpctx);
439452
void uninit_audio_out(struct MPContext *mpctx);
440453
void uninit_audio_chain(struct MPContext *mpctx);
454+
int init_audio_decoder(struct MPContext *mpctx, struct track *track);
455+
void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src);
441456

442457
// configfiles.c
443458
void mp_parse_cfgfiles(struct MPContext *mpctx);
@@ -558,11 +573,13 @@ int video_vf_vo_control(struct vo_chain *vo_c, int vf_cmd, void *data);
558573
void reset_video_state(struct MPContext *mpctx);
559574
int init_video_decoder(struct MPContext *mpctx, struct track *track);
560575
int reinit_video_chain(struct MPContext *mpctx);
576+
int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src);
561577
int reinit_video_filters(struct MPContext *mpctx);
562578
void write_video(struct MPContext *mpctx, double endpts);
563579
void mp_force_video_refresh(struct MPContext *mpctx);
564580
void uninit_video_out(struct MPContext *mpctx);
565581
void uninit_video_chain(struct MPContext *mpctx);
566582
double calc_average_frame_duration(struct MPContext *mpctx);
583+
int init_video_decoder(struct MPContext *mpctx, struct track *track);
567584

568585
#endif /* MPLAYER_MP_CORE_H */

0 commit comments

Comments
 (0)