diff mbox series

[FFmpeg-devel] lavfi/libplacebo: properly handle EOF

Message ID 20230521111352.102281-1-ffmpeg@haasn.xyz
State Accepted
Commit c00fd025587fc8f028cda2c36f0061070fe91a35
Headers show
Series [FFmpeg-devel] lavfi/libplacebo: properly handle EOF | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Niklas Haas May 21, 2023, 11:13 a.m. UTC
From: Niklas Haas <git@haasn.dev>

The current code relied on pl_queue eventually returning EOF back to the
caller, which didn't work in all situations (e.g. single frame input).
Also, the current code assumed that ff_inlink_acknowledge_status only
fired once, which was patently not true, as the above edge cases
demonstrated.

Solve both issues by keeping track of the acknowledged link status and
forwarding it (instead of trying to probe the pl_queue again) in the
event that we run out of queued input frames, as well as (in CFR mode)
when we pass the indicated status PTS.
---
 libavfilter/vf_libplacebo.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

Comments

Niklas Haas May 22, 2023, 8:35 a.m. UTC | #1
On Sun, 21 May 2023 13:13:52 +0200 Niklas Haas <ffmpeg@haasn.xyz> wrote:
> From: Niklas Haas <git@haasn.dev>
> 
> The current code relied on pl_queue eventually returning EOF back to the
> caller, which didn't work in all situations (e.g. single frame input).
> Also, the current code assumed that ff_inlink_acknowledge_status only
> fired once, which was patently not true, as the above edge cases
> demonstrated.
> 
> Solve both issues by keeping track of the acknowledged link status and
> forwarding it (instead of trying to probe the pl_queue again) in the
> event that we run out of queued input frames, as well as (in CFR mode)
> when we pass the indicated status PTS.
> ---
>  libavfilter/vf_libplacebo.c | 29 +++++++++++++++++------------
>  1 file changed, 17 insertions(+), 12 deletions(-)
> 
> diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
> index 94e49aa4652..6ce0f6263e4 100644
> --- a/libavfilter/vf_libplacebo.c
> +++ b/libavfilter/vf_libplacebo.c
> @@ -131,6 +131,8 @@ typedef struct LibplaceboContext {
>  
>      /* filter state */
>      AVFifo *out_pts; ///< timestamps of wanted output frames
> +    int64_t status_pts;
> +    int status;
>  
>      /* settings */
>      char *out_format_string;
> @@ -805,19 +807,12 @@ static int libplacebo_activate(AVFilterContext *ctx)
>      if (ret < 0)
>          return ret;
>  
> -    if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
> +    if (!s->status && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
>          pts = av_rescale_q_rnd(pts, inlink->time_base, outlink->time_base,
>                                 AV_ROUND_UP);
> -        if (status == AVERROR_EOF) {
> -            /* Signal EOF to pl_queue, and enqueue this output frame to
> -             * make sure we see PL_QUEUE_EOF returned eventually */
> -            pl_queue_push(s->queue, NULL);
> -            if (!s->fps.num)
> -                av_fifo_write(s->out_pts, &pts, 1);
> -        } else {
> -            ff_outlink_set_status(outlink, status, pts);
> -            return 0;
> -        }
> +        pl_queue_push(s->queue, NULL); /* Signal EOF to pl_queue */
> +        s->status = status;
> +        s->status_pts = pts;
>      }
>  
>      if (ff_outlink_frame_wanted(outlink)) {
> @@ -827,7 +822,17 @@ static int libplacebo_activate(AVFilterContext *ctx)
>          if (s->fps.num) {
>              pts = outlink->frame_count_out;
>          } else if (av_fifo_peek(s->out_pts, &pts, 1, 0) < 0) {
> -            ff_inlink_request_frame(inlink);
> +            /* No frames queued */
> +            if (s->status) {
> +                pts = s->status_pts;
> +            } else {
> +                ff_inlink_request_frame(inlink);
> +                return 0;
> +            }
> +        }
> +
> +        if (s->status && pts >= s->status_pts) {
> +            ff_outlink_set_status(outlink, s->status, s->status_pts);
>              return 0;
>          }
>  
> -- 
> 2.40.1
> 

Merged as c00fd025587fc8f028cda2c36f0061070fe91a35
diff mbox series

Patch

diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 94e49aa4652..6ce0f6263e4 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -131,6 +131,8 @@  typedef struct LibplaceboContext {
 
     /* filter state */
     AVFifo *out_pts; ///< timestamps of wanted output frames
+    int64_t status_pts;
+    int status;
 
     /* settings */
     char *out_format_string;
@@ -805,19 +807,12 @@  static int libplacebo_activate(AVFilterContext *ctx)
     if (ret < 0)
         return ret;
 
-    if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
+    if (!s->status && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
         pts = av_rescale_q_rnd(pts, inlink->time_base, outlink->time_base,
                                AV_ROUND_UP);
-        if (status == AVERROR_EOF) {
-            /* Signal EOF to pl_queue, and enqueue this output frame to
-             * make sure we see PL_QUEUE_EOF returned eventually */
-            pl_queue_push(s->queue, NULL);
-            if (!s->fps.num)
-                av_fifo_write(s->out_pts, &pts, 1);
-        } else {
-            ff_outlink_set_status(outlink, status, pts);
-            return 0;
-        }
+        pl_queue_push(s->queue, NULL); /* Signal EOF to pl_queue */
+        s->status = status;
+        s->status_pts = pts;
     }
 
     if (ff_outlink_frame_wanted(outlink)) {
@@ -827,7 +822,17 @@  static int libplacebo_activate(AVFilterContext *ctx)
         if (s->fps.num) {
             pts = outlink->frame_count_out;
         } else if (av_fifo_peek(s->out_pts, &pts, 1, 0) < 0) {
-            ff_inlink_request_frame(inlink);
+            /* No frames queued */
+            if (s->status) {
+                pts = s->status_pts;
+            } else {
+                ff_inlink_request_frame(inlink);
+                return 0;
+            }
+        }
+
+        if (s->status && pts >= s->status_pts) {
+            ff_outlink_set_status(outlink, s->status, s->status_pts);
             return 0;
         }