[FFmpeg-devel] [PATCH] libavfilter-soc: Make overlay handle still images

Vitor Sessak vitor1001
Wed May 6 17:53:18 CEST 2009


Martin Storsj? wrote:
> Hi,

Hi, and thanks for helping with libavfilter!

> 
> Currently, the overlay filter can't properly handle the case when one 
> input is a still image. The filter logic determines that the still image 
> input is the one currently being behind and just tries to get a new frame 
> from that input, without actually getting any frame with a pts higher than 
> the one from the running video.
> 
> The attached patch is an initial attempt at fixing this: If the filter 
> receives a new frame with the same pts as the previous one, it marks that 
> input as having reached eof and doesn't try to read any more data from 
> that input.

Just a question: how are you testing those changes?

> +
> +    int eof[2];                 //< end of file for each input
>  } OverlayContext;
>  
>  static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> @@ -149,9 +151,26 @@ static int request_frame(AVFilterLink *link)
>          if(avfilter_request_frame(link->src->inputs[0]) ||
>             avfilter_request_frame(link->src->inputs[1]))
>              return -1;
> -    } else
> +    } else if (!(over->eof[0] && over->eof[1])) {
> +        int oldpts;
> +
> +        /* if this input is at eof, pull from the other one */
> +        if (over->eof[idx])
> +            idx = idx ? 0 : 1;
> +
> +        oldpts = over->pics[idx][1]->pts;
>          if(avfilter_request_frame(link->src->inputs[idx]))
>              return -1;
> +        if(over->pics[idx][1]->pts == oldpts) {
> +            /* no new pts, we're probably at eof, pull a frame
> +               from the other queue to keep it moving */

The correct way to know if the video is over is to check if 
request_frame() returned -1.

Also, there is a bug in vf_overlay.c that may causes you some problems:

> static int request_frame(AVFilterLink *link)
> {
>     AVFilterPicRef *pic;
>     OverlayContext *over = link->src->priv;
>     int idx;
>     int x, y, w, h;
> 
>     /* the first time through, we need to pull a couple frames */
>     if(!over->pics[0][1] && !over->pics[1][1] &&
>        (avfilter_request_frame(link->src->inputs[0]) ||
>         avfilter_request_frame(link->src->inputs[1])))
>         return -1;
> 
>     /* then we pull a frame from the stream which currently has a lower pts */
>     if((idx = lower_timestamp(over)) == 2) {
>         if(avfilter_request_frame(link->src->inputs[0]) ||
>            avfilter_request_frame(link->src->inputs[1]))
>             return -1;
>     } else
>         if(avfilter_request_frame(link->src->inputs[idx]))
>             return -1;

You see that here the filter will call avfilter_request_frame() twice in 
one of the two inputs. That is a problem, because all you can be sure 
(thanks to poll_frame()) is that each input have _one_ available frame. 
The correct solution is, in the case of the first output frame, to 
overlay one frame of the input 1 with one frame of input 2, no matter 
what timestamp.

Another thing is that this filter if designed this way will not stop 
overlaying frames after one of the movies is finished (it will repeat 
the last frame of the one that have finished until the other finishes 
too). The first frame of one of the videos will also be repeated in the 
beginning if the videos that have different initial timestamps. This 
behavior is consistent, but I don't know if it is the most useful one...

-Vitor



More information about the ffmpeg-devel mailing list