hi all, all things I said for filter_facemask can be applied now too.
greetings, branko kokanovic
Index: filter/filter_xsharpen.c =================================================================== RCS file: /cvstc/transcode/filter/filter_xsharpen.c,v retrieving revision 1.25 diff -u -r1.25 filter_xsharpen.c --- filter/filter_xsharpen.c 29 Sep 2006 17:34:44 -0000 1.25 +++ filter/filter_xsharpen.c 29 Jul 2007 18:20:47 -0000 @@ -1,9 +1,9 @@ /* - filter_xsharpen.c + filter_xsharpen.c -- VirtualDub's XSharpen Filter Copyright (C) 1999-2000 Donald A. Graft modified 2002 by Tilmann Bitterberg for use with transcode - + modified 2007 by Branko Kokanovic <branko.kokanovic at gmail dot com> to use NMS This file is part of transcode, a video stream processing tool Xsharpen Filter for VirtualDub -- sharpen by mapping pixels @@ -29,17 +29,27 @@ */ #define MOD_NAME "filter_xharpen.so" -#define MOD_VERSION "(1.0b2) (2003-02-12)" +#define MOD_VERSION "(1.0b3) (2007-07-29)" #define MOD_CAP "VirtualDub's XSharpen Filter" #define MOD_AUTHOR "Donald Graft, Tilmann Bitterberg" +#define MOD_FEATURES \ + TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO +#define MOD_FLAGS \ + TC_MODULE_FLAG_RECONFIGURABLE + +/* ------------------------------------------------- + * + * mandatory include files + * + *-------------------------------------------------*/ #include "transcode.h" #include "filter.h" #include "libtc/libtc.h" #include "libtc/optstr.h" +#include "libtc/tcmodule-plugin.h" #include "aclib/imgconvert.h" -static vob_t *vob=NULL; /* vdub compat */ typedef unsigned int Pixel; @@ -49,571 +59,698 @@ typedef int PixDim; typedef int PixOffset; -/////////////////////////////////////////////////////////////////////////// +static const char xsharpen_help[] = "" + "Overview\n" + " This filter performs a subtle but useful sharpening effect. The\n" + " result is a sharpening effect that not only avoids amplifying\n" + " noise, but also tends to reduce it. A welcome side effect is that\n" + " files processed with this filter tend to compress to smaller files.\n" + "\n" + "Options\n" + " Strength 'strength' (0-255) [200]\n" + " When this value is 255, mapped pixels are not blended with the\n" + " original pixel values, so a full-strength effect is obtained. As\n" + " the value is reduced, each mapped pixel is blended with more of the\n" + " original pixel. At a value of 0, the original pixels are passed\n" + " through and there is no sharpening effect.\n" + "\n" + " Threshold 'threshold' (0-255) [255]\n" + " This value determines how close a pixel must be to the brightest or\n" + " dimmest pixel to be mapped. If a pixel is more than threshold away\n" + " from the brightest or dimmest pixel, it is not mapped. Thus, as\n" + " the threshold is reduced, pixels in the mid range start to be\n" + " spared.\n"; + +/*************************************************************************/ typedef struct MyFilterData { - Pixel32 *convertFrameIn; - Pixel32 *convertFrameOut; - int strength; - int strengthInv; - int threshold; - int srcPitch; - int dstPitch; - TCVHandle tcvhandle; + Pixel32 *convertFrameIn; + Pixel32 *convertFrameOut; + int strength; + int strengthInv; + int threshold; + int srcPitch; + int dstPitch; + int codec; + TCVHandle tcvhandle; + char conf_str[TC_BUF_MIN]; } MyFilterData; -static MyFilterData *mfd; +/*************************************************************************/ + +/* Module interface routines and data. */ + +/*************************************************************************/ + +/** + * xsharpen_init: Initialize this instance of the module. See + * tcmodule-data.h for function details. + */ -static void help_optstr(void) +static int xsharpen_init(TCModuleInstance *self, uint32_t features) { - tc_log_info (MOD_NAME, "(%s) help\n" -"* Overview\n" -" This filter performs a subtle but useful sharpening effect. The\n" -" result is a sharpening effect that not only avoids amplifying\n" -" noise, but also tends to reduce it. A welcome side effect is that\n" -" files processed with this filter tend to compress to smaller files.\n" -"\n" -"* Options\n" -" * Strength 'strength' (0-255) [200]\n" -" When this value is 255, mapped pixels are not blended with the\n" -" original pixel values, so a full-strength effect is obtained. As\n" -" the value is reduced, each mapped pixel is blended with more of the\n" -" original pixel. At a value of 0, the original pixels are passed\n" -" through and there is no sharpening effect.\n" -"\n" -" * Threshold 'threshold' (0-255) [255]\n" -" This value determines how close a pixel must be to the brightest or\n" -" dimmest pixel to be mapped. If a pixel is more than threshold away\n" -" from the brightest or dimmest pixel, it is not mapped. Thus, as\n" -" the threshold is reduced, pixels in the mid range start to be\n" -" spared.\n" - , MOD_CAP); + MyFilterData *mfd = NULL; + + TC_MODULE_SELF_CHECK(self, "init"); + TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); + + mfd = tc_malloc(sizeof(MyFilterData)); + if (!mfd) { + tc_log_error(MOD_NAME, "init: out of memory!"); + return TC_ERROR; + } + self->userdata = mfd; + + /* initialize data */ + mfd->strength = 200; /* 255 is too much */ + mfd->strengthInv = 255 - mfd->strength; + mfd->threshold = 255; + mfd->srcPitch = 0; + mfd->dstPitch = 0; + mfd->convertFrameIn = NULL; + mfd->convertFrameOut= NULL; + + return TC_OK; } -int tc_filter(frame_list_t *ptr_, char *options) +/*************************************************************************/ + +/** + * xsharpen_fini: Clean up after this instance of the module. See + * tcmodule-data.h for function details. + */ + +static int xsharpen_fini(TCModuleInstance *self) { - vframe_list_t *ptr = (vframe_list_t *)ptr_; + MyFilterData *mfd = NULL; + + TC_MODULE_SELF_CHECK(self, "fini"); + + mfd = self->userdata; + + if (mfd->convertFrameIn) + tc_free(mfd->convertFrameIn); + mfd->convertFrameIn = NULL; + + if (mfd->convertFrameOut) + tc_free(mfd->convertFrameOut); + mfd->convertFrameOut = NULL; + + if (mfd->tcvhandle){ + tcv_free(mfd->tcvhandle); + } + mfd->tcvhandle = 0; - //---------------------------------- - // - // filter init - // - //---------------------------------- + tc_free(self->userdata); + self->userdata = NULL; + return TC_OK; +} + +/*************************************************************************/ - if(ptr->tag & TC_FILTER_INIT) { +/** + * xsharpen_configure: Configure this instance of the module. See + * tcmodule-data.h for function details. + */ +static int xsharpen_configure(TCModuleInstance *self, + const char *options, vob_t *vob) +{ + MyFilterData *mfd = NULL; int width, height; - if((vob = tc_get_vob())==NULL) return(-1); + TC_MODULE_SELF_CHECK(self, "configure"); - mfd = tc_malloc(sizeof(MyFilterData)); + mfd = self->userdata; - if (!mfd) { - tc_log_error(MOD_NAME, "No memory at %d!", __LINE__); - return (-1); - } + if(vob == NULL){ + return TC_ERROR; + } height = vob->ex_v_height; width = vob->ex_v_width; - /* default values */ - mfd->strength = 200; /* 255 is too much */ - mfd->strengthInv = 255 - mfd->strength; - mfd->threshold = 255; - mfd->srcPitch = 0; - mfd->dstPitch = 0; + /* setup defaults */ + mfd->codec = vob->im_v_codec; + mfd->strength = 200; /* 255 is too much */ + mfd->strengthInv = 255 - mfd->strength; + mfd->threshold = 255; + mfd->srcPitch = 0; + mfd->dstPitch = 0; - if (options != NULL) { + if (options) { + if (verbose >= TC_STATS) { + tc_log_info(MOD_NAME, "options=%s", options); + } + optstr_get (options, "strength", "%d", &mfd->strength); + optstr_get (options, "threshold", "%d", &mfd->threshold); + } + mfd->strengthInv = 255 - mfd->strength; - if(verbose) tc_log_info(MOD_NAME, "options=%s", options); + if (verbose > TC_INFO) { + tc_log_info (MOD_NAME, " XSharpen Filter Settings (%dx%d):", width,height); + tc_log_info (MOD_NAME, " strength = %d", mfd->strength); + tc_log_info (MOD_NAME, " threshold = %d", mfd->threshold); + } - optstr_get (options, "strength", "%d", &mfd->strength); - optstr_get (options, "threshold", "%d", &mfd->threshold); + /* fetch memory */ + mfd->convertFrameIn = tc_malloc (width*height*sizeof(Pixel32)); + if (!mfd->convertFrameIn) { + tc_log_error(MOD_NAME, "No memory at %d!", __LINE__); + return TC_ERROR; + } + memset(mfd->convertFrameIn, 0, width*height*sizeof(Pixel32)); - } + mfd->convertFrameOut = tc_malloc (width*height*sizeof(Pixel32)); + if (!mfd->convertFrameOut) { + tc_log_error(MOD_NAME, "No memory at %d!", __LINE__); + return TC_ERROR; + } + memset(mfd->convertFrameOut, 0, width*height*sizeof(Pixel32)); - mfd->strengthInv = 255 - mfd->strength; + mfd->tcvhandle = tcv_init(); - if (verbose > 1) { + /* filter init ok */ + if (verbose) { + tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); + } - tc_log_info (MOD_NAME, " XSharpen Filter Settings (%dx%d):", width,height); - tc_log_info (MOD_NAME, " strength = %d", mfd->strength); - tc_log_info (MOD_NAME, " threshold = %d", mfd->threshold); - } + return TC_OK; +} - if (options) - if ( optstr_lookup(options, "help") != NULL) { - help_optstr(); - } +/*************************************************************************/ - /* fetch memory */ +/** + * xsharpen_stop: Reset this instance of the module. See tcmodule-data.h + * for function details. + */ - mfd->convertFrameIn = tc_malloc (width*height*sizeof(Pixel32)); - if (!mfd->convertFrameIn) { - tc_log_error(MOD_NAME, "No memory at %d!", __LINE__); - return (-1); - } - memset(mfd->convertFrameIn, 0, width*height*sizeof(Pixel32)); +static int xsharpen_stop(TCModuleInstance *self) +{ + TC_MODULE_SELF_CHECK(self, "stop"); + return TC_OK; +} - mfd->convertFrameOut = tc_malloc (width*height*sizeof(Pixel32)); - if (!mfd->convertFrameOut) { - tc_log_error(MOD_NAME, "No memory at %d!", __LINE__); - return (-1); - } - memset(mfd->convertFrameOut, 0, width*height*sizeof(Pixel32)); +/*************************************************************************/ - mfd->tcvhandle = tcv_init(); +/** + * xsharpen_inspect: Return the value of an option in this instance of + * the module. See tcmodule-data.h for function details. + */ - // filter init ok. - if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); +static int xsharpen_inspect(TCModuleInstance *self, + const char *param, const char **value) +{ + MyFilterData *mfd = NULL; - return 0; + TC_MODULE_SELF_CHECK(self, "inspect"); + TC_MODULE_SELF_CHECK(param, "inspect"); + TC_MODULE_SELF_CHECK(value, "inspect"); - } /* TC_FILTER_INIT */ + mfd = self->userdata; + if (optstr_lookup(param, "help")) { + *value = xsharpen_help; + } + if (optstr_lookup(param, "strength")) { + tc_snprintf(mfd->conf_str, sizeof(mfd->conf_str),"ypos=%d",mfd->strength); + *value = mfd->conf_str; + } + if (optstr_lookup(param, "threshold")) { + tc_snprintf(mfd->conf_str, sizeof(mfd->conf_str),"ypos=%d",mfd->threshold); + *value = mfd->conf_str; + } - if(ptr->tag & TC_FILTER_GET_CONFIG) { - if (options) { - char buf[256]; - optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VRYO", "1"); - tc_snprintf (buf, sizeof(buf), "%d", mfd->strength); - optstr_param (options, "strength", "How much of the effect", "%d", buf, "0", "255"); - - tc_snprintf (buf, sizeof(buf), "%d", mfd->threshold); - optstr_param (options, "threshold", - "How close a pixel must be to the brightest or dimmest pixel to be mapped", - "%d", buf, "0", "255"); - } - } - - - if(ptr->tag & TC_FILTER_CLOSE) { - - if (mfd->convertFrameIn) - free (mfd->convertFrameIn); - mfd->convertFrameIn = NULL; - - if (mfd->convertFrameOut) - free (mfd->convertFrameOut); - mfd->convertFrameOut = NULL; - - tcv_free(mfd->tcvhandle); - mfd->tcvhandle = 0; - - if (mfd) - free(mfd); - mfd = NULL; - - return 0; - - } /* TC_FILTER_CLOSE */ - -/////////////////////////////////////////////////////////////////////////// - - if(ptr->tag & TC_POST_M_PROCESS && ptr->tag & TC_VIDEO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) { - - if (vob->im_v_codec == CODEC_RGB) { - const PixDim width = ptr->v_width; - const PixDim height = ptr->v_height; - Pixel32 *src, *dst; - int x, y; - int r, g, b, R, G, B; - Pixel32 p, min=1000, max=-1; - int luma, lumac, lumamax, lumamin, mindiff, maxdiff; - const int srcpitch = ptr->v_width*sizeof(Pixel32); - const int dstpitch = ptr->v_width*sizeof(Pixel32); - - Pixel32 * dst_buf; - Pixel32 * src_buf; - - tcv_convert(mfd->tcvhandle, ptr->video_buf, - (uint8_t *)mfd->convertFrameIn, - ptr->v_width, ptr->v_height, IMG_RGB24, IMG_BGRA32); - - src_buf = mfd->convertFrameIn; - dst_buf = mfd->convertFrameOut; - - /* First copy through the four border lines. */ - src = src_buf; - dst = dst_buf; - for (x = 0; x < width; x++) - { - dst[x] = src[x]; - } - src = (Pixel *)((char *)src_buf + (height - 1) * srcpitch); - dst = (Pixel *)((char *)dst_buf + (height - 1) * dstpitch); - for (x = 0; x < width; x++) - { - dst[x] = src[x]; - } - src = src_buf; - dst = dst_buf; - for (y = 0; y < height; y++) - { - dst[0] = src[0]; - dst[width-1] = src[width-1]; - src = (Pixel *)((char *)src + srcpitch); - dst = (Pixel *)((char *)dst + dstpitch); - } - - /* Now calculate and store the pixel luminances for the remaining pixels. */ - src = src_buf; - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - r = (src[x] >> 16) & 0xff; - g = (src[x] >> 8) & 0xff; - b = src[x] & 0xff; - luma = (55 * r + 182 * g + 19 * b) >> 8; - src[x] &= 0x00ffffff; - src[x] |= (luma << 24); - } - src = (Pixel *)((char *)src + srcpitch); - } - - /* Finally run the 3x3 rank-order sharpening kernel over the pixels. */ - src = (Pixel *)((char *)src_buf + srcpitch); - dst = (Pixel *)((char *)dst_buf + dstpitch); - for (y = 1; y < height - 1; y++) - { - for (x = 1; x < width - 1; x++) - { - /* Find the brightest and dimmest pixels in the 3x3 window - surrounding the current pixel. */ - lumamax = -1; - lumamin = 1000; - - p = ((Pixel32 *)((char *)src - srcpitch))[x-1]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = ((Pixel32 *)((char *)src - srcpitch))[x]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = ((Pixel32 *)((char *)src - srcpitch))[x+1]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = src[x-1]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = src[x]; - lumac = luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = src[x+1]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = ((Pixel32 *)((char *)src + srcpitch))[x-1]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = ((Pixel32 *)((char *)src + srcpitch))[x]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - p = ((Pixel32 *)((char *)src + srcpitch))[x+1]; - luma = p >> 24; - if (luma > lumamax) - { - lumamax = luma; - max = p; - } - if (luma < lumamin) - { - lumamin = luma; - min = p; - } - - /* Determine whether the current pixel is closer to the - brightest or the dimmest pixel. Then compare the current - pixel to that closest pixel. If the difference is within - threshold, map the current pixel to the closest pixel; - otherwise pass it through. */ - p = -1; - if (mfd->strength != 0) - { - mindiff = lumac - lumamin; - maxdiff = lumamax - lumac; - if (mindiff > maxdiff) - { - if (maxdiff < mfd->threshold) - { - p = max; - } - } - else - { - if (mindiff < mfd->threshold) - { - p = min; - } - } - } - if (p == -1) - { - dst[x] = src[x]; - } - else - { - - R = (src[x] >> 16) & 0xff; - G = (src[x] >> 8) & 0xff; - B = src[x] & 0xff; - r = (p >> 16) & 0xff; - g = (p >> 8) & 0xff; - b = p & 0xff; - r = (mfd->strength * r + mfd->strengthInv * R) / 255; - g = (mfd->strength * g + mfd->strengthInv * G) / 255; - b = (mfd->strength * b + mfd->strengthInv * B) / 255; - dst[x] = (r << 16) | (g << 8) | b; - } - } - src = (Pixel *)((char *)src + srcpitch); - dst = (Pixel *)((char *)dst + dstpitch); - } - - tcv_convert(mfd->tcvhandle, (uint8_t *)mfd->convertFrameOut, - ptr->video_buf, ptr->v_width, ptr->v_height, - IMG_BGRA32, IMG_RGB24); - - return 0; - } - - - if (vob->im_v_codec == CODEC_YUV) { - - const PixDim width = ptr->v_width; - const PixDim height = ptr->v_height; - char *src, *dst; - int x, y; - int luma, lumac, lumamax, lumamin; - int p, mindiff, maxdiff; - const int srcpitch = ptr->v_width; - const int dstpitch = ptr->v_width; - - char * src_buf = ptr->video_buf; - static char * dst_buf = NULL; - - if (!dst_buf) - dst_buf = tc_malloc (width*height*3/2); - - /* First copy through the four border lines. */ - /* first */ - src = src_buf; - dst = dst_buf; - ac_memcpy (dst, src, width); - - /* last */ - src = src_buf+srcpitch*(height-1); - dst = dst_buf+dstpitch*(height-1); - ac_memcpy (dst, src, width); - - /* copy Cb and Cr */ - ac_memcpy (dst_buf+dstpitch*height, src_buf+srcpitch*height, width*height>>1); - - src = src_buf; - dst = dst_buf; - for (y = 0; y < height; y++) - { - *dst = *src; - *(dst+width-1) = *(src+width-1); - dst += dstpitch; - src += srcpitch; - } - - src = src_buf+srcpitch; - dst = dst_buf+dstpitch; - - /* Finally run the 3x3 rank-order sharpening kernel over the pixels. */ - for (y = 1; y < height - 1; y++) - { - for (x = 1; x < width - 1; x++) - { - /* Find the brightest and dimmest pixels in the 3x3 window - surrounding the current pixel. */ - lumamax = -1000; - lumamin = 1000; - - luma = (src - srcpitch)[x-1] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = (src - srcpitch)[x] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = (src - srcpitch)[x+1] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = src[x-1] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = src[x] &0xff; - lumac = luma; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = src[x+1] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = (src + srcpitch)[x-1] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = (src + srcpitch)[x] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - luma = (src + srcpitch)[x+1] &0xff; - if (luma > lumamax) - lumamax = luma; - if (luma < lumamin) - lumamin = luma; - - /* Determine whether the current pixel is closer to the - brightest or the dimmest pixel. Then compare the current - pixel to that closest pixel. If the difference is within - threshold, map the current pixel to the closest pixel; - otherwise pass it through. */ - - p = -1; - if (mfd->strength != 0) - { - mindiff = lumac - lumamin; - maxdiff = lumamax - lumac; - if (mindiff > maxdiff) - { - if (maxdiff < mfd->threshold) - p = lumamax&0xff; - } - else - { - if (mindiff < mfd->threshold) - p = lumamin&0xff; - } - } - if (p == -1) - { - dst[x] = src[x]; - } - else - { - int t; - lumac = src[x] &0xff; - t = ((mfd->strength*p + mfd->strengthInv*lumac)/255) & 0xff; - if (t>240) t = 240; - if (t<16) t = 16; - dst[x] = t&0xff; - - } - } - src += srcpitch; - dst += dstpitch; - } - - ac_memcpy (ptr->video_buf, dst_buf, width*height*3/2); - - return 0; - - } - } - return 0; + return TC_OK; } +/*************************************************************************/ + +/** + * xsharpen_filter_video: show something on given frame of the video + * stream. See tcmodule-data.h for function details. + */ + +static int xsharpen_filter_video(TCModuleInstance *self, vframe_list_t *frame) +{ + MyFilterData *mfd = NULL; + int post = 0; + + TC_MODULE_SELF_CHECK(self, "filer_video"); + TC_MODULE_SELF_CHECK(frame, "filer_video"); + + mfd = self->userdata; + post = (frame->tag & TC_POST_M_PROCESS); + + if(post && !(frame->attributes & TC_FRAME_IS_SKIPPED)) { + if (mfd->codec == CODEC_RGB) { + const PixDim width = frame->v_width; + const PixDim height = frame->v_height; + Pixel32 *src, *dst; + int x, y; + int r, g, b, R, G, B; + Pixel32 p, min=1000, max=-1; + int luma, lumac, lumamax, lumamin, mindiff, maxdiff; + const int srcpitch = frame->v_width*sizeof(Pixel32); + const int dstpitch = frame->v_width*sizeof(Pixel32); + + Pixel32 * dst_buf; + Pixel32 * src_buf; + + tcv_convert(mfd->tcvhandle, frame->video_buf, + (uint8_t *)mfd->convertFrameIn, frame->v_width, frame->v_height, + IMG_RGB24, IMG_BGRA32); + + src_buf = mfd->convertFrameIn; + dst_buf = mfd->convertFrameOut; + + /* First copy through the four border lines. */ + src = src_buf; + dst = dst_buf; + for (x = 0; x < width; x++){ + dst[x] = src[x]; + } + src = (Pixel *)((char *)src_buf + (height - 1) * srcpitch); + dst = (Pixel *)((char *)dst_buf + (height - 1) * dstpitch); + for (x = 0; x < width; x++){ + dst[x] = src[x]; + } + src = src_buf; + dst = dst_buf; + for (y = 0; y < height; y++){ + dst[0] = src[0]; + dst[width-1] = src[width-1]; + src = (Pixel *)((char *)src + srcpitch); + dst = (Pixel *)((char *)dst + dstpitch); + } + + /* Now calculate and store the pixel luminances for the remaining pixels. */ + src = src_buf; + for (y = 0; y < height; y++){ + for (x = 0; x < width; x++){ + r = (src[x] >> 16) & 0xff; + g = (src[x] >> 8) & 0xff; + b = src[x] & 0xff; + luma = (55 * r + 182 * g + 19 * b) >> 8; + src[x] &= 0x00ffffff; + src[x] |= (luma << 24); + } + src = (Pixel *)((char *)src + srcpitch); + } + + /* Finally run the 3x3 rank-order sharpening kernel over the pixels. */ + src = (Pixel *)((char *)src_buf + srcpitch); + dst = (Pixel *)((char *)dst_buf + dstpitch); + for (y = 1; y < height - 1; y++){ + for (x = 1; x < width - 1; x++){ + /* Find the brightest and dimmest pixels in the 3x3 window + surrounding the current pixel. */ + lumamax = -1; + lumamin = 1000; + + p = ((Pixel32 *)((char *)src - srcpitch))[x-1]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src - srcpitch))[x]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src - srcpitch))[x+1]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = src[x-1]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = src[x]; + lumac = luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = src[x+1]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src + srcpitch))[x-1]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src + srcpitch))[x]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src + srcpitch))[x+1]; + luma = p >> 24; + if (luma > lumamax){ + lumamax = luma; + max = p; + } + if (luma < lumamin){ + lumamin = luma; + min = p; + } + + /* Determine whether the current pixel is closer to the + brightest or the dimmest pixel. Then compare the current + pixel to that closest pixel. If the difference is within + threshold, map the current pixel to the closest pixel; + otherwise pass it through. */ + p = -1; + if (mfd->strength != 0){ + mindiff = lumac - lumamin; + maxdiff = lumamax - lumac; + if (mindiff > maxdiff){ + if (maxdiff < mfd->threshold){ + p = max; + } + }else{ + if (mindiff < mfd->threshold){ + p = min; + } + } + } + if (p == -1){ + dst[x] = src[x]; + }else{ + R = (src[x] >> 16) & 0xff; + G = (src[x] >> 8) & 0xff; + B = src[x] & 0xff; + r = (p >> 16) & 0xff; + g = (p >> 8) & 0xff; + b = p & 0xff; + r = (mfd->strength * r + mfd->strengthInv * R) / 255; + g = (mfd->strength * g + mfd->strengthInv * G) / 255; + b = (mfd->strength * b + mfd->strengthInv * B) / 255; + dst[x] = (r << 16) | (g << 8) | b; + } + } + src = (Pixel *)((char *)src + srcpitch); + dst = (Pixel *)((char *)dst + dstpitch); + } + + tcv_convert(mfd->tcvhandle, (uint8_t *)mfd->convertFrameOut, + frame->video_buf, frame->v_width, frame->v_height, + IMG_BGRA32, IMG_RGB24); + + return TC_OK; + } + if (mfd->codec == CODEC_YUV) { + const PixDim width = frame->v_width; + const PixDim height = frame->v_height; + char *src, *dst; + int x, y; + int luma, lumac, lumamax, lumamin; + int p, mindiff, maxdiff; + const int srcpitch = frame->v_width; + const int dstpitch = frame->v_width; + + char * src_buf = frame->video_buf; + static char * dst_buf = NULL; + + if (!dst_buf){ + dst_buf = tc_malloc (width*height*3/2); + } + + /* First copy through the four border lines. */ + /* first */ + src = src_buf; + dst = dst_buf; + ac_memcpy (dst, src, width); + + /* last */ + src = src_buf+srcpitch*(height-1); + dst = dst_buf+dstpitch*(height-1); + ac_memcpy (dst, src, width); + + /* copy Cb and Cr */ + ac_memcpy (dst_buf+dstpitch*height, src_buf+srcpitch*height, width*height>>1); + + src = src_buf; + dst = dst_buf; + for (y = 0; y < height; y++){ + *dst = *src; + *(dst+width-1) = *(src+width-1); + dst += dstpitch; + src += srcpitch; + } + + src = src_buf+srcpitch; + dst = dst_buf+dstpitch; + + /* Finally run the 3x3 rank-order sharpening kernel over the pixels. */ + for (y = 1; y < height - 1; y++){ + for (x = 1; x < width - 1; x++){ + /* Find the brightest and dimmest pixels in the 3x3 window + surrounding the current pixel. */ + lumamax = -1000; + lumamin = 1000; + + luma = (src - srcpitch)[x-1] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + + luma = (src - srcpitch)[x] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + luma = (src - srcpitch)[x+1] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + + luma = src[x-1] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + luma = src[x] &0xff; + lumac = luma; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + + luma = src[x+1] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + + luma = (src + srcpitch)[x-1] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + + luma = (src + srcpitch)[x] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + + luma = (src + srcpitch)[x+1] &0xff; + if (luma > lumamax) + lumamax = luma; + if (luma < lumamin) + lumamin = luma; + + /* Determine whether the current pixel is closer to the + brightest or the dimmest pixel. Then compare the current + pixel to that closest pixel. If the difference is within + threshold, map the current pixel to the closest pixel; + otherwise pass it through. */ + + p = -1; + if (mfd->strength != 0){ + mindiff = lumac - lumamin; + maxdiff = lumamax - lumac; + if (mindiff > maxdiff){ + if (maxdiff < mfd->threshold) + p = lumamax&0xff; + }else{ + if (mindiff < mfd->threshold) + p = lumamin&0xff; + } + } + if (p == -1){ + dst[x] = src[x]; + }else{ + int t; + lumac = src[x] &0xff; + t = ((mfd->strength*p + mfd->strengthInv*lumac)/255) & 0xff; + if (t>240) t = 240; + if (t<16) t = 16; + dst[x] = t&0xff; + } + } + src += srcpitch; + dst += dstpitch; + } + + ac_memcpy (frame->video_buf, dst_buf, width*height*3/2); + return TC_OK; + } + } + return TC_OK; +} + +/*************************************************************************/ + +static const TCCodecID xsharpen_codecs_in[] = { + TC_CODEC_RGB, TC_CODEC_YUV420P, TC_CODEC_ERROR +}; +static const TCCodecID xsharpen_codecs_out[] = { + TC_CODEC_RGB, TC_CODEC_YUV420P, TC_CODEC_ERROR +}; +static const TCFormatID xsharpen_formats[] = { + TC_FORMAT_ERROR +}; + +static const TCModuleInfo xsharpen_info = { + .features = MOD_FEATURES, + .flags = MOD_FLAGS, + .name = MOD_NAME, + .version = MOD_VERSION, + .description = MOD_CAP, + .codecs_in = xsharpen_codecs_in, + .codecs_out = xsharpen_codecs_out, + .formats_in = xsharpen_formats, + .formats_out = xsharpen_formats +}; + +static const TCModuleClass xsharpen_class = { + .info = &xsharpen_info, + + .init = xsharpen_init, + .fini = xsharpen_fini, + .configure = xsharpen_configure, + .stop = xsharpen_stop, + .inspect = xsharpen_inspect, + + .filter_video = xsharpen_filter_video +}; + +extern const TCModuleClass *tc_plugin_setup(void) +{ + return &xsharpen_class; +} + +/*************************************************************************/ + +static int xsharpen_get_config(TCModuleInstance *self, char *options) +{ + MyFilterData *mfd = NULL; + char buf[TC_BUF_MIN]; + + TC_MODULE_SELF_CHECK(self, "get_config"); + + mfd = self->userdata; + + optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION, + MOD_AUTHOR, "VRYO", "1"); + + /* can be omitted */ + optstr_param (options, "help", "VirtualDub's XSharpen Filter", "", "0"); + + tc_snprintf (buf, sizeof(buf), "%d", mfd->strength); + optstr_param (options, "strength", "How much of the effect", "%d", buf, "0", "255"); + + tc_snprintf (buf, sizeof(buf), "%d", mfd->threshold); + optstr_param (options, "threshold", + "How close a pixel must be to the brightest or dimmest pixel to be mapped", + "%d", buf, "0", "255"); + + return TC_OK; +} + + +static int xsharpen_process(TCModuleInstance *self, + frame_list_t *frame) +{ + TC_MODULE_SELF_CHECK(self, "process"); + + if (frame->tag & TC_VIDEO) { + return xsharpen_filter_video(self, (vframe_list_t*)frame); + } + return TC_OK; +} + +/*************************************************************************/ + +/* Old-fashioned module interface. */ + +TC_FILTER_OLDINTERFACE(xsharpen) + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */