From a08fb3983f2e2adeff1c948d2e744d606ac4219b Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sat, 24 Oct 2015 15:19:11 +0200 Subject: lavfi/af_amix: mostly fix scheduling. --- libavfilter/af_amix.c | 142 ++++++++++++++++++++++---------------------------- 1 file changed, 62 insertions(+), 80 deletions(-) diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index 434dd907f6..223328bfff 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -44,9 +44,8 @@ #include "formats.h" #include "internal.h" -#define INPUT_OFF 0 /**< input has reached EOF */ #define INPUT_ON 1 /**< input is active */ -#define INPUT_INACTIVE 2 /**< input is on, but is currently inactive */ +#define INPUT_EOF 2 /**< input has reached EOF (may still be active) */ #define DURATION_LONGEST 0 #define DURATION_SHORTEST 1 @@ -209,7 +208,7 @@ static void calculate_scales(MixContext *s, int nb_samples) } for (i = 0; i < s->nb_inputs; i++) { - if (s->input_state[i] == INPUT_ON) + if (s->input_state[i] & INPUT_ON) s->input_scale[i] = 1.0f / s->scale_norm; else s->input_scale[i] = 0.0f; @@ -264,15 +263,52 @@ static int config_output(AVFilterLink *outlink) return 0; } +static int calc_active_inputs(MixContext *s); + /** * Read samples from the input FIFOs, mix, and write to the output link. */ -static int output_frame(AVFilterLink *outlink, int nb_samples) +static int output_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; MixContext *s = ctx->priv; AVFrame *out_buf, *in_buf; - int i; + int nb_samples, ns, ret, i; + + ret = calc_active_inputs(s); + if (ret < 0) + return ret; + + if (s->input_state[0] & INPUT_ON) { + /* first input live: use the corresponding frame size */ + nb_samples = frame_list_next_frame_size(s->frame_list); + for (i = 1; i < s->nb_inputs; i++) { + if (s->input_state[i] & INPUT_ON) { + ns = av_audio_fifo_size(s->fifos[i]); + if (ns < nb_samples) { + if (!(s->input_state[i] & INPUT_EOF)) + /* unclosed input with not enough samples */ + return 0; + /* closed input to drain */ + nb_samples = ns; + } + } + } + } else { + /* first input closed: use the available samples */ + nb_samples = INT_MAX; + for (i = 1; i < s->nb_inputs; i++) { + if (s->input_state[i] & INPUT_ON) { + ns = av_audio_fifo_size(s->fifos[i]); + nb_samples = FFMIN(nb_samples, ns); + } + } + if (nb_samples == INT_MAX) + return AVERROR_EOF; + } + + s->next_pts = frame_list_next_pts(s->frame_list); + frame_list_remove_samples(s->frame_list, nb_samples); calculate_scales(s, nb_samples); @@ -287,7 +323,7 @@ static int output_frame(AVFilterLink *outlink, int nb_samples) } for (i = 0; i < s->nb_inputs; i++) { - if (s->input_state[i] == INPUT_ON) { + if (s->input_state[i] & INPUT_ON) { int planes, plane_size, p; av_audio_fifo_read(s->fifos[i], (void **)in_buf->extended_data, @@ -313,29 +349,6 @@ static int output_frame(AVFilterLink *outlink, int nb_samples) return ff_filter_frame(outlink, out_buf); } -/** - * Returns the smallest number of samples available in the input FIFOs other - * than that of the first input. - */ -static int get_available_samples(MixContext *s) -{ - int i; - int available_samples = INT_MAX; - - av_assert0(s->nb_inputs > 1); - - for (i = 1; i < s->nb_inputs; i++) { - int nb_samples; - if (s->input_state[i] == INPUT_OFF) - continue; - nb_samples = av_audio_fifo_size(s->fifos[i]); - available_samples = FFMIN(available_samples, nb_samples); - } - if (available_samples == INT_MAX) - return 0; - return available_samples; -} - /** * Requests a frame, if needed, from each input link other than the first. */ @@ -348,19 +361,21 @@ static int request_samples(AVFilterContext *ctx, int min_samples) for (i = 1; i < s->nb_inputs; i++) { ret = 0; - if (s->input_state[i] == INPUT_OFF) + if (!(s->input_state[i] & INPUT_ON)) continue; - while (!ret && av_audio_fifo_size(s->fifos[i]) < min_samples) - ret = ff_request_frame(ctx->inputs[i]); + if (av_audio_fifo_size(s->fifos[i]) >= min_samples) + continue; + ret = ff_request_frame(ctx->inputs[i]); if (ret == AVERROR_EOF) { + s->input_state[i] |= INPUT_EOF; if (av_audio_fifo_size(s->fifos[i]) == 0) { - s->input_state[i] = INPUT_OFF; + s->input_state[i] = 0; continue; } } else if (ret < 0) return ret; } - return 0; + return output_frame(ctx->outputs[0]); } /** @@ -374,11 +389,11 @@ static int calc_active_inputs(MixContext *s) int i; int active_inputs = 0; for (i = 0; i < s->nb_inputs; i++) - active_inputs += !!(s->input_state[i] != INPUT_OFF); + active_inputs += !!(s->input_state[i] & INPUT_ON); s->active_inputs = active_inputs; if (!active_inputs || - (s->duration_mode == DURATION_FIRST && s->input_state[0] == INPUT_OFF) || + (s->duration_mode == DURATION_FIRST && !(s->input_state[0] & INPUT_ON)) || (s->duration_mode == DURATION_SHORTEST && active_inputs != s->nb_inputs)) return AVERROR_EOF; return 0; @@ -389,66 +404,30 @@ static int request_frame(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; MixContext *s = ctx->priv; int ret; - int wanted_samples, available_samples; + int wanted_samples; ret = calc_active_inputs(s); if (ret < 0) return ret; - if (s->input_state[0] == INPUT_OFF) { - ret = request_samples(ctx, 1); - if (ret < 0) - return ret; - - ret = calc_active_inputs(s); - if (ret < 0) - return ret; - - available_samples = get_available_samples(s); - if (!available_samples) - return AVERROR(EAGAIN); - - return output_frame(outlink, available_samples); - } + if (!(s->input_state[0] & INPUT_ON)) + return request_samples(ctx, 1); if (s->frame_list->nb_frames == 0) { ret = ff_request_frame(ctx->inputs[0]); if (ret == AVERROR_EOF) { - s->input_state[0] = INPUT_OFF; + s->input_state[0] = 0; if (s->nb_inputs == 1) return AVERROR_EOF; - else - return AVERROR(EAGAIN); - } else if (ret < 0) - return ret; + return output_frame(ctx->outputs[0]); + } + return ret; } av_assert0(s->frame_list->nb_frames > 0); wanted_samples = frame_list_next_frame_size(s->frame_list); - if (s->active_inputs > 1) { - ret = request_samples(ctx, wanted_samples); - if (ret < 0) - return ret; - - ret = calc_active_inputs(s); - if (ret < 0) - return ret; - } - - if (s->active_inputs > 1) { - available_samples = get_available_samples(s); - if (!available_samples) - return AVERROR(EAGAIN); - available_samples = FFMIN(available_samples, wanted_samples); - } else { - available_samples = wanted_samples; - } - - s->next_pts = frame_list_next_pts(s->frame_list); - frame_list_remove_samples(s->frame_list, available_samples); - - return output_frame(outlink, available_samples); + return request_samples(ctx, wanted_samples); } static int filter_frame(AVFilterLink *inlink, AVFrame *buf) @@ -478,6 +457,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data, buf->nb_samples); + av_frame_free(&buf); + return output_frame(outlink); + fail: av_frame_free(&buf); -- cgit v1.2.3