diff --git a/NEWS b/NEWS index b71c605e6e663fa86a9ba7739c350fe34be1f815..cd7591e273391441ecebd90fd493b4ce6a4193c9 100644 --- a/NEWS +++ b/NEWS @@ -2073,6 +2073,7 @@ Video Filters: * Improvements on the transform filter, to support 10bits and RGB formats * Revival of the openCV and openCV example filters * ARM NEON acceleration of chroma filters + * New crop filter without picture copy Stream Output: * Extended support for recording, notably for MKV and AVI diff --git a/modules/video_filter/Makefile.am b/modules/video_filter/Makefile.am index 85b8e3ae9ae58fb8a782c58c79a6416c4bc23cd1..c7fe5e0694a964289ee84d45cffd49e4d402c96d 100644 --- a/modules/video_filter/Makefile.am +++ b/modules/video_filter/Makefile.am @@ -34,6 +34,7 @@ libhqdn3d_plugin_la_SOURCES = video_filter/hqdn3d.c video_filter/hqdn3d.h libhqdn3d_plugin_la_LIBADD = $(LIBM) libinvert_plugin_la_SOURCES = video_filter/invert.c libmagnify_plugin_la_SOURCES = video_filter/magnify.c +libformatcrop_plugin_la_SOURCES = video_filter/formatcrop.c libmirror_plugin_la_SOURCES = video_filter/mirror.c libmotionblur_plugin_la_SOURCES = video_filter/motionblur.c libmotiondetect_plugin_la_SOURCES = video_filter/motiondetect.c @@ -86,6 +87,7 @@ video_filter_LTLIBRARIES = \ libgaussianblur_plugin.la \ libinvert_plugin.la \ libmagnify_plugin.la \ + libformatcrop_plugin.la \ libmirror_plugin.la \ libmotionblur_plugin.la \ libmotiondetect_plugin.la \ diff --git a/modules/video_filter/formatcrop.c b/modules/video_filter/formatcrop.c new file mode 100644 index 0000000000000000000000000000000000000000..78d1e41705004490f66afcc1355586bf66ea1636 --- /dev/null +++ b/modules/video_filter/formatcrop.c @@ -0,0 +1,194 @@ +/***************************************************************************** + * formatcrop.c + ***************************************************************************** + * Copyright (C) 2021 VLC authors and VideoLAN + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <limits.h> + +#include <vlc_common.h> +#include <vlc_plugin.h> +#include <vlc_filter.h> +#include <vlc_picture.h> + +/** + * This filter crops the input pictures by adjusting the format (offsets and + * size) without any copy (contrary to croppadd). + */ + +#define CFG_PREFIX "formatcrop-" +static const char *const filter_options[] = { + "top", "bottom", "left", "right", NULL, +}; + +#define CROPTOP_TEXT N_("Pixels to crop from top") +#define CROPTOP_LONGTEXT \ + N_("Number of pixels to crop from the top of the image.") + +#define CROPBOTTOM_TEXT N_("Pixels to crop from bottom") +#define CROPBOTTOM_LONGTEXT \ + N_("Number of pixels to crop from the bottom of the image.") + +#define CROPLEFT_TEXT N_("Pixels to crop from left") +#define CROPLEFT_LONGTEXT \ + N_("Number of pixels to crop from the left of the image.") + +#define CROPRIGHT_TEXT N_("Pixels to crop from right") +#define CROPRIGHT_LONGTEXT \ + N_("Number of pixels to crop from the right of the image.") + +struct sys { + unsigned x; + unsigned y; + unsigned width; + unsigned height; +}; + +#define IDX_TOP 0 +#define IDX_LEFT 1 +#define IDX_BOTTOM 2 +#define IDX_RIGHT 3 + +struct transform { + unsigned idx_top; + unsigned idx_left; + /* idx_bottom is idx_top XOR 2 + idx_right is idx_left XOR 2 */ +}; + +static const struct transform transforms[8] = { + [ORIENT_TOP_LEFT] = { IDX_TOP, IDX_LEFT }, + [ORIENT_TOP_RIGHT] = { IDX_TOP, IDX_RIGHT }, + [ORIENT_BOTTOM_LEFT] = { IDX_BOTTOM, IDX_LEFT }, + [ORIENT_BOTTOM_RIGHT] = { IDX_BOTTOM, IDX_RIGHT }, + [ORIENT_LEFT_TOP] = { IDX_LEFT, IDX_TOP }, + [ORIENT_LEFT_BOTTOM] = { IDX_LEFT, IDX_BOTTOM }, + [ORIENT_RIGHT_TOP] = { IDX_RIGHT, IDX_TOP }, + [ORIENT_RIGHT_BOTTOM] = { IDX_RIGHT, IDX_BOTTOM }, +}; + +static picture_t * +Filter(filter_t *filter, picture_t *pic) +{ + struct sys *sys = filter->p_sys; + + if (!pic) + return NULL; + + picture_t *out = picture_Clone(pic); + if (!out) + return NULL; + picture_CopyProperties(out, pic); + + picture_Release(pic); + + video_format_t *fmt = &out->format; + fmt->i_x_offset = sys->x; + fmt->i_y_offset = sys->y; + fmt->i_visible_width = sys->width; + fmt->i_visible_height = sys->height; + + return out; +} + +static void +Close(filter_t *filter) +{ + struct sys *sys = filter->p_sys; + free(sys); +} + +static int +Open(filter_t *filter) +{ + config_ChainParse(filter, CFG_PREFIX, filter_options, filter->p_cfg); + unsigned top = var_InheritInteger(filter, CFG_PREFIX "top"); + unsigned bottom = var_InheritInteger(filter, CFG_PREFIX "bottom"); + unsigned left = var_InheritInteger(filter, CFG_PREFIX "left"); + unsigned right = var_InheritInteger(filter, CFG_PREFIX "right"); + + video_format_t *fmt = &filter->fmt_in.video; + video_orientation_t orientation = fmt->orientation; + + /* In the same order as IDX_ constants values */ + unsigned crop[] = { top, left, bottom, right }; + + /* Transform from picture crop to physical crop (with orientation) */ + const struct transform *tx = &transforms[orientation]; + unsigned crop_top = crop[tx->idx_top]; + unsigned crop_left = crop[tx->idx_left]; + unsigned crop_bottom = crop[tx->idx_top ^ 2]; + unsigned crop_right = crop[tx->idx_left ^ 2]; + + if (crop_top + crop_bottom >= fmt->i_visible_height) + { + msg_Err(filter, "Vertical crop (top=%u, bottom=%u) " + "greater than the picture height (%u)\n", + crop_top, crop_bottom, fmt->i_visible_height); + return VLC_EGENERIC; + } + + if (crop_left + crop_right >= fmt->i_visible_width) + { + msg_Err(filter, "Horizontal crop (left=%u, right=%u) " + "greater than the picture width (%u)\n", + crop_left, crop_right, fmt->i_visible_width); + return VLC_EGENERIC; + } + + struct sys *sys = malloc(sizeof(*sys)); + if (!sys) + return VLC_EGENERIC; + + filter->p_sys = sys; + + sys->x = fmt->i_x_offset + crop_left; + sys->y = fmt->i_y_offset + crop_top; + sys->width = fmt->i_visible_width - crop_left - crop_right; + sys->height = fmt->i_visible_height - crop_top - crop_bottom; + + static const struct vlc_filter_operations filter_ops = + { + .filter_video = Filter, + .close = Close, + }; + filter->ops = &filter_ops; + + return VLC_SUCCESS; +} + +vlc_module_begin() + set_shortname("formatcrop") + set_description(N_("Video cropping filter")) + set_callback_video_filter(Open) + + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VFILTER); + + add_integer_with_range(CFG_PREFIX "top", 0, 0, INT_MAX, + CROPTOP_TEXT, CROPTOP_LONGTEXT) + add_integer_with_range(CFG_PREFIX "bottom", 0, 0, INT_MAX, + CROPBOTTOM_TEXT, CROPTOP_LONGTEXT) + add_integer_with_range(CFG_PREFIX "left", 0, 0, INT_MAX, + CROPLEFT_TEXT, CROPTOP_LONGTEXT) + add_integer_with_range(CFG_PREFIX "right", 0, 0, INT_MAX, + CROPRIGHT_TEXT, CROPTOP_LONGTEXT) +vlc_module_end() diff --git a/po/POTFILES.in b/po/POTFILES.in index 5b31464ddd56e5a1a80210325eea1af39bd87bf1..73ee32bff713f20201b9281a97ceda207a52a660 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1301,6 +1301,7 @@ modules/video_filter/edgedetection.c modules/video_filter/erase.c modules/video_filter/extract.c modules/video_filter/fps.c +modules/video_filter/formatcrop.c modules/video_filter/freeze.c modules/video_filter/gaussianblur.c modules/video_filter/gradfun.c