The logic did not follow the documented behaviour and that caused skipping of some audio in the loop and in the leftover buffer. Example command line which should produce a smooth sine wave for the whole duration of the output: ffmpeg -f lavfi -i "sine=r=48000:f=480:d=4" -af "aloop=loop=4:start=48000:size=48000" out.wav Fixes ticket #11283.
Unified · Split
| @@ -21,6 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include "config_components.h" |
| 22 | 22 | |
| 23 | 23 | #include "libavutil/audio_fifo.h" |
| 24 | +#include "libavutil/avassert.h" | |
| 24 | 25 | #include "libavutil/internal.h" |
| 25 | 26 | #include "libavutil/mem.h" |
| 26 | 27 | #include "libavutil/opt.h" |
| @@ -104,7 +105,7 @@ static av_cold void auninit(AVFilterContext *ctx) · 77 unmodified lines | ||
| 104 | 105 | av_audio_fifo_free(s->left); |
| 105 | 106 | } |
| 106 | 107 | |
| 107 | −static int push_samples(AVFilterContext *ctx, int nb_samples) | |
| 108 | +static int push_samples(AVFilterContext *ctx, int nb_samples, AVFrame **frame) | |
| 108 | 109 | { |
| 109 | 110 | AVFilterLink *outlink = ctx->outputs[0]; |
| 110 | 111 | LoopContext *s = ctx->priv; |
| @@ -126,9 +127,7 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) · 15 unmodified lines | ||
| 126 | 127 | i += out->nb_samples; |
| 127 | 128 | s->current_sample += out->nb_samples; |
| 128 | 129 | |
| 129 | − ret = ff_filter_frame(outlink, out); | |
| 130 | − if (ret < 0) | |
| 131 | − return ret; | |
| 130 | + *frame = out; | |
| 132 | 131 | |
| 133 | 132 | if (s->current_sample >= s->nb_samples) { |
| 134 | 133 | s->current_sample = 0; |
| @@ -136,6 +135,8 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) · 1 unmodified line | ||
| 136 | 135 | if (s->loop > 0) |
| 137 | 136 | s->loop--; |
| 138 | 137 | } |
| 138 | + | |
| 139 | + return 0; | |
| 139 | 140 | } |
| 140 | 141 | |
| 141 | 142 | return ret; |
| @@ -182,10 +183,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) · 40 unmodified lines | ||
| 182 | 183 | s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, outlink->time_base); |
| 183 | 184 | ret = ff_filter_frame(outlink, frame); |
| 184 | 185 | } else { |
| 185 | − int nb_samples = frame->nb_samples; | |
| 186 | − | |
| 187 | − av_frame_free(&frame); | |
| 188 | − ret = push_samples(ctx, nb_samples); | |
| 186 | + av_assert0(0); | |
| 189 | 187 | } |
| 190 | 188 | } else { |
| 191 | 189 | s->ignored_samples += frame->nb_samples; |
| @@ -197,7 +195,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) · 5 unmodified lines | ||
| 197 | 195 | return ret; |
| 198 | 196 | } |
| 199 | 197 | |
| 200 | −static int arequest_frame(AVFilterLink *outlink) | |
| 198 | +static int arequest_frame(AVFilterLink *outlink, AVFrame **frame) | |
| 201 | 199 | { |
| 202 | 200 | AVFilterContext *ctx = outlink->src; |
| 203 | 201 | LoopContext *s = ctx->priv; |
| @@ -217,17 +215,11 @@ static int arequest_frame(AVFilterLink *outlink) · 13 unmodified lines | ||
| 217 | 215 | av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples); |
| 218 | 216 | out->pts = s->pts; |
| 219 | 217 | s->pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); |
| 220 | − ret = ff_filter_frame(outlink, out); | |
| 221 | − if (ret < 0) | |
| 222 | − return ret; | |
| 218 | + *frame = out; | |
| 223 | 219 | } |
| 224 | − ret = ff_request_frame(ctx->inputs[0]); | |
| 220 | + return 0; | |
| 225 | 221 | } else { |
| 226 | − ret = push_samples(ctx, 1024); | |
| 227 | − } | |
| 228 | − | |
| 229 | − if (s->eof && s->nb_samples > 0 && s->loop != 0) { | |
| 230 | − ret = push_samples(ctx, 1024); | |
| 222 | + ret = push_samples(ctx, 1024, frame); | |
| 231 | 223 | } |
| 232 | 224 | |
| 233 | 225 | return ret; |
| @@ -245,37 +237,31 @@ static int aactivate(AVFilterContext *ctx) · 11 unmodified lines | ||
| 245 | 237 | |
| 246 | 238 | update_time(ctx, inlink->time_base); |
| 247 | 239 | |
| 248 | − if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) { | |
| 249 | − const int in_nb_samples = FFMIN(1024, s->size - s->nb_samples); | |
| 250 | − if (in_nb_samples == 0) | |
| 251 | − ret = ff_inlink_consume_frame(inlink, &frame); | |
| 252 | − else | |
| 253 | − ret = ff_inlink_consume_samples(inlink, in_nb_samples, in_nb_samples, &frame); | |
| 254 | − if (ret < 0) | |
| 255 | − return ret; | |
| 256 | − if (ret > 0) | |
| 257 | − return afilter_frame(inlink, frame); | |
| 258 | − } | |
| 240 | +retry: | |
| 241 | + ret = arequest_frame(outlink, &frame); | |
| 242 | + if (ret < 0) | |
| 243 | + return ret; | |
| 244 | + if (frame) | |
| 245 | + return ff_filter_frame(outlink, frame); | |
| 259 | 246 | |
| 260 | − if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts)) { | |
| 261 | − if (status == AVERROR_EOF) { | |
| 247 | + ret = ff_inlink_consume_frame(inlink, &frame); | |
| 248 | + if (ret < 0) | |
| 249 | + return ret; | |
| 250 | + if (ret > 0) | |
| 251 | + return afilter_frame(inlink, frame); | |
| 252 | + | |
| 253 | + ret = ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts); | |
| 254 | + if (ret) { | |
| 255 | + if (status == AVERROR_EOF && !s->eof) { | |
| 262 | 256 | s->size = s->nb_samples; |
| 263 | 257 | s->eof = 1; |
| 258 | + goto retry; | |
| 264 | 259 | } |
| 265 | − } | |
| 266 | − | |
| 267 | − if (s->eof && (!s->loop || !s->size)) { | |
| 268 | − ff_outlink_set_status(outlink, AVERROR_EOF, s->eof_pts + s->pts_offset); | |
| 260 | + ff_outlink_set_status(outlink, status, s->eof_pts); | |
| 269 | 261 | return 0; |
| 270 | 262 | } |
| 271 | 263 | |
| 272 | − if (!s->eof && (!s->size || | |
| 273 | − (s->nb_samples < s->size) || | |
| 274 | − (s->nb_samples >= s->size && s->loop == 0))) { | |
| 275 | − FF_FILTER_FORWARD_WANTED(outlink, inlink); | |
| 276 | − } else if (s->loop && s->nb_samples == s->size) { | |
| 277 | − return arequest_frame(outlink); | |
| 278 | − } | |
| 264 | + FF_FILTER_FORWARD_WANTED(outlink, inlink); | |
| 279 | 265 | |
| 280 | 266 | return FFERROR_NOT_READY; |
| 281 | 267 | } |