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.

Signed-off-by: Marton Balint <c...@passwd.hu>
---
 libavfilter/f_loop.c | 70 ++++++++++++++++++--------------------------
 1 file changed, 28 insertions(+), 42 deletions(-)

diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c
index 3372c77fee..4e5e8d0e79 100644
--- a/libavfilter/f_loop.c
+++ b/libavfilter/f_loop.c
@@ -21,6 +21,7 @@
 #include "config_components.h"
 
 #include "libavutil/audio_fifo.h"
+#include "libavutil/avassert.h"
 #include "libavutil/internal.h"
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
@@ -104,7 +105,7 @@ static av_cold void auninit(AVFilterContext *ctx)
     av_audio_fifo_free(s->left);
 }
 
-static int push_samples(AVFilterContext *ctx, int nb_samples)
+static int push_samples(AVFilterContext *ctx, int nb_samples, AVFrame **frame)
 {
     AVFilterLink *outlink = ctx->outputs[0];
     LoopContext *s = ctx->priv;
@@ -126,9 +127,7 @@ static int push_samples(AVFilterContext *ctx, int 
nb_samples)
         i += out->nb_samples;
         s->current_sample += out->nb_samples;
 
-        ret = ff_filter_frame(outlink, out);
-        if (ret < 0)
-            return ret;
+        *frame = out;
 
         if (s->current_sample >= s->nb_samples) {
             s->current_sample = 0;
@@ -136,6 +135,8 @@ static int push_samples(AVFilterContext *ctx, int 
nb_samples)
             if (s->loop > 0)
                 s->loop--;
         }
+
+        return 0;
     }
 
     return ret;
@@ -182,10 +183,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame 
*frame)
             s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, 
outlink->time_base);
             ret = ff_filter_frame(outlink, frame);
         } else {
-            int nb_samples = frame->nb_samples;
-
-            av_frame_free(&frame);
-            ret = push_samples(ctx, nb_samples);
+            av_assert0(0);
         }
     } else {
         s->ignored_samples += frame->nb_samples;
@@ -197,7 +195,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame 
*frame)
     return ret;
 }
 
-static int arequest_frame(AVFilterLink *outlink)
+static int arequest_frame(AVFilterLink *outlink, AVFrame **frame)
 {
     AVFilterContext *ctx = outlink->src;
     LoopContext *s = ctx->priv;
@@ -217,17 +215,11 @@ static int arequest_frame(AVFilterLink *outlink)
             av_audio_fifo_read(s->left, (void **)out->extended_data, 
nb_samples);
             out->pts = s->pts;
             s->pts += av_rescale_q(nb_samples, (AVRational){1, 
outlink->sample_rate}, outlink->time_base);
-            ret = ff_filter_frame(outlink, out);
-            if (ret < 0)
-                return ret;
+            *frame = out;
         }
-        ret = ff_request_frame(ctx->inputs[0]);
+        return 0;
     } else {
-        ret = push_samples(ctx, 1024);
-    }
-
-    if (s->eof && s->nb_samples > 0 && s->loop != 0) {
-        ret = push_samples(ctx, 1024);
+        ret = push_samples(ctx, 1024, frame);
     }
 
     return ret;
@@ -245,37 +237,31 @@ static int aactivate(AVFilterContext *ctx)
 
     update_time(ctx, inlink->time_base);
 
-    if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) {
-        const int in_nb_samples = FFMIN(1024, s->size - s->nb_samples);
-        if (in_nb_samples == 0)
-            ret = ff_inlink_consume_frame(inlink, &frame);
-        else
-            ret = ff_inlink_consume_samples(inlink, in_nb_samples, 
in_nb_samples, &frame);
-        if (ret < 0)
-            return ret;
-        if (ret > 0)
-            return afilter_frame(inlink, frame);
-    }
+retry:
+    ret = arequest_frame(outlink, &frame);
+    if (ret < 0)
+        return ret;
+    if (frame)
+        return ff_filter_frame(outlink, frame);
 
-    if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts)) 
{
-        if (status == AVERROR_EOF) {
+    ret = ff_inlink_consume_frame(inlink, &frame);
+    if (ret < 0)
+        return ret;
+    if (ret > 0)
+        return afilter_frame(inlink, frame);
+
+    ret = ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts);
+    if (ret) {
+        if (status == AVERROR_EOF && !s->eof) {
             s->size = s->nb_samples;
             s->eof = 1;
+            goto retry;
         }
-    }
-
-    if (s->eof && (!s->loop || !s->size)) {
-        ff_outlink_set_status(outlink, AVERROR_EOF, s->eof_pts + 
s->pts_offset);
+        ff_outlink_set_status(outlink, status, s->eof_pts);
         return 0;
     }
 
-    if (!s->eof && (!s->size ||
-        (s->nb_samples < s->size) ||
-        (s->nb_samples >= s->size && s->loop == 0))) {
-        FF_FILTER_FORWARD_WANTED(outlink, inlink);
-    } else if (s->loop && s->nb_samples == s->size) {
-        return arequest_frame(outlink);
-    }
+    FF_FILTER_FORWARD_WANTED(outlink, inlink);
 
     return FFERROR_NOT_READY;
 }
-- 
2.43.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to