📄 tdeinterlace.cpp
字号:
/*
** TDeinterlace v1.0b4 for AviSynth 2.5.x
**
** TDeinterlace is a bi-directionally motion adaptive deinterlacer.
** It also uses a couple modified forms of ela interpolation which
** help to reduce "jaggy" edges in places where interpolation must
** be used. TDeinterlace currently supports YV12 and YUY2 colorspaces.
**
** Copyright (C) 2004-2005 Kevin Stone
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "TDeinterlace.h"
PVideoFrame __stdcall TDeinterlace::GetFrame(int n, IScriptEnvironment* env)
{
if (n < 0) n = 0;
else if (mode == 0 && n > nfrms) n = nfrms;
else if (mode == 1 && n > nfrms2) n = nfrms2;
if (vi.IsYV12()) return(GetFrameYV12(n, env));
else return(GetFrameYUY2(n, env));
}
int TDeinterlace::getHint(PVideoFrame &src, unsigned int &storeHint, int &hintField)
{
hintField = -1;
const unsigned char *p = src->GetReadPtr(PLANAR_Y);
unsigned int i, magic_number = 0, hint = 0;
storeHint = 0xFFFFFFFF;
for (i=0; i<32; ++i)
{
magic_number |= ((*p++ & 1) << i);
}
if (magic_number != 0xdeadbeef && magic_number != 0xdeadfeed) return -1;
for (i=0; i<32; ++i)
{
hint |= ((*p++ & 1) << i);
}
if (magic_number == 0xdeadbeef && hint&0xFFFFFF00) return -1;
if (magic_number == 0xdeadfeed && hint&0xFFFFFF00) return -1;
storeHint = hint;
if (magic_number == 0xdeadbeef)
{
storeHint |= 0x00100000;
if (hint&0x00000001) return 0;
return 1;
}
if (hint&0x00000008) hintField = 1;
else hintField = 0;
if (hint&0x00000010) return 1;
return 0;
}
void TDeinterlace::putHint(PVideoFrame &src, unsigned int hint, int fieldt)
{
int type = hint&0x00100000 ? 0 : 1;
hint &= ~0x00100000;
if (hint&0xFFFFFF00) return;
if (type == 1)
{
hint &= 0x00000020;
if (fieldt == 1) hint |= 0x0000000E;
else hint |= 0x00000005;
}
unsigned char *p = src->GetWritePtr(PLANAR_Y);
unsigned int i;
for (i=0; i<32; ++i)
{
*p &= ~1;
if (type == 0) *p++ |= ((0xdeadbeef & (1 << i)) >> i);
else *p++ |= ((0xdeadfeed & (1 << i)) >> i);
}
for (i=0; i<32; ++i)
{
*p &= ~1;
*p++ |= ((hint & (1 << i)) >> i);
}
}
TDeinterlace::TDeinterlace(PClip _child, int _mode, int _order, int _field, int _mthreshL,
int _mthreshC, int _map, const char* _ovr, int _ovrDefault, int _type, bool _debug,
int _mtnmode, bool _sharp, bool _hints, PClip _clip2, bool _full, int _cthresh,
bool _chroma, int _MI, bool _tryWeave, int _link, bool _denoise, int _AP,
int _blockx, int _blocky, int _APType, IScriptEnvironment* env) :
GenericVideoFilter(_child), mode(_mode), order(_order), field(_field), mthreshL(_mthreshL),
mthreshC(_mthreshC), map(_map), ovr(_ovr), ovrDefault(_ovrDefault), type(_type),
debug(_debug), mtnmode(_mtnmode), sharp(_sharp), hints(_hints), clip2(_clip2), full(_full),
cthresh(_cthresh), chroma(_chroma), MI(_MI), tryWeave(_tryWeave), link(_link),
denoise(_denoise), AP(_AP), blockx(_blockx), blocky(_blocky), APType(_APType)
{
int z, w, q, b, i, track, count;
char linein[81];
char *linep;
FILE *f = NULL;
input = cArray = NULL;
if (!vi.IsYV12() && !vi.IsYUY2())
env->ThrowError("TDeint: YV12 and YUY2 data only!");
if (mode != 0 && mode != 1 && mode != -1 && mode != -2)
env->ThrowError("TDeint: mode must be set to -2, -1, 0, or 1!");
if (order != 0 && order != 1 && order != -1)
env->ThrowError("TDeint: order must be set to 0, 1, or -1!");
if (field != 0 && field != 1 && field != -1)
env->ThrowError("TDeint: field must be set to 0, 1, or -1!");
if (map < 0 || map > 2)
env->ThrowError("TDeint: map option must be set to 0, 1, or 2!");
if (ovrDefault != 0 && ovrDefault != 1)
env->ThrowError("TDeint: ovrDefault must be set to either 0 or 1!");
if (type != 0 && type != 1 && type != 2 && type != 3)
env->ThrowError("TDeint: type must be set to either 0, 1, 2, or 3!");
if (mtnmode < 0 || mtnmode > 3)
env->ThrowError("TDeint: mtnmode must be set to either 0, 1, 2, or 3!");
if (vi.height&1 || vi.width&1)
env->ThrowError("TDeint: width and height must be multiples of 2!");
if (link < 0 || link > 3)
env->ThrowError("TDeint: link must be set to 0, 1, 2, or 3!");
if (blockx != 4 && blockx != 8 && blockx != 16 && blockx != 32 && blockx != 64 &&
blockx != 128 && blockx != 256 && blockx != 512 && blockx != 1024 && blockx != 2048)
env->ThrowError("TDeint: illegal blockx size!");
if (blocky != 4 && blocky != 8 && blocky != 16 && blocky != 32 && blocky != 64 &&
blocky != 128 && blocky != 256 && blocky != 512 && blocky != 1024 && blocky != 2048)
env->ThrowError("TDeint: illegal blocky size!");
if (APType < 0 || APType > 2)
env->ThrowError("TDeint: APType must be set to 0, 1, or 2!");
child->SetCacheHints(CACHE_RANGE, 4);
useClip2 = false;
if ((hints || !full) && mode == 0 && clip2)
{
const VideoInfo& vi1 = clip2->GetVideoInfo();
if (vi1.height != vi.height || vi1.width != vi.width)
env->ThrowError("TDeint: width and height of clip2 must equal that of the input clip!");
if (!vi1.IsYV12() && !vi1.IsYUY2())
env->ThrowError("TDeint: YV12 and YUY2 data only (clip2)!");
if ((vi.IsYV12() && vi1.IsYUY2()) || (vi.IsYUY2() && vi1.IsYV12()))
env->ThrowError("TDeint: colorspace of clip2 doesn't match that of the input clip!");
if (vi.num_frames != vi1.num_frames)
env->ThrowError("TDeint: number of frames in clip2 doesn't match that of the input clip!");
useClip2 = true;
}
xhalf = blockx >> 1;
yhalf = blocky >> 1;
xshift = blockx == 4 ? 2 : blockx == 8 ? 3 : blockx == 16 ? 4 : blockx == 32 ? 5 :
blockx == 64 ? 6 : blockx == 128 ? 7 : blockx == 256 ? 8 : blockx == 512 ? 9 :
blockx == 1024 ? 10 : 11;
yshift = blocky == 4 ? 2 : blocky == 8 ? 3 : blocky == 16 ? 4 : blocky == 32 ? 5 :
blocky == 64 ? 6 : blocky == 128 ? 7 : blocky == 256 ? 8 : blocky == 512 ? 9 :
blocky == 1024 ? 10 : 11;
if (((!full && mode == 0) || tryWeave) && mode >= 0)
{
cArray = (int *)_aligned_malloc((((vi.width+xhalf)>>xshift)+1)*(((vi.height+yhalf)>>yshift)+1)*4*sizeof(int), 32);
if (cArray == NULL) env->ThrowError("TDeint: malloc failure!");
}
if (vi.IsYUY2())
{
xhalf *= 2;
++xshift;
}
vi.SetFieldBased(false);
nfrms = nfrms2 = vi.num_frames - 1;
accumP = accumN = 0;
cthresh6 = cthresh * 6;
passHint = 0xFFFFFFFF;
autoFO = false;
if (mode < 0)
{
vi.height *= 2;
field = 1;
}
if (order == -1) autoFO = true;
if (mode == 1)
{
vi.num_frames *= 2;
nfrms2 = vi.num_frames - 1;
vi.SetFPS(vi.fps_numerator*2, vi.fps_denominator);
}
else if (field == -1)
{
// telecide matches off the bottom field so we want field=0 in that case.
// tfm can match off top or bottom, but it will indicate which in its hints
// and field is adjusted appropriately then... so we use field=0 by default
// if hints=true. Otherwise, if hints=false, we default to field = 1.
if (hints) field = 0;
else field = 1;
}
orderS = order;
fieldS = field;
mthreshLS = mthreshL;
mthreshCS = mthreshC;
typeS = type;
if (debug)
{
sprintf(buf,"TDeint: %s (%s) by tritical\n", VERSION, DATE);
OutputDebugString(buf);
sprintf(buf,"TDeint: mode = %d (%s)\n", mode, mode == 0 ? "normal - same rate" :
mode == 1 ? "bob - double rate" : mode == -2 ? "upsize - ELA" : "upsize - ELA-2");
OutputDebugString(buf);
}
if (*ovr && mode >= 0)
{
countOvr = i = 0;
if ((f = fopen(ovr, "r")) != NULL)
{
while(fgets(linein, 80, f) != 0)
{
if (linein[0] == 0 || linein[0] == '\n' || linein[0] == '\r' || linein[0] == ';' ||
linein[0] == '#') continue;
linep = linein;
while (*linep != '-' && *linep != '+' && *linep != 0) *linep++;
if (*linep == 0) ++countOvr;
else if (*(linep+1) == '-' || *(linep+1) == '+')
{
linep = linein;
while (*linep != ',' && *linep != 0) *linep++;
if (*linep == ',')
{
sscanf(linein, "%d,%d", &z, &w);
if (z<0 || z>nfrms || w<0 || w>nfrms || w < z)
{
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (invalid frame range)!");
}
countOvr += (w - z + 1);
}
else
{
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (invalid entry)!");
}
}
else ++countOvr;
}
fclose(f);
f = NULL;
if (countOvr <= 0)
{
goto noovrexit;
}
++countOvr;
countOvr *= 4;
input = (int *)malloc(countOvr*sizeof(int));
if (input == NULL)
env->ThrowError("TDeint: ovr input error (malloc failure)!");
memset(input,255,countOvr*sizeof(int));
if ((f = fopen(ovr, "r")) != NULL)
{
while (fgets(linein, 80, f) != NULL)
{
if (linein[0] == 0 || linein[0] == '\n' || linein[0] == '\r' ||
linein[0] == ';' || linein[0] == '#') continue;
linep = linein;
while (*linep != ',' && *linep != 0 && *linep != ' ') *linep++;
if (*linep == ',')
{
sscanf(linein, "%d,%d", &z, &w);
if (w == 0) w = nfrms;
if (z<0 || z>nfrms || w<0 || w>nfrms || w < z)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (invalid frame range)!");
}
linep = linein;
while (*linep != ' ' && *linep != 0) *linep++;
if (*linep != 0)
{
*linep++;
if (*linep == 'f' || *linep == 'o' || *linep == 'l' || *linep == 'c' || *linep == 't')
{
q = *linep;
linep += 2;
if (*linep == 0)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (no change value specified)!");
}
sscanf(linep, "%d", &b);
if (q == 102 && b != 0 && b != 1)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad field value)!");
}
else if (q == 111 && b != 0 && b != 1)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad order value)!");
}
else if (q == 116 && b != 0 && b != 1 && b != 2 && b != 3)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad type value)!");
}
input[i] = q; ++i;
input[i] = z; ++i;
input[i] = w; ++i;
input[i] = b; ++i;
}
else if (*linep == '+' || *linep == '-')
{
if (*(linep+1) == '+' || *(linep+1) == '-')
{
track = z; count = 0;
while ((*linep == '+' || *linep == '-') && (track <= w))
{
q = *linep;
input[i] = q; ++i;
input[i] = track; ++i;
input[i] = track; ++i; ++i;
++count; ++track;
*linep++;
}
while (track <= w)
{
input[i] = input[i-(count*4)]; ++i;
input[i] = track; ++i;
input[i] = track; ++i; ++i;
++track;
}
}
else
{
q = *linep;
input[i] = q; ++i;
input[i] = z; ++i;
input[i] = w; ++i; ++i;
}
}
else
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad specifier)!");
}
}
else
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (no space after frame range)!");
}
}
else if (*linep == ' ')
{
sscanf(linein, "%d", &z);
if (z<0 || z>nfrms)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (out of range frame #)!");
}
linep = linein;
while (*linep != ' ' && *linep != 0) *linep++;
if (*linep != 0)
{
*linep++;
q = *linep;
input[i] = q; ++i;
input[i] = z; ++i;
input[i] = z; ++i;
if (*linep == 'f' || *linep == 'o' || *linep == 'l' || *linep == 'c' || *linep == 't')
{
linep += 2;
if (*linep == 0)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (no change value specified)!");
}
sscanf(linep, "%d", &b);
if (q == 102 && b != 0 && b != 1)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad field value)!");
}
else if (q == 111 && b != 0 && b != 1)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad order value)!");
}
else if (q == 116 && b != 0 && b != 1 && b != 2 && b != 3)
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad type value)!");
}
input[i] = b; ++i;
}
else if (*linep == '+' || *linep == '-') ++i;
else
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (bad specifier)!");
}
}
else
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (no space after frame number)!");
}
}
else
{
free(input);
input = NULL;
fclose(f);
f = NULL;
env->ThrowError("TDeint: ovr input error (invalid line)!");
}
}
fclose(f);
f = NULL;
}
else
{
free(input);
input = NULL;
env->ThrowError("TDeint: ovr input error (cannot open file)!");
}
}
else env->ThrowError("TDeint: ovr input error (cannot open file)!");
}
noovrexit:
_asm emms;
}
TDeinterlace::~TDeinterlace()
{
if (input != NULL) free(input);
if (cArray != NULL) _aligned_free(cArray);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -