[FFmpeg-devel] [PATCH v3 1/2] vf_crop: Add support for cropping hardware frames

Philip Langdale philipl at overt.org
Mon Mar 25 06:58:03 EET 2019


On Sat, 23 Mar 2019 16:18:48 +0000
Mark Thompson <sw at jkqxz.net> wrote:

> Set the cropping fields in the AVFrame.
> ---
>  libavfilter/vf_crop.c | 74
> +++++++++++++++++++++++++++++-------------- 1 file changed, 51
> insertions(+), 23 deletions(-)
> 
> There is the slightly unfortunate effect the filter links don't carry
> the cropping information, so we don't know how big the cropped output
> is in following links until we actually get a frame.
> 
> For example, to get the middle ninth of a stream:
> 
> ./ffmpeg_g -y -hwaccel vaapi -hwaccel_device /dev/dri/renderD128
> -hwaccel_output_format vaapi -i in.mp4 -an -vf
> "crop=iw/3:ih/3:iw/3:ih/3,scale_vaapi=iw/3:ih/3" -c:v h264_vaapi
> out.mp4
> 
> Without the extra arguments to scale it will take the cropped part
> correctly but then scale it to the original size.
> 
> diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
> index 84be4c7d0d..7f6b0f03d3 100644
> --- a/libavfilter/vf_crop.c
> +++ b/libavfilter/vf_crop.c
> @@ -98,9 +98,17 @@ static int query_formats(AVFilterContext *ctx)
>  
>      for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
>          const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
> -        if (!(desc->flags & (AV_PIX_FMT_FLAG_HWACCEL |
> AV_PIX_FMT_FLAG_BITSTREAM)) &&
> -            !((desc->log2_chroma_w || desc->log2_chroma_h)
> && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) &&
> -            (ret = ff_add_format(&formats, fmt)) < 0)
> +        if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM)
> +            continue;
> +        if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
> +            // Not usable if there is any subsampling but the format
> is
> +            // not planar (e.g. YUYV422).
> +            if ((desc->log2_chroma_w || desc->log2_chroma_h) &&
> +                !(desc->flags & AV_PIX_FMT_FLAG_PLANAR))
> +                continue;
> +        }
> +        ret = ff_add_format(&formats, fmt);
> +        if (ret < 0)
>              return ret;
>      }
>  
> @@ -157,8 +165,14 @@ static int config_input(AVFilterLink *link)
>      s->var_values[VAR_POS]   = NAN;
>  
>      av_image_fill_max_pixsteps(s->max_step, NULL, pix_desc);
> -    s->hsub = pix_desc->log2_chroma_w;
> -    s->vsub = pix_desc->log2_chroma_h;
> +
> +    if (pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
> +        s->hsub = 1;
> +        s->vsub = 1;
> +    } else {
> +        s->hsub = pix_desc->log2_chroma_w;
> +        s->vsub = pix_desc->log2_chroma_h;
> +    }
>  
>      if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr),
>                                        var_names, s->var_values,
> @@ -237,9 +251,15 @@ fail_expr:
>  static int config_output(AVFilterLink *link)
>  {
>      CropContext *s = link->src->priv;
> +    const AVPixFmtDescriptor *desc =
> av_pix_fmt_desc_get(link->format); 
> -    link->w = s->w;
> -    link->h = s->h;
> +    if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
> +        // Hardware frames adjust the cropping regions rather than
> +        // changing the frame size.
> +    } else {
> +        link->w = s->w;
> +        link->h = s->h;
> +    }
>      link->sample_aspect_ratio = s->out_sar;
>  
>      return 0;
> @@ -252,9 +272,6 @@ static int filter_frame(AVFilterLink *link,
> AVFrame *frame) const AVPixFmtDescriptor *desc =
> av_pix_fmt_desc_get(link->format); int i;
>  
> -    frame->width  = s->w;
> -    frame->height = s->h;
> -
>      s->var_values[VAR_N] = link->frame_count_out;
>      s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
>          NAN : frame->pts * av_q2d(link->time_base);
> @@ -285,22 +302,33 @@ static int filter_frame(AVFilterLink *link,
> AVFrame *frame) (int)s->var_values[VAR_N], s->var_values[VAR_T],
> s->var_values[VAR_POS], s->x, s->y, s->x+s->w, s->y+s->h);
>  
> -    frame->data[0] += s->y * frame->linesize[0];
> -    frame->data[0] += s->x * s->max_step[0];
> -
> -    if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags &
> FF_PSEUDOPAL)) {
> -        for (i = 1; i < 3; i ++) {
> -            if (frame->data[i]) {
> -                frame->data[i] += (s->y >> s->vsub) *
> frame->linesize[i];
> -                frame->data[i] += (s->x * s->max_step[i]) >> s->hsub;
> +    if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
> +        frame->crop_top   += s->y;
> +        frame->crop_left  += s->x;
> +        frame->crop_bottom = frame->height - frame->crop_top -
> frame->crop_bottom - s->h;
> +        frame->crop_right  = frame->width  - frame->crop_left -
> frame->crop_right - s->w; +
> +    } else {
> +        frame->width  = s->w;
> +        frame->height = s->h;
> +
> +        frame->data[0] += s->y * frame->linesize[0];
> +        frame->data[0] += s->x * s->max_step[0];
> +
> +        if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags &
> FF_PSEUDOPAL)) {
> +            for (i = 1; i < 3; i ++) {
> +                if (frame->data[i]) {
> +                    frame->data[i] += (s->y >> s->vsub) *
> frame->linesize[i];
> +                    frame->data[i] += (s->x * s->max_step[i]) >>
> s->hsub;
> +                }
>              }
>          }
> -    }
>  
> -    /* alpha plane */
> -    if (frame->data[3]) {
> -        frame->data[3] += s->y * frame->linesize[3];
> -        frame->data[3] += s->x * s->max_step[3];
> +        /* alpha plane */
> +        if (frame->data[3]) {
> +            frame->data[3] += s->y * frame->linesize[3];
> +            frame->data[3] += s->x * s->max_step[3];
> +        }
>      }
>  
>      return ff_filter_frame(link->dst->outputs[0], frame);

Ship it.

--phil


More information about the ffmpeg-devel mailing list