diff --git a/libavfilter/vf_zoom.c b/libavfilter/vf_zoom.c index 4d5fe7c2b93..95525ac36d1 100644 --- a/libavfilter/vf_zoom.c +++ b/libavfilter/vf_zoom.c @@ -489,12 +489,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) const int out_w = outlink->w; const int out_h = outlink->h; - out = ff_get_video_buffer(outlink, out_w, out_h); - if (!out) { - av_frame_free(&in); - return AVERROR(ENOMEM); - } - av_frame_copy_props(out, in); // eval T (time) zoom->var_values[VAR_T] = in->pts == AV_NOPTS_VALUE ? @@ -536,47 +530,81 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_log(zoom, AV_LOG_WARNING, "x position %.2f is out of range of [0-1]\n", zoom->x); zoom->x = av_clipd_c(zoom->x, 0, 1); } - if(zoom->y < 0 || zoom->y > 1){ - av_log(zoom, AV_LOG_WARNING, "y position %.2f is out of range of [0-1]\n", zoom->y); + if(zoom->y < 0 || zoom->y > 1){ + av_log(zoom, AV_LOG_WARNING, "y position %.2f is out of range of [0-1]\n", zoom->y); zoom->y = av_clipd_c(zoom->y, 0, 1); - } - // copy in the background - ff_fill_rectangle(&zoom->dc, &zoom->fillcolor, - out->data, out->linesize, - 0, 0, - out_w, out_h); + } + + + if(zoom_val == 1) { + if((ret = av_frame_make_writable(in)) < 0){ + goto error; + } + out = in; + } else { + out = ff_get_video_buffer(outlink, out_w, out_h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } // scale if(zoom_val == 1) { - // it's 1, just copy - // quite an expensive noop :D - ff_copy_rectangle2(&zoom->dc, - out->data, out->linesize, - in->data, in->linesize, - 0, 0, - av_clip_c(in_w * zoom->x - out_w / 2.0, 0, in_w - out_w), - av_clip_c(in_h * zoom->y - out_h / 2.0, 0, in_h - out_h), - out_w, out_h); + // it's 1, just a ref + + out->width = out_w; + out->height = out_h; + int x = av_clip_c(in_w * zoom->x - out_w / 2.0, 0, in_w - out_w); + int y = av_clip_c(in_h * zoom->y - out_h / 2.0, 0, in_h - out_h); + + out->data[0] += y * out->linesize[0]; + out->data[0] += x * zoom->desc->comp[0].step; + + if (!(zoom->desc->flags & AV_PIX_FMT_FLAG_PAL || zoom->desc->flags & FF_PSEUDOPAL)) { + for (int i = 1; i < 3; i ++) { + if (out->data[i]) { + out->data[i] += (y >> zoom->desc->log2_chroma_h) * out->linesize[i]; + out->data[i] += (x >> zoom->desc->log2_chroma_w) * zoom->desc->comp[i].step; + } + } + } + + /* alpha plane */ + if (out->data[3]) { + out->data[3] += y * out->linesize[3]; + out->data[3] += x * zoom->desc->comp[3].step; + } } else if (zoom_val <= 0) { // if it's 0 or lower do nothing // noop } else if (zoom_val < 1) { + // fill in the background + ff_fill_rectangle(&zoom->dc, &zoom->fillcolor, + out->data, out->linesize, + 0, 0, + out_w, out_h); // zoom in (0, 1) ret = zoom_out(zoom, in, out, outlink); if(ret) goto error; } else if (zoom_val > 1){ - // zoom in (1, +ing) + // zoom in (1, +inf) ret = zoom_in(zoom, in, out, outlink); if(ret) goto error; } - av_frame_free(&in); + if(in != out) { + av_frame_free(&in); + } return ff_filter_frame(outlink, out); error: - av_frame_free(&out); + if(out) { + av_frame_free(&out); + } return ret; }