Signed-off-by: Paul B Mahol <one...@gmail.com> --- doc/filters.texi | 26 +++++++ libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_swaprect.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 libavfilter/vf_swaprect.c
diff --git a/doc/filters.texi b/doc/filters.texi index 274532d..47e5362 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -10897,6 +10897,32 @@ Interpolate) pixel art scaling algorithm. Useful for enlarging pixel art images without reducing sharpness. +@section swaprect + +Swap two rectangular objects in video. + +This filter accepts the following options: + +@table @option +@item w +Set object width. + +@item h +Set object height. + +@item x1 +Set 1st rect x coordinate. + +@item y1 +Set 1st rect y coordinate. + +@item x2 +Set 2nd rect x coordinate. + +@item y2 +Set 2nd rect y coordinate. +@end table + @section swapuv Swap U & V plane. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 8884d1d..4d1376b 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -233,6 +233,7 @@ OBJS-$(CONFIG_SSIM_FILTER) += vf_ssim.o dualinput.o framesync. OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o OBJS-$(CONFIG_SUBTITLES_FILTER) += vf_subtitles.o OBJS-$(CONFIG_SUPER2XSAI_FILTER) += vf_super2xsai.o +OBJS-$(CONFIG_SWAPRECT_FILTER) += vf_swaprect.o OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o OBJS-$(CONFIG_TBLEND_FILTER) += vf_blend.o dualinput.o framesync.o OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 0eeef53..94a951b 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -254,6 +254,7 @@ void avfilter_register_all(void) REGISTER_FILTER(STEREO3D, stereo3d, vf); REGISTER_FILTER(SUBTITLES, subtitles, vf); REGISTER_FILTER(SUPER2XSAI, super2xsai, vf); + REGISTER_FILTER(SWAPRECT, swaprect, vf); REGISTER_FILTER(SWAPUV, swapuv, vf); REGISTER_FILTER(TBLEND, tblend, vf); REGISTER_FILTER(TELECINE, telecine, vf); diff --git a/libavfilter/vf_swaprect.c b/libavfilter/vf_swaprect.c new file mode 100644 index 0000000..c0934a7 --- /dev/null +++ b/libavfilter/vf_swaprect.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2015 Paul B. Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct SwapRectContext { + const AVClass *class; + int w, h; + int x1[4], y1[4]; + int x2[4], y2[4]; + int nb_planes; + int planewidth[4]; + int planeheight[4]; + int pixsteps[4]; + + uint8_t *temp; +} SwapRectContext; + +#define OFFSET(x) offsetof(SwapRectContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +static const AVOption swaprect_options[] = { + { "w", "set rect width", OFFSET(w), AV_OPT_TYPE_INT, {.i64=1}, 1, INT_MAX, .flags = FLAGS }, + { "h", "set rect height", OFFSET(h), AV_OPT_TYPE_INT, {.i64=1}, 1, INT_MAX, .flags = FLAGS }, + { "x1", "set 1st rect x coordinate", OFFSET(x1[0]), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, .flags = FLAGS }, + { "y1", "set 1st rect y coordinate", OFFSET(y1[0]), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, .flags = FLAGS }, + { "x2", "set 2nd rect x coordinate", OFFSET(x2[0]), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, .flags = FLAGS }, + { "y2", "set 2nd rect y coordinate", OFFSET(y2[0]), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, .flags = FLAGS }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(swaprect); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *pix_fmts = NULL; + int fmt, ret; + + 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_PAL || + desc->flags & AV_PIX_FMT_FLAG_HWACCEL || + desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) && + (ret = ff_add_format(&pix_fmts, fmt)) < 0) + return ret; + } + + return ff_set_common_formats(ctx, pix_fmts); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + SwapRectContext *s = ctx->priv; + int y, p; + + for (p = 0; p < s->nb_planes; p++) { + uint8_t *src = in->data[p] + s->y1[p] * in->linesize[p] + s->x1[p] * s->pixsteps[p]; + uint8_t *dst = in->data[p] + s->y2[p] * in->linesize[p] + s->x2[p] * s->pixsteps[p]; + for (y = 0; y < s->planeheight[p]; y++) { + memcpy(s->temp, src, s->planewidth[p] * s->pixsteps[p]); + memmove(src, dst, s->planewidth[p] * s->pixsteps[p]); + memcpy(dst, s->temp, s->planewidth[p] * s->pixsteps[p]); + src += in->linesize[p]; + dst += in->linesize[p]; + } + } + + return ff_filter_frame(outlink, in); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + SwapRectContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + + if (s->w + s->x1[0] > inlink->w || + s->w + s->x2[0] > inlink->w || + s->h + s->y1[0] > inlink->h || + s->h + s->y2[0] > inlink->h) + return AVERROR(EINVAL); + + av_image_fill_max_pixsteps(s->pixsteps, NULL, desc); + s->nb_planes = av_pix_fmt_count_planes(inlink->format); + + s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(s->h, desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = s->h; + s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(s->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = s->w; + + s->x1[1] = s->x1[2] = FF_CEIL_RSHIFT(s->x1[0], desc->log2_chroma_w); + s->x1[0] = s->x1[3] = s->x1[0]; + s->y1[1] = s->y1[2] = FF_CEIL_RSHIFT(s->y1[0], desc->log2_chroma_h); + s->y1[0] = s->y1[3] = s->y1[0]; + + s->x2[1] = s->x2[2] = FF_CEIL_RSHIFT(s->x2[0], desc->log2_chroma_w); + s->x2[0] = s->x2[3] = s->x2[0]; + s->y2[1] = s->y2[2] = FF_CEIL_RSHIFT(s->y2[0], desc->log2_chroma_h); + s->y2[0] = s->y2[3] = s->y2[0]; + + s->temp = av_malloc_array(s->w, s->pixsteps[0]); + if (!s->temp) + return AVERROR(ENOMEM); + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + SwapRectContext *s = ctx->priv; + av_freep(&s->temp); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + .needs_writable = 1, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_swaprect = { + .name = "swaprect", + .description = NULL_IF_CONFIG_SMALL("Swap 2 rectangular objects in video."), + .priv_size = sizeof(SwapRectContext), + .priv_class = &swaprect_class, + .query_formats = query_formats, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, +}; -- 1.9.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel