diff --git a/Makefile.in b/Makefile.in index 5a219d08a..83d598550 100644 --- a/Makefile.in +++ b/Makefile.in @@ -93,7 +93,6 @@ OBJS = @OBJS@ \ @JACK_TRANS_OBJ@ \ @SPEEX_OBJ@ \ src/capture_filter.o \ - src/capture_filter/blank.o \ src/capture_filter/every.o \ src/capture_filter/logo.o \ src/capture_filter/none.o \ @@ -650,6 +649,9 @@ rtsp_server: @RTSP_SERVER_LIB_TARGET@ @VCAPTURE_FILTER_RESIZE_LIB_TARGET@: @RESIZE_OBJ@ $(LINKER) $(LDFLAGS) -shared -Wl,-soname,module_vcapfilter_resize.so $^ @RESIZE_LIBS@ -o $@ +@VCAPTURE_FILTER_BLANK_LIB_TARGET@: @BLANK_OBJ@ + $(LINKER) $(LDFLAGS) -shared -Wl,-soname,module_vcapfilter_blank.so $^ @BLANK_LIBS@ -o $@ + @OPENSSL_LIB_TARGET@: @OPENSSL_OBJ@ $(LINKER) $(LDFLAGS) -shared -Wl,-soname,module_openssl.so $^ @CRYPTO_LIBS@ -o $@ diff --git a/configure.ac b/configure.ac index 983ab05a8..ffbe91b8b 100644 --- a/configure.ac +++ b/configure.ac @@ -1438,6 +1438,43 @@ fi AC_SUBST(RESIZE_LIBS) AC_SUBST(RESIZE_OBJ) +# ------------------------------------------------------------------------------------------------- +# Blank stuff +# ------------------------------------------------------------------------------------------------- +BLANK_LIBS= +BLANK_OBJ= +blank=no + +define(blank_dep, libswscale) + +AC_ARG_ENABLE(blank, +[ --disable-blank disable blank capture filter (default is auto)] +[ Requires: blank_dep], + [blank_req=$enableval], + [blank_req=auto] + ) + +PKG_CHECK_MODULES([BLANK], [blank_dep], FOUND_BLANK_DEP=yes, FOUND_BLANK_DEP=no) + +if test $blank_req != no -a $FOUND_BLANK_DEP = yes +then + CFLAGS="$CFLAGS ${BLANK_CFLAGS}" + CXXFLAGS="$CXXFLAGS ${BLANK_CFLAGS}" + BLANK_OBJ="src/capture_filter/blank.o" + AC_SUBST(VCAPTURE_FILTER_BLANK_LIB_TARGET, "lib/ultragrid/module_vcapfilter_blank.so") + + LIB_TARGETS="$LIB_TARGETS $VCAPTURE_FILTER_BLANK_LIB_TARGET" + LIB_OBJS="$LIB_OBJS $BLANK_OBJ" + LIB_MODULES="$LIB_MODULES $BLANK_LIBS" + blank=yes +fi + +if test $blank_req = yes -a $blank = no; then + AC_MSG_ERROR([Blank dep not found (libswscale)]); +fi + +AC_SUBST(BLANK_LIBS) +AC_SUBST(BLANK_OBJ) # ------------------------------------------------------------------------------------------------- @@ -2872,6 +2909,7 @@ RESULT=\ Libavcodec .................. $libavcodec resize capture filter ....... $resize + blank capture filter ........ $blank RTSP Server ................. $rtsp_server scale postprocessor ......... $scale testcard extras ............. $testcard_extras_req diff --git a/src/capture_filter.cpp b/src/capture_filter.cpp index 6ddac79ed..b9772172d 100644 --- a/src/capture_filter.cpp +++ b/src/capture_filter.cpp @@ -62,7 +62,6 @@ using namespace std; static void init_capture_filters() __attribute__((constructor)); static void init_capture_filters() { - register_library("blank", &capture_filter_blank, LIBRARY_CLASS_CAPTURE_FILTER, CAPTURE_FILTER_ABI_VERSION); register_library("every", &capture_filter_every, LIBRARY_CLASS_CAPTURE_FILTER, CAPTURE_FILTER_ABI_VERSION); register_library("logo", &capture_filter_logo, LIBRARY_CLASS_CAPTURE_FILTER, CAPTURE_FILTER_ABI_VERSION); register_library("none", &capture_filter_none, LIBRARY_CLASS_CAPTURE_FILTER, CAPTURE_FILTER_ABI_VERSION); diff --git a/src/capture_filter/blank.c b/src/capture_filter/blank.cpp similarity index 58% rename from src/capture_filter/blank.c rename to src/capture_filter/blank.cpp index bdefa4942..78fe73525 100644 --- a/src/capture_filter/blank.c +++ b/src/capture_filter/blank.cpp @@ -1,14 +1,10 @@ +/** + * @file src/capture_filter/blank.cpp + * @author Martin Pulec + */ /* - * FILE: capture_filter/blank.c - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith - * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * Copyright (c) 2013-2015 CESNET, z. s. p. o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions @@ -21,14 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of CESNET nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 3. Neither the name of CESNET nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, @@ -42,8 +33,6 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * */ #ifdef HAVE_CONFIG_H @@ -53,12 +42,20 @@ #endif /* HAVE_CONFIG_H */ #include "capture_filter.h" +#include "libavcodec_common.h" +#include "lib_common.h" #include "messaging.h" #include "module.h" #include "video.h" #include "video_codec.h" +extern "C" { +#include +} + +#define FACTOR 6 + static int init(struct module *parent, const char *cfg, void **state); static void done(void *state); static struct video_frame *filter(void *state, struct video_frame *in); @@ -72,7 +69,10 @@ struct state_blank { struct video_desc saved_desc; bool in_relative_units; - bool outline; + bool black; + + struct SwsContext *ctx_downscale, + *ctx_upscale; }; static bool parse(struct state_blank *s, char *cfg) @@ -80,7 +80,7 @@ static bool parse(struct state_blank *s, char *cfg) int vals[4]; double vals_relative[4]; unsigned int counter = 0; - bool outline = false; + bool black = false; memset(&s->saved_desc, 0, sizeof(s->saved_desc)); @@ -108,8 +108,8 @@ static bool parse(struct state_blank *s, char *cfg) break; } while ((item = strtok_r(cfg, ":", &save_ptr))) { - if (strcmp(item, "outline") == 0) { - outline = true; + if (strcmp(item, "black") == 0) { + black = true; } else { fprintf(stderr, "[Blank] Unknown config value: %s\n", item); @@ -130,10 +130,10 @@ static bool parse(struct state_blank *s, char *cfg) } else { s->x = vals[0]; s->y = vals[1]; - s->width = vals[2]; + s->width = (vals[2] + FACTOR - 1) / FACTOR * FACTOR; s->height = vals[3]; } - s->outline = outline; + s->black = black; return true; } @@ -143,14 +143,14 @@ static int init(struct module *parent, const char *cfg, void **state) if (cfg && strcasecmp(cfg, "help") == 0) { printf("Blanks specified rectangular area:\n\n"); printf("blank usage:\n"); - printf("\tblank:x:y:widht:height[:outline]\n"); + printf("\tblank:x:y:widht:height[:black]\n"); printf("\t\tor\n"); - printf("\tblank:x%%:y%%:widht%%:height%%[:outline]\n"); + printf("\tblank:x%%:y%%:widht%%:height%%[:black]\n"); printf("\t(all values in pixels)\n"); return 1; } - struct state_blank *s = calloc(1, sizeof(struct state_blank)); + struct state_blank *s = new state_blank(); assert(s); if (cfg) { @@ -158,7 +158,7 @@ static int init(struct module *parent, const char *cfg, void **state) bool ret = parse(s, tmp); free(tmp); if (!ret) { - free(s); + delete s; return -1; } } @@ -173,9 +173,12 @@ static int init(struct module *parent, const char *cfg, void **state) static void done(void *state) { - struct state_blank *s = state; + auto s = (struct state_blank *) state; module_done(&s->mod); - free(state); + + sws_freeContext(s->ctx_downscale); + sws_freeContext(s->ctx_upscale); + delete s; } static void process_message(struct state_blank *s, struct msg_universal *msg) @@ -188,17 +191,63 @@ static void process_message(struct state_blank *s, struct msg_universal *msg) */ static struct video_frame *filter(void *state, struct video_frame *in) { - struct state_blank *s = state; - codec_t codec = in->color_spec; - assert(in->tile_count == 1); - if (s->in_relative_units && !video_desc_eq(s->saved_desc, - video_desc_from_frame(in))) { + auto s = (struct state_blank *) state; + codec_t codec = in->color_spec; + int bpp = get_bpp(codec); + enum AVPixelFormat av_pixfmt = AV_PIX_FMT_NONE; + + if (ug_to_av_pixfmt_map.find(codec) != ug_to_av_pixfmt_map.end()) { + av_pixfmt = ug_to_av_pixfmt_map.at(codec); + } + + if (s->in_relative_units) { s->x = s->x_relative * in->tiles[0].width; s->y = s->y_relative * in->tiles[0].height; s->width = s->width_relative * in->tiles[0].width; + s->width = (s->width + FACTOR - 1) / FACTOR * FACTOR; s->height = s->height_relative * in->tiles[0].height; + } + + int width = s->width; + int height = s->height; + int x = s->x; + int y = s->y; + + x = (x + bpp - 1) / bpp * bpp; + + if (y + height > (int) in->tiles[0].height) { + height = in->tiles[0].height - y; + } + + if (x + width > (int) in->tiles[0].width) { + width = in->tiles[0].width - x; + width = width / FACTOR * FACTOR; + } + + if (!video_desc_eq(s->saved_desc, + video_desc_from_frame(in))) { + + if (av_pixfmt == AV_PIX_FMT_NONE || !sws_isSupportedInput(av_pixfmt) || + !sws_isSupportedOutput(av_pixfmt)) { + fprintf(stderr, "Unable to find suitable pixfmt!\n"); + return in; + } + + sws_freeContext(s->ctx_downscale); + sws_freeContext(s->ctx_upscale); + + s->ctx_downscale = sws_getContext(width, height, av_pixfmt, + width / FACTOR, height / FACTOR, av_pixfmt, SWS_FAST_BILINEAR,0,0,0); + s->ctx_upscale = sws_getContext(width / FACTOR, height / FACTOR, av_pixfmt, + width, height, av_pixfmt, SWS_FAST_BILINEAR,0,0,0); + + if (s->ctx_downscale == NULL || s->ctx_upscale == NULL) { + fprintf(stderr, "Unable to initialize scaling context!"); + return in; + } + s->saved_desc = video_desc_from_frame(in); } @@ -208,51 +257,31 @@ static struct video_frame *filter(void *state, struct video_frame *in) free_message(msg); } - for(int y = s->y; y < s->y + s->height; ++y) { - if(y >= (int) in->tiles[0].height) { - break; - } - unsigned char pattern[4]; + if (width <= 0 || height <= 0) + return in; - memset(pattern, 0, sizeof(pattern)); + int orig_stride = vc_get_linesize(in->tiles[0].width, in->color_spec); + char *orig = in->tiles[0].data + x * bpp + y * orig_stride; + int tmp_stride = vc_get_linesize(width / FACTOR, in->color_spec); + size_t tmp_len = tmp_stride * (height / FACTOR); + uint8_t *tmp = (uint8_t *) malloc(tmp_len); + if (s->black) { if (codec == UYVY) { - pattern[0] = 127; - pattern[1] = 0; - } + unsigned char pattern[] = { 127, 0 }; - int start = s->x * get_bpp(codec); - int length = s->width * get_bpp(codec); - int linesize = vc_get_linesize(in->tiles[0].width, codec); - // following code won't work correctly eg. for v210 - if(start >= linesize) { - return in; - } - if(start + length > linesize) { - length = linesize - start; - } - if (codec == UYVY || codec_is_a_rgb(codec)) { - // bpp should be integer here, so we can afford this - for (int x = start; x < start + length; x += get_bpp(codec)) { - memcpy(in->tiles[0].data + y * linesize + x, pattern, - get_bpp(codec)); - if (x == start && s->outline && - y != s->y && y != s->y + s->height - 1) { - x = start + length - 2 * get_bpp(codec); - } - } - } else { //fallback - if (s->outline && - y != s->y && y != s->y + s->height - 1) { - memset(in->tiles[0].data + y * linesize + start, 0, - get_pf_block_size(codec)); - memset(in->tiles[0].data + y * linesize + start + length - - get_pf_block_size(codec), 0, - get_pf_block_size(codec)); - } else { - memset(in->tiles[0].data + y * linesize + start, 0, length); + for (size_t i = 0; i < tmp_len; i += get_bpp(codec)) { + memcpy(tmp + i, pattern, get_bpp(codec)); } + } else { + memset(tmp, 0, tmp_len); } + } else { + sws_scale(s->ctx_downscale, (uint8_t **) &orig, &orig_stride, 0, height, &tmp, &tmp_stride); } + sws_scale(s->ctx_upscale, &tmp, &tmp_stride, 0, height / FACTOR, (uint8_t **) &orig, &orig_stride); + + free(tmp); + return in; } @@ -263,3 +292,10 @@ struct capture_filter_info capture_filter_blank = { .filter = filter, }; +static void mod_reg(void) __attribute__((constructor)); + +static void mod_reg(void) +{ + register_library("capture_filter_blank", &capture_filter_blank, LIBRARY_CLASS_CAPTURE_FILTER, CAPTURE_FILTER_ABI_VERSION); +} + diff --git a/src/libavcodec_common.h b/src/libavcodec_common.h index 51182ca53..108e3e8a1 100644 --- a/src/libavcodec_common.h +++ b/src/libavcodec_common.h @@ -116,5 +116,33 @@ static bool is420(enum AVPixelFormat pix_fmt) { return false; } +#ifdef __cplusplus +#include +#include "types.h" + +static const std::unordered_map> ug_to_av_pixfmt_map = { + {RGBA, AV_PIX_FMT_RGBA}, + {UYVY, AV_PIX_FMT_UYVY422}, + {YUYV,AV_PIX_FMT_YUYV422}, + //R10k, + //v210, + //DVS10, + //DXT1, + //DXT1_YUV, + //DXT5, + {RGB, AV_PIX_FMT_RGB24}, + // DPX10, + //JPEG, + //RAW, + //H264, + //MJPG, + //VP8, + {BGR, AV_PIX_FMT_BGR24} + //J2K, + +}; + +#endif // __cplusplus + #endif // LIBAVCODEC_COMMON_H_