[FFmpeg-devel] lavfi noise generator

Stefano Sabatini stefano.sabatini-lala
Fri Jan 2 03:26:17 CET 2009


On date Tuesday 2008-12-30 19:14:37 +0100, Stefano Sabatini encoded:
> On date Monday 2008-12-29 16:27:04 +0100, Vitor Sessak encoded:
> > Stefano Sabatini wrote:
[...]
> >> Hi Vitor, vsrc_noise.c is a *source* rather than a filter, so I don't
> >> think it is possible to use the the draw_slice() API.
> >
> > Indeed, it should not be possible, at least not with the current svn  
> > code. See my attached patch.
> >
> >> What I'm currently doing is:
> >>
> >> static int request_frame(AVFilterLink *link)
> >> {
> >>     NoiseContext *ctx = link->src->priv;
> >>     AVFilterPicRef *picref = avfilter_get_video_buffer(link, AV_PERM_WRITE);
> >>
> >>     fill_picture(ctx, picref);
> >>     picref->pts = av_rescale_q(ctx->pts++, (AVRational){ ctx->frame_rate.den, ctx->frame_rate.num }, AV_TIME_BASE_Q);
> >>
> >>     avfilter_start_frame(link, avfilter_ref_pic(picref, ~0));
> >>     avfilter_draw_slice(link, 0, picref->h);
> >>     avfilter_end_frame(link);
> >>
> >>     avfilter_unref_pic(picref);
> >>
> >>     return 0;
> >> }
> >
> > Could something like the following work?
> >
> > #define SLICE_SIZE 32
> >
> > static int request_frame(AVFilterLink *link)
> > {
> >     NoiseContext *ctx = link->src->priv;
> >     AVFilterPicRef *picref = avfilter_get_video_buffer(link,  
> > AV_PERM_WRITE);
> >     int h;
> >
> >     picref->pts = av_rescale_q(ctx->pts++, (AVRational) {  
> > ctx->frame_rate.den, ctx->frame_rate.num }, AV_TIME_BASE_Q);
> >
> >     avfilter_start_frame(link, avfilter_ref_pic(picref, ~0));
> >     for(h=0; h < ctx->h; h += SLICE_SIZE) {
> >        fill_picture(ctx, picref, h, FFMIN(h+SLICE_SIZE, ctx->h));
> >        avfilter_draw_slice(link, h, FFMIN(h+SLICE_SIZE, ctx->h));
> >     }
> >     avfilter_end_frame(link);
> >
> >     avfilter_unref_pic(picref);
> >
> >     return 0;
> > }
> 
> It should work, the only thing I don't like is that in this way the
> code *needs* to know about the picture structure (it needs to know how
> to access the slice), while before I was simply filling the whole
> buffer, and this consideration leads to this (maybe silly) question:
> what's the advantage of per-slice filling in this case?
> 
> > But maybe an even cleaner solution would be to use draw_slice() and  
> > change the function avfilter_request_frame() as in the completely  
> > untested attached patch.
> 
> [...]
> 
> > Index: libavfilter/avfilter.c
> > ===================================================================
> > --- libavfilter/avfilter.c	(revision 16243)
> > +++ libavfilter/avfilter.c	(working copy)
> > @@ -179,7 +179,18 @@
> >          return link_spad(link).request_frame(link);
> >      else if(link->src->inputs[0])
> >          return avfilter_request_frame(link->src->inputs[0]);
> > +    else if (link_spad(link).draw_slice) {
> > +        int h;
> > +        for (h=0; h < link->h; h += SLICE_SIZE) {
> > +            AVFilterPicRef *picref = avfilter_get_video_buffer(link, AV_PERM_WRITE);
> > +            avfilter_start_frame(link, avfilter_ref_pic(picref, ~0));
> > +            link_spad(link).draw_slice(link, h, FFMIN(h+SLICE_SIZE, link->h));
> > +        }
> > +        avfilter_end_frame(link);
> > +        avfilter_unref_pic(picref);
> > +    }
> >      else return -1;
> > +    return 0;
> >  }
> >  
> >  int avfilter_poll_frame(AVFilterLink *link)

What if we need to change the context before/after to send the picture data?

And what if we need to set the PTS (as indeed would be needed by most
sources? (yes we could set PTS for each slice but this would be rater
ugly.)

The first solution I see is to define a start/end callback for the
output pads too, for example redefining the start_frame/end_frame to
be definable also for output pads.

For example for the output pad start_frame callback we could use
start_frame() with NULL as argument or redefine a new callback
definable only for output pads.

This is my attempt in that direction:

int avfilter_request_frame(AVFilterLink *link)
{
    if(link_spad(link).request_frame)
        return link_spad(link).request_frame(link);
    else if(link->src->inputs[0])
        return avfilter_request_frame(link->src->inputs[0]);
    else {
        AVFilterPicRef *picref = NULL;
        if (link_spad(link).start_frame)
            link_spad(link).start_frame(link, NULL);
        else {
            picref = avfilter_get_video_buffer(link, AV_PERM_WRITE);
            avfilter_start_frame(link, avfilter_ref_pic(picref, ~0));
        }

        if (link_spad(link).draw_slice) {
            int y;

            for (y=0; y < link->h; y += SLICE_SIZE)
                link_spad(link).draw_slice(link, y, FFMIN(SLICE_SIZE, link->h - y));
        }

        if (link_spad(link).end_frame)
            link_spad(link).end_frame(link);
        else {
            avfilter_end_frame(link);
            if (picref)
                avfilter_unref_pic(picref);
        }
    }

    return 0;
}

The problem with the above code is that it is broken, indeed
request_frame() needs to notify when it fails or it has finished to
issue pictures (returning a value different than 0), using the
combination of start_frame/draw_slice/end_frame callbacks I can't see
a clean way to return that information.

Resuming it seems to me that the draw_slice callback defined in output
pads seems useful only for sources which:

* don't need to set the PTS
* don't need to change their internal state
* don't need to notify failure/end of transmission

that is it doesn't seems so useful at all.

But maybe I'm wrong.

Regards.
-- 
FFmpeg = Fundamental and Fantastic Magnificient Picky Exuberant Gadget




More information about the ffmpeg-devel mailing list