📄 effects.cpp
字号:
/********************************************************************
********************************************************************/
class Levels : public GenericVideoFilter {
unsigned char map[256], mapchroma[256];
public:
Levels(int in_min, float gamma, int in_max, int out_min, int out_max, PVideoFilter _child)
: GenericVideoFilter(_child)
{
if (gamma <= 0.0)
throw FilterChainError(Sprintf("BrightnessContrastGamma: gamma must be positive"));
gamma = 1/gamma;
int divisor = in_max - in_min + (in_max == in_min);
if (vi.IsYUY2()) {
for (int i=0; i<256; ++i) {
double p = ((i-16)*(255.0/219.0) - in_min) / divisor;
p = pow(min(max(p, 0.0), 1.0), gamma);
p = p * (out_max - out_min) + out_min;
int pp = int(p*(219.0/255.0)+16.5);
map[i] = min(max(pp,16),235);
int q = ((i-128) * (out_max-out_min) + (divisor>>1)) / divisor + 128;
mapchroma[i] = min(max(q,16),235);
// mapchroma[i] = i;
}
} else {
for (int i=0; i<256; ++i) {
double p = (i - in_min) / divisor;
p = pow(min(max(p, 0.0), 1.0), gamma);
p = p * (out_max - out_min) + out_min;
map[i] = PixelClip(int(p+0.5));
}
}
}
void GetFrame(int n, unsigned char* buf) {
child->GetFrame(n, buf);
unsigned char* p = buf;
if (vi.IsYUY2()) {
for (int i=vi.ImageSize()>>1; i; --i) {
p[0] = map[p[0]];
p[1] = mapchroma[p[1]];
p += 2;
}
} else {
for (int i=vi.ImageSize()>>1; i; --i) {
p[0] = map[p[0]];
++p;
}
}
}
static PVideoFilter __cdecl Create(const FilterInfo*, const Arg* args, const char*) {
return new Levels(args[0].integer, args[1].floating_pt, args[2].integer, args[3].integer, args[4].integer, args[5].clip);
}
};
/********************************************************************
********************************************************************/
class AdjustFocus : public GenericVideoFilter {
const int amount;
unsigned char* line;
public:
AdjustFocus(double _amount, PVideoFilter _child)
: GenericVideoFilter(_child), amount(int(32768*pow(2.0, _amount)+0.5)), line(0) {}
void GetFrame(int n, unsigned char* buf) {
if (!line)
line = new unsigned char[vi.RowSize()];
child->GetFrame(n, buf);
const int center_weight = amount*2;
const int outer_weight = 32768-amount;
int row_size = vi.RowSize();
memcpy(line, buf, row_size);
unsigned char* p = buf + row_size;
{
for (int y = vi.height-2; y; --y) {
for (int x = row_size; x; --x) {
unsigned char a = ScaledPixelClip(p[0] * center_weight + (line[x] + p[row_size]) * outer_weight);
line[x] = p[0];
p[0] = a;
++p;
}
}
}
unsigned char* q = buf;
for (int y = vi.height; y; --y) {
if (vi.IsYUY2()) {
unsigned char uv = q[1];
unsigned char yy = q[2];
unsigned char vu = q[3];
q[2] = ScaledPixelClip(q[2] * center_weight + (q[0] + q[4]) * outer_weight);
q += 4;
for (int x = vi.width-4; x; --x) {
unsigned char w = ScaledPixelClip(q[1] * center_weight + (uv + q[5]) * outer_weight);
uv = vu; vu = q[1]; q[1] = w;
unsigned char y = ScaledPixelClip(q[0] * center_weight + (yy + q[2]) * outer_weight);
yy = q[0]; q[0] = y;
q += 2;
}
q[0] = ScaledPixelClip(q[0] * center_weight + (yy + q[2]) * outer_weight);
q += 4;
} else {
unsigned char bb = q[0];
unsigned char gg = q[1];
unsigned char rr = q[2];
q += 3;
for (int x = vi.width-2; x; --x) {
unsigned char b = ScaledPixelClip(q[0] * center_weight + (bb + q[3]) * outer_weight);
bb = q[0]; q[0] = b;
unsigned char g = ScaledPixelClip(q[1] * center_weight + (gg + q[4]) * outer_weight);
gg = q[1]; q[1] = g;
unsigned char r = ScaledPixelClip(q[2] * center_weight + (rr + q[5]) * outer_weight);
rr = q[2]; q[2] = r;
q += 3;
}
q += 3;
}
}
}
static PVideoFilter __cdecl CreateSharpen(const FilterInfo*, const Arg* args, const char*) {
const float amount = args[0].floating_pt;
if (amount < -1.5849625 || amount > 1.0)
throw FilterChainError(Sprintf("Sharpen: argument must be in the range -1.58 to 1.0"));
return new AdjustFocus(amount, args[1].clip);
}
static PVideoFilter __cdecl CreateBlur(const FilterInfo*, const Arg* args, const char*) {
const float amount = args[0].floating_pt;
if (amount < -1.0 || amount > 1.5849625)
throw FilterChainError(Sprintf("Blur: argument must be in the range -1.0 to 1.58"));
return new AdjustFocus(-amount, args[1].clip);
}
};
/********************************************************************
********************************************************************/
class TemporalSoften : public GenericVideoFilter {
const unsigned luma_threshold, chroma_threshold;
const int radius;
unsigned char** source_buffers;
int cur_frame;
void NextFrame();
void PrevFrame();
public:
TemporalSoften(int _radius, unsigned _luma_threshold, unsigned _chroma_threshold, PVideoFilter _child);
void GetFrame(int n, unsigned char* buf);
~TemporalSoften();
static PVideoFilter __cdecl Create(const FilterInfo*, const Arg* args, const char*) {
return new TemporalSoften(args[0].integer, args[1].integer, args[2].integer, args[3].clip);
}
};
class SpatialSoften : public GenericVideoFilter {
const unsigned luma_threshold, chroma_threshold;
const int diameter;
unsigned char* source_buffer;
public:
SpatialSoften(int _radius, unsigned _luma_threshold, unsigned _chroma_threshold, PVideoFilter _child);
void GetFrame(int n, unsigned char* buf);
~SpatialSoften();
static PVideoFilter __cdecl Create(const FilterInfo*, const Arg* args, const char*) {
return new SpatialSoften(args[0].integer, args[1].integer, args[2].integer, args[3].clip);
}
};
static inline IsClose(int a, int b, unsigned threshold) { return (unsigned(a-b+threshold) <= threshold*2); }
void TemporalSoften::NextFrame() {
unsigned char* temp = source_buffers[0];
if (!temp) temp = new unsigned char[vi.ImageSize()];
for (int i=0; i<radius*2; ++i)
source_buffers[i] = source_buffers[i+1];
++cur_frame;
child->GetFrame(cur_frame+radius, source_buffers[radius*2] = temp);
}
void TemporalSoften::PrevFrame() {
unsigned char* temp = source_buffers[radius*2];
if (!temp) temp = new unsigned char[vi.ImageSize()];
for (int i=radius*2; i>0; --i)
source_buffers[i] = source_buffers[i-1];
--cur_frame;
child->GetFrame(cur_frame-radius, source_buffers[0] = temp);
}
TemporalSoften::TemporalSoften(int _radius, unsigned _luma_threshold, unsigned _chroma_threshold, PVideoFilter _child)
: GenericVideoFilter(_child), radius(_radius), luma_threshold(_luma_threshold), chroma_threshold(_chroma_threshold), cur_frame(-32768)
{
if (!vi.IsYUY2())
throw FilterChainError("TemporalSoften: requires YUY2 input");
source_buffers = new unsigned char*[radius*2+1];
memset(source_buffers, 0, (radius*2+1)*sizeof(unsigned char*));
}
TemporalSoften::~TemporalSoften() {
if (source_buffers) {
for (int i=0; i<radius*2+1; ++i)
if (source_buffers[i])
delete[] source_buffers[i];
delete[] source_buffers;
}
}
void TemporalSoften::GetFrame(int n, unsigned char* buf) {
if (n < cur_frame - (radius*2+1) || n > cur_frame + (radius*2+1))
cur_frame = n - (radius*2+1); // this is safe because all buffered frames will be replaced in a moment
if (cur_frame < n) {
while (cur_frame < n)
NextFrame();
} else {
while (cur_frame > n)
PrevFrame();
}
for (int y = 0; y < vi.height; ++y) {
int line = y * vi.RowSize();
#ifdef OLD_TEMPORAL_SOFTEN_METHOD
for (int x = 0; x < vi.width*2; x += 4) {
int cnt1=0, cnt2=0, y1=0, u=0, y2=0, v=0;
int Y1=source_buffers[radius][line+x], U=source_buffers[radius][line+x+1], Y2=source_buffers[radius][line+x+2], V=source_buffers[radius][line+x+3];
for (int a = 0; a <= radius*2; ++a) {
if (IsClose(source_buffers[a][line+x+1], U, chroma_threshold) && IsClose(source_buffers[a][line+x+3], V, chroma_threshold)) {
if (IsClose(source_buffers[a][line+x], Y1, luma_threshold)) {
++cnt1; y1 += source_buffers[a][line+x]; u += source_buffers[a][line+x+1]; v += source_buffers[a][line+x+3];
}
if (IsClose(source_buffers[a][line+x+2], Y2, luma_threshold)) {
++cnt2; y2 += source_buffers[a][line+x+2]; u += source_buffers[a][line+x+1]; v += source_buffers[a][line+x+3];
}
}
}
buf[line+x+0] = (y1+(cnt1>>1)) / cnt1;
buf[line+x+2] = (y2+(cnt2>>1)) / cnt2;
buf[line+x+1] = (u+((cnt1+cnt2)>>1)) / (cnt1+cnt2);
buf[line+x+3] = (v+((cnt1+cnt2)>>1)) / (cnt1+cnt2);
}
#else
for (int x = 0; x < vi.width*2; x += 2) {
int cnt1=0, cnt2=0, yy=0, uv=0;
int YY=source_buffers[radius][line+x], UV=source_buffers[radius][line+x+1];
for (int a = 0; a <= radius*2; ++a) {
if (IsClose(source_buffers[a][line+x], YY, luma_threshold)) {
++cnt1; yy += source_buffers[a][line+x];
}
if (IsClose(source_buffers[a][line+x+1], UV, chroma_threshold)) {
++cnt2; uv += source_buffers[a][line+x+1];
}
}
buf[line+x+0] = (yy+(cnt1>>1)) / cnt1;
buf[line+x+1] = (uv+(cnt2>>1)) / cnt2;
}
#endif
}
}
SpatialSoften::SpatialSoften(int _radius, unsigned _luma_threshold, unsigned _chroma_threshold, PVideoFilter _child)
: GenericVideoFilter(_child), diameter(_radius*2+1), luma_threshold(_luma_threshold),
chroma_threshold(_chroma_threshold), source_buffer(0)
{
if (!vi.IsYUY2())
throw FilterChainError("SpatialSoften: requires YUY2 input");
}
SpatialSoften::~SpatialSoften() {
if (source_buffer)
delete[] source_buffer;
}
void SpatialSoften::GetFrame(int n, unsigned char* buf) {
if (!source_buffer)
source_buffer = new unsigned char[vi.ImageSize()];
child->GetFrame(n, source_buffer);
int row_size = vi.RowSize();
for (int y=0; y<vi.height; ++y) {
const unsigned char* line[65]; // better not make diameter bigger than this...
for (int h=0; h<diameter; ++h)
line[h] = &source_buffer[row_size * min(max(y+h-(diameter>>1), 0), vi.height-1)];
int x;
int edge = (diameter+1) & -4;
for (x=0; x<edge; ++x) // diameter-1 == (diameter>>1) * 2
buf[y*row_size + x] = source_buffer[y*row_size + x];
for (; x < row_size - edge; x+=2) {
int cnt=0, _y=0, _u=0, _v=0;
int xx = x | 3;
int Y = source_buffer[y*row_size + x], U = source_buffer[y*row_size + (x | 3) - 2], V = source_buffer[y*row_size + (x | 3)];
for (int h=0; h<diameter; ++h) {
for (int w = -diameter+1; w < diameter; w += 2) {
int xw = (x+w) | 3;
if (IsClose(line[h][x+w], Y, luma_threshold) && IsClose(line[h][xw-2], U, chroma_threshold) && IsClose(line[h][xw], V, chroma_threshold)) {
++cnt; _y += line[h][x+w]; _u += line[h][xw-2]; _v += line[h][xw];
}
}
}
buf[y*row_size + x] = (_y + (cnt>>1)) / cnt;
if (!(x&3)) {
buf[y*row_size + x+1] = (_u + (cnt>>1)) / cnt;
buf[y*row_size + x+3] = (_v + (cnt>>1)) / cnt;
}
}
for (; x<row_size; ++x)
buf[y*row_size + x] = source_buffer[y*row_size + x];
}
}
FilterInfo effects_filters[] = {
{ "VerticalReduceBy2", "c", VerticalReduceBy2::Create },
{ "HorizontalReduceBy2", "c", HorizontalReduceBy2::Create },
{ "ReduceBy2", "c", Create_ReduceBy2 },
{ "Levels", "ifiiic", Levels::Create },
{ "Blur", "fc", AdjustFocus::CreateBlur },
{ "Sharpen", "fc", AdjustFocus::CreateSharpen },
{ "BilinearResize", "iic", Create_BilinearResize },
{ "BilinearResize", "ffffiic", Create_BilinearResize },
{ "BicubicResize", "iic", Create_BicubicResize },
{ "BicubicResize", "ffiic", Create_BicubicResizeBC },
{ "BicubicResize", "ffffiic", Create_BicubicResize },
{ "BicubicResize", "ffffffiic", Create_BicubicResizeBC },
{ "Bob", "c", Create_Bob },
{ "Bob", "ffc", Create_Bob },
{ "Crop", "iiiic", Crop::Create },
{ "CropBottom", "ic", CropBottom::Create },
{ "AddBorders", "iiiic", AddBorders::Create },
{ "Letterbox", "iic", Letterbox::Create },
{ "FixLuminance", "ifc", FixLuminance::Create },
{ "PeculiarBlend", "ic", PeculiarBlend::Create },
{ "TemporalSoften", "iiic", TemporalSoften::Create },
{ "SpatialSoften", "iiic", SpatialSoften::Create },
{ 0,0,0 }
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -