[FFmpeg-cvslog] avfilter/f_loop: add time option, for loop start in seconds

Paul B Mahol git at videolan.org
Sun May 14 22:00:57 EEST 2023


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sun May 14 12:15:20 2023 +0200| [7a63add0eaf0f890b4af990114710c6fabcfb4d7] | committer: Paul B Mahol

avfilter/f_loop: add time option, for loop start in seconds

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=7a63add0eaf0f890b4af990114710c6fabcfb4d7
---

 doc/filters.texi     |  8 +++++
 libavfilter/f_loop.c | 89 +++++++++++++++++++++++++++++-----------------------
 2 files changed, 57 insertions(+), 40 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 9ada73bab0..28acbe3509 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2363,6 +2363,10 @@ Set maximal number of samples. Default is 0.
 
 @item start
 Set first sample of loop. Default is 0.
+
+ at item time
+Set the time of loop start in seconds.
+Only used if option named @var{start} is set to @code{-1}.
 @end table
 
 @anchor{amerge}
@@ -16759,6 +16763,10 @@ Set maximal size in number of frames. Default is 0.
 
 @item start
 Set first frame of loop. Default is 0.
+
+ at item time
+Set the time of loop start in seconds.
+Only used if option named @var{start} is set to @code{-1}.
 @end table
 
 @subsection Examples
diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c
index d217efe2fd..5a91a0cbe9 100644
--- a/libavfilter/f_loop.c
+++ b/libavfilter/f_loop.c
@@ -39,7 +39,7 @@ typedef struct LoopContext {
     AVFrame **frames;
     int nb_frames;
     int current_frame;
-    int64_t start_pts;
+    int64_t time_pts;
     int64_t duration;
     int64_t current_sample;
     int64_t nb_samples;
@@ -49,7 +49,10 @@ typedef struct LoopContext {
     int eof;
     int64_t size;
     int64_t start;
+    int64_t time;
     int64_t pts;
+    int64_t pts_offset;
+    int64_t eof_pts;
 } LoopContext;
 
 #define AFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
@@ -65,6 +68,17 @@ static void check_size(AVFilterContext *ctx)
                ctx->input_pads[0].type == AVMEDIA_TYPE_VIDEO ? "frames" : "samples");
 }
 
+static void update_time(AVFilterContext *ctx, AVRational tb)
+{
+    LoopContext *s = ctx->priv;
+
+    if (s->time != INT64_MAX) {
+        int64_t time_pts = av_rescale_q(s->time, AV_TIME_BASE_Q, tb);
+        if (s->time_pts == AV_NOPTS_VALUE || time_pts < s->time_pts)
+            s->time_pts = time_pts;
+    }
+}
+
 #if CONFIG_ALOOP_FILTER
 
 static int aconfig_input(AVFilterLink *inlink)
@@ -72,6 +86,8 @@ static int aconfig_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     LoopContext *s  = ctx->priv;
 
+    s->time_pts = AV_NOPTS_VALUE;
+
     s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, 8192);
     s->left = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, 8192);
     if (!s->fifo || !s->left)
@@ -117,7 +133,6 @@ static int push_samples(AVFilterContext *ctx, int nb_samples)
             return ret;
 
         if (s->current_sample >= s->nb_samples) {
-            s->duration = s->pts;
             s->current_sample = 0;
 
             if (s->loop > 0)
@@ -135,11 +150,17 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame)
     LoopContext *s = ctx->priv;
     int ret = 0;
 
-    if (s->ignored_samples + frame->nb_samples > s->start && s->size > 0 && s->loop != 0) {
+    if (((s->start >= 0 && s->ignored_samples + frame->nb_samples > s->start) ||
+         (s->time_pts != AV_NOPTS_VALUE &&
+          frame->pts >= s->time_pts)) &&
+        s->size > 0 && s->loop != 0) {
         if (s->nb_samples < s->size) {
             int written = FFMIN(frame->nb_samples, s->size - s->nb_samples);
             int drain = 0;
 
+            if (s->start < 0)
+                s->start = inlink->sample_count_out - written;
+
             ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, written);
             if (ret < 0)
                 return ret;
@@ -221,10 +242,11 @@ static int aactivate(AVFilterContext *ctx)
     LoopContext *s = ctx->priv;
     AVFrame *frame = NULL;
     int ret, status;
-    int64_t pts;
 
     FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
 
+    update_time(ctx, inlink->time_base);
+
     if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) {
         ret = ff_inlink_consume_frame(inlink, &frame);
         if (ret < 0)
@@ -233,7 +255,7 @@ static int aactivate(AVFilterContext *ctx)
             return afilter_frame(inlink, frame);
     }
 
-    if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
+    if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts)) {
         if (status == AVERROR_EOF) {
             s->size = s->nb_samples;
             s->eof = 1;
@@ -241,7 +263,7 @@ static int aactivate(AVFilterContext *ctx)
     }
 
     if (s->eof && (!s->loop || !s->size)) {
-        ff_outlink_set_status(outlink, AVERROR_EOF, s->duration);
+        ff_outlink_set_status(outlink, AVERROR_EOF, s->eof_pts + s->pts_offset);
         return 0;
     }
 
@@ -259,7 +281,8 @@ static int aactivate(AVFilterContext *ctx)
 static const AVOption aloop_options[] = {
     { "loop",  "number of loops",               OFFSET(loop),  AV_OPT_TYPE_INT,   {.i64 = 0 }, -1, INT_MAX,   AFLAGS },
     { "size",  "max number of samples to loop", OFFSET(size),  AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT32_MAX, AFLAGS },
-    { "start", "set the loop start sample",     OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT64_MAX, AFLAGS },
+    { "start", "set the loop start sample",     OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, -1, INT64_MAX, AFLAGS },
+    { "time",  "set the loop start time",       OFFSET(time),  AV_OPT_TYPE_DURATION, {.i64=INT64_MAX}, INT64_MIN, INT64_MAX, AFLAGS },
     { NULL }
 };
 
@@ -298,6 +321,8 @@ static av_cold int init(AVFilterContext *ctx)
 {
     LoopContext *s = ctx->priv;
 
+    s->time_pts = AV_NOPTS_VALUE;
+
     s->frames = av_calloc(s->size, sizeof(*s->frames));
     if (!s->frames)
         return AVERROR(ENOMEM);
@@ -323,33 +348,20 @@ static int push_frame(AVFilterContext *ctx)
 {
     AVFilterLink *outlink = ctx->outputs[0];
     LoopContext *s = ctx->priv;
-    int64_t pts, duration;
+    AVFrame *out;
     int ret;
 
-    AVFrame *out = av_frame_clone(s->frames[s->current_frame]);
-
+    out = av_frame_clone(s->frames[s->current_frame]);
     if (!out)
         return AVERROR(ENOMEM);
-    out->pts += s->duration - s->start_pts;
-#if FF_API_PKT_DURATION
-FF_DISABLE_DEPRECATION_WARNINGS
-    if (out->pkt_duration)
-        duration = out->pkt_duration;
-    else
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-    if (out->duration)
-        duration = out->duration;
-    else
-        duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
-    pts = out->pts + duration;
+    out->pts += s->pts_offset;
     ret = ff_filter_frame(outlink, out);
     s->current_frame++;
 
     if (s->current_frame >= s->nb_frames) {
-        s->duration = pts;
         s->current_frame = 0;
 
+        s->pts_offset += s->duration;
         if (s->loop > 0)
             s->loop--;
     }
@@ -365,35 +377,30 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     int64_t duration;
     int ret = 0;
 
-    if (inlink->frame_count_out >= s->start && s->size > 0 && s->loop != 0) {
+    if (((s->start >= 0 && inlink->frame_count_out >= s->start) ||
+         (s->time_pts != AV_NOPTS_VALUE &&
+          frame->pts >= s->time_pts)) &&
+        s->size > 0 && s->loop != 0) {
         if (s->nb_frames < s->size) {
-            if (!s->nb_frames)
-                s->start_pts = frame->pts;
             s->frames[s->nb_frames] = av_frame_clone(frame);
             if (!s->frames[s->nb_frames]) {
                 av_frame_free(&frame);
                 return AVERROR(ENOMEM);
             }
             s->nb_frames++;
-#if FF_API_PKT_DURATION
-FF_DISABLE_DEPRECATION_WARNINGS
-            if (frame->pkt_duration)
-                duration = frame->pkt_duration;
-            else
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
             if (frame->duration)
                 duration = frame->duration;
             else
                 duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
-            s->duration = frame->pts + duration;
+            s->duration += duration;
+            s->pts_offset = s->duration;
             ret = ff_filter_frame(outlink, frame);
         } else {
             av_frame_free(&frame);
             ret = push_frame(ctx);
         }
     } else {
-        frame->pts += s->duration;
+        frame->pts += s->pts_offset - s->duration;
         ret = ff_filter_frame(outlink, frame);
     }
 
@@ -407,10 +414,11 @@ static int activate(AVFilterContext *ctx)
     LoopContext *s = ctx->priv;
     AVFrame *frame = NULL;
     int ret, status;
-    int64_t pts;
 
     FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
 
+    update_time(ctx, inlink->time_base);
+
     if (!s->eof && (s->nb_frames < s->size || !s->loop || !s->size)) {
         ret = ff_inlink_consume_frame(inlink, &frame);
         if (ret < 0)
@@ -419,7 +427,7 @@ static int activate(AVFilterContext *ctx)
             return filter_frame(inlink, frame);
     }
 
-    if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
+    if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts)) {
         if (status == AVERROR_EOF) {
             s->size = s->nb_frames;
             s->eof = 1;
@@ -427,7 +435,7 @@ static int activate(AVFilterContext *ctx)
     }
 
     if (s->eof && (!s->loop || !s->size)) {
-        ff_outlink_set_status(outlink, AVERROR_EOF, s->duration);
+        ff_outlink_set_status(outlink, AVERROR_EOF, s->eof_pts + s->pts_offset);
         return 0;
     }
 
@@ -445,7 +453,8 @@ static int activate(AVFilterContext *ctx)
 static const AVOption loop_options[] = {
     { "loop",  "number of loops",              OFFSET(loop),  AV_OPT_TYPE_INT,   {.i64 = 0 }, -1, INT_MAX,   VFLAGS },
     { "size",  "max number of frames to loop", OFFSET(size),  AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT16_MAX, VFLAGS },
-    { "start", "set the loop start frame",     OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT64_MAX, VFLAGS },
+    { "start", "set the loop start frame",     OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, -1, INT64_MAX, VFLAGS },
+    { "time",  "set the loop start time",      OFFSET(time),  AV_OPT_TYPE_DURATION, {.i64=INT64_MAX}, INT64_MIN, INT64_MAX, VFLAGS },
     { NULL }
 };
 



More information about the ffmpeg-cvslog mailing list