[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