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 | #include "config_components.h" | 21 | #include "config_components.h" |
| 22 | 22 | ||
| 23 | #include "libavutil/audio_fifo.h" | 23 | #include "libavutil/audio_fifo.h" |
| 24 | #include "libavutil/avassert.h" | ||
| 24 | #include "libavutil/internal.h" | 25 | #include "libavutil/internal.h" |
| 25 | #include "libavutil/mem.h" | 26 | #include "libavutil/mem.h" |
| 26 | #include "libavutil/opt.h" | 27 | #include "libavutil/opt.h" |
| @@ -104,7 +105,7 @@ static av_cold void auninit(AVFilterContext *ctx) · 77 unmodified lines | |||
| 104 | av_audio_fifo_free(s->left); | 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 | AVFilterLink *outlink = ctx->outputs[0]; | 110 | AVFilterLink *outlink = ctx->outputs[0]; |
| 110 | LoopContext *s = ctx->priv; | 111 | LoopContext *s = ctx->priv; |
| @@ -126,9 +127,7 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) · 15 unmodified lines | |||
| 126 | i += out->nb_samples; | 127 | i += out->nb_samples; |
| 127 | s->current_sample += out->nb_samples; | 128 | s->current_sample += out->nb_samples; |
| 128 | 129 | ||
| 129 | ret = ff_filter_frame(outlink, out); | 130 | *frame = out; |
| 130 | if (ret < 0) | ||
| 131 | return ret; | ||
| 132 | 131 | ||
| 133 | if (s->current_sample >= s->nb_samples) { | 132 | if (s->current_sample >= s->nb_samples) { |
| 134 | s->current_sample = 0; | 133 | s->current_sample = 0; |
| @@ -136,6 +135,8 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) · 1 unmodified line | |||
| 136 | if (s->loop > 0) | 135 | if (s->loop > 0) |
| 137 | s->loop--; | 136 | s->loop--; |
| 138 | } | 137 | } |
| 138 | |||
| 139 | return 0; | ||
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | return ret; | 142 | return ret; |
| @@ -182,10 +183,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) · 40 unmodified lines | |||
| 182 | s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, outlink->time_base); | 183 | s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, outlink->time_base); |
| 183 | ret = ff_filter_frame(outlink, frame); | 184 | ret = ff_filter_frame(outlink, frame); |
| 184 | } else { | 185 | } else { |
| 185 | int nb_samples = frame->nb_samples; | 186 | av_assert0(0); |
| 186 | |||
| 187 | av_frame_free(&frame); | ||
| 188 | ret = push_samples(ctx, nb_samples); | ||
| 189 | } | 187 | } |
| 190 | } else { | 188 | } else { |
| 191 | s->ignored_samples += frame->nb_samples; | 189 | s->ignored_samples += frame->nb_samples; |
| @@ -197,7 +195,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) · 5 unmodified lines | |||
| 197 | return ret; | 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 | AVFilterContext *ctx = outlink->src; | 200 | AVFilterContext *ctx = outlink->src; |
| 203 | LoopContext *s = ctx->priv; | 201 | LoopContext *s = ctx->priv; |
| @@ -217,17 +215,11 @@ static int arequest_frame(AVFilterLink *outlink) · 13 unmodified lines | |||
| 217 | av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples); | 215 | av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples); |
| 218 | out->pts = s->pts; | 216 | out->pts = s->pts; |
| 219 | s->pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); | 217 | s->pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); |
| 220 | ret = ff_filter_frame(outlink, out); | 218 | *frame = out; |
| 221 | if (ret < 0) | ||
| 222 | return ret; | ||
| 223 | } | 219 | } |
| 224 | ret = ff_request_frame(ctx->inputs[0]); | 220 | return 0; |
| 225 | } else { | 221 | } else { |
| 226 | ret = push_samples(ctx, 1024); | 222 | ret = push_samples(ctx, 1024, frame); |
| 227 | } | ||
| 228 | |||
| 229 | if (s->eof && s->nb_samples > 0 && s->loop != 0) { | ||
| 230 | ret = push_samples(ctx, 1024); | ||
| 231 | } | 223 | } |
| 232 | 224 | ||
| 233 | return ret; | 225 | return ret; |
| @@ -245,37 +237,31 @@ static int aactivate(AVFilterContext *ctx) · 11 unmodified lines | |||
| 245 | 237 | ||
| 246 | update_time(ctx, inlink->time_base); | 238 | update_time(ctx, inlink->time_base); |
| 247 | 239 | ||
| 248 | if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) { | 240 | retry: |
| 249 | const int in_nb_samples = FFMIN(1024, s->size - s->nb_samples); | 241 | ret = arequest_frame(outlink, &frame); |
| 250 | if (in_nb_samples == 0) | 242 | if (ret < 0) |
| 251 | ret = ff_inlink_consume_frame(inlink, &frame); | 243 | return ret; |
| 252 | else | 244 | if (frame) |
| 253 | ret = ff_inlink_consume_samples(inlink, in_nb_samples, in_nb_samples, &frame); | 245 | return ff_filter_frame(outlink, frame); |
| 254 | if (ret < 0) | ||
| 255 | return ret; | ||
| 256 | if (ret > 0) | ||
| 257 | return afilter_frame(inlink, frame); | ||
| 258 | } | ||
| 259 | 246 | ||
| 260 | if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts)) { | 247 | ret = ff_inlink_consume_frame(inlink, &frame); |
| 261 | if (status == AVERROR_EOF) { | 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 | s->size = s->nb_samples; | 256 | s->size = s->nb_samples; |
| 263 | s->eof = 1; | 257 | s->eof = 1; |
| 258 | goto retry; | ||
| 264 | } | 259 | } |
| 265 | } | 260 | ff_outlink_set_status(outlink, status, s->eof_pts); |
| 266 | |||
| 267 | if (s->eof && (!s->loop || !s->size)) { | ||
| 268 | ff_outlink_set_status(outlink, AVERROR_EOF, s->eof_pts + s->pts_offset); | ||
| 269 | return 0; | 261 | return 0; |
| 270 | } | 262 | } |
| 271 | 263 | ||
| 272 | if (!s->eof && (!s->size || | 264 | FF_FILTER_FORWARD_WANTED(outlink, inlink); |
| 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 | } | ||
| 279 | 265 | ||
| 280 | return FFERROR_NOT_READY; | 266 | return FFERROR_NOT_READY; |
| 281 | } | 267 | } |