📄 tdeinterlaceyv12.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 TDeinterlace::GetFrameYV12(int n, IScriptEnvironment* env)
{
if (mode < 0)
{
PVideoFrame src2up = child->GetFrame(n, env);
PVideoFrame dst2up = env->NewVideoFrame(vi);
PVideoFrame msk2up = env->NewVideoFrame(vi);
copyForUpsize(dst2up, src2up, 3, env);
setMaskForUpsize(msk2up, 3);
if (mode == -2) smartELADeintYV12(dst2up, msk2up, dst2up, dst2up, dst2up);
else if (mode == -1) ELADeintYV12(dst2up, msk2up, dst2up, dst2up, dst2up);
return dst2up;
}
if (mode == 1)
{
if (autoFO) order = child->GetParity(n>>1) ? 1 : 0;
if (n&1) field = order == 1 ? 0 : 1;
else field = order;
n >>= 1;
}
else if (autoFO) order = child->GetParity(n) ? 1 : 0;
PVideoFrame prv2, prv, nxt, nxt2, dst, mask;
PVideoFrame src = child->GetFrame(n, env);
bool found = false, fieldOVR = false;
int x, hintField = -1;
passHint = 0xFFFFFFFF;
if (input != NULL && *ovr)
{
if (mode != 1)
{
field = fieldS;
if (!autoFO) order = orderS;
}
mthreshL = mthreshLS;
mthreshC = mthreshCS;
type = typeS;
for (x=0; x<countOvr; x+=4)
{
if (n >= input[x+1] && n <= input[x+2])
{
if (input[x] == 45 && mode != 1) // -
{
if (debug)
{
sprintf(buf,"TDeint: frame %d: not deinterlacing\n", n);
OutputDebugString(buf);
}
return src;
}
else if (input[x] == 43 && mode != 1) found = true; // +
else if (input[x] == 102 && mode != 1) { field = input[x+3]; fieldOVR = true; } // f
else if (input[x] == 111 && mode != 1) order = input[x+3]; // o
else if (input[x] == 108) mthreshL = input[x+3]; // l
else if (input[x] == 99) mthreshC = input[x+3]; // c
else if (input[x] == 116) type = input[x+3]; // t
}
}
if (!found && ovrDefault == 1 && mode != 1)
{
if (debug)
{
sprintf(buf,"TDeint: frame %d: not deinterlacing\n", n);
OutputDebugString(buf);
}
return src;
}
}
if (mode == 0 && hints && TDeinterlace::getHint(src, passHint, hintField) == 0 && !found)
{
if (debug)
{
sprintf(buf,"TDeint: frame %d: not deinterlacing (HINTS)\n", n);
OutputDebugString(buf);
}
return src;
}
if (mode == 0 && !full && !found)
{
if (!checkCombedYV12(src, env))
{
if (debug)
{
sprintf(buf,"TDeint: frame %d: not deinterlacing (full = false)\n", n);
OutputDebugString(buf);
}
return src;
}
}
if (!fieldOVR && hintField >= 0)
{
int tempf = field;
field = hintField;
hintField = tempf;
}
if (!useClip2)
{
prv2 = child->GetFrame(n>1 ? n-2 : n>0 ? n-1 : 0, env);
prv = child->GetFrame(n>0 ? n-1 : 0, env);
nxt = child->GetFrame(n<nfrms ? n+1 : nfrms, env);
nxt2 = child->GetFrame(n<nfrms-1 ? n+2 : n<nfrms ? n+1 : nfrms, env);
}
else
{
prv2 = clip2->GetFrame(n>1 ? n-2 : n>0 ? n-1 : 0, env);
prv = clip2->GetFrame(n>0 ? n-1 : 0, env);
src = clip2->GetFrame(n, env);
nxt = clip2->GetFrame(n<nfrms ? n+1 : nfrms, env);
nxt2 = clip2->GetFrame(n<nfrms-1 ? n+2 : n<nfrms ? n+1 : nfrms, env);
}
dst = env->NewVideoFrame(vi);
if (type == 2 || mtnmode > 1 || tryWeave)
{
subtractFieldsYV12(prv, src, nxt);
if (debug)
{
sprintf(buf, "TDeint: frame %d: accumP = %u accumN = %u\n", n, accumP, accumN);
OutputDebugString(buf);
}
}
if (tryWeave && (mode != 0 || full || found || (field^order && accumP > accumN) ||
(!(field^order) && accumN > accumP)))
{
createWeaveFrameYV12(dst, prv, src, nxt, env);
if (!checkCombedYV12(dst, env))
{
if (debug)
{
sprintf(buf,"TDeint: frame %d: weaved with %s (tryWeave)\n", n,
field^order ? (accumP <= accumN ? "CURR" : "NEXT") :
(accumN <= accumP ? "CURR" : "PREV"));
OutputDebugString(buf);
}
if (hintField >= 0 && !fieldOVR) field = hintField;
return dst;
}
}
mask = env->NewVideoFrame(vi);
if (mthreshL <= 0 && mthreshC <= 0) setMaskForUpsize(mask, 3);
else if (mtnmode == 0 || mtnmode == 2) createMotionMapYV12(prv2, prv, src, nxt, nxt2, mask, n);
else if (mtnmode == 1 || mtnmode == 3) createMotionMap2YV12(prv2, prv, src, nxt, nxt2, mask, n);
else env->ThrowError("TDeint: an unknown error occured!");
if (denoise) denoiseYV12(mask);
if (link == 1) linkFULL_YV12(mask);
else if (link == 2) linkYtoUV_YV12(mask);
else if (link == 3) linkUVtoY_YV12(mask);
else if (link != 0) env->ThrowError("TDeint: an unknown error occured (link)!");
if (map == 1) mapColorsYV12(dst, mask);
else if (map == 2) mapMergeYV12(dst, mask, prv, src, nxt);
else if (type == 0) cubicDeintYV12(dst, mask, prv, src, nxt);
else if (type == 1) smartELADeintYV12(dst, mask, prv, src, nxt);
else if (type == 2) kernelDeintYV12(dst, mask, prv, src, nxt);
else if (type == 3) ELADeintYV12(dst, mask, prv, src, nxt);
else env->ThrowError("TDeint: an unknown error occured!");
if (AP >= 0 && AP < 255 && map == 0) apPostCheck(dst, mask, env);
if (!(passHint&0xFFFFFF00)) TDeinterlace::putHint(dst, passHint, field);
if (debug)
{
sprintf(buf,"TDeint: frame %d: field = %s order = %s\n", n,
field == 1 ? "bottom" : "top", order == 1 ? "tff" : "bff");
OutputDebugString(buf);
sprintf(buf,"TDeint: frame %d: mthreshL = %d mthreshC = %d type = %d\n", n,
mthreshL, mthreshC, type);
OutputDebugString(buf);
}
if (hintField >= 0 && !fieldOVR) field = hintField;
return dst;
}
void TDeinterlace::createMotionMapYV12(PVideoFrame &prv2, PVideoFrame &prv,
PVideoFrame &src, PVideoFrame &nxt, PVideoFrame &nxt2, PVideoFrame &mask, int n)
{
const unsigned char *prv2pY = prv2->GetReadPtr(PLANAR_Y);
const unsigned char *prv2pV = prv2->GetReadPtr(PLANAR_V);
const unsigned char *prv2pU = prv2->GetReadPtr(PLANAR_U);
int prv2_pitchY = prv2->GetPitch(PLANAR_Y);
int prv2_pitchUV = prv2->GetPitch(PLANAR_V);
prv2pY += prv2_pitchY*(2-field);
prv2pV += prv2_pitchUV*(2-field);
prv2pU += prv2_pitchUV*(2-field);
prv2_pitchY *= 2;
prv2_pitchUV *= 2;
const unsigned char *prvpY = prv->GetReadPtr(PLANAR_Y);
const unsigned char *prvpV = prv->GetReadPtr(PLANAR_V);
const unsigned char *prvpU = prv->GetReadPtr(PLANAR_U);
int prv_pitchY = prv->GetPitch(PLANAR_Y);
int prv_pitchUV = prv->GetPitch(PLANAR_V);
prvpY += prv_pitchY*(2-field);
prvpV += prv_pitchUV*(2-field);
prvpU += prv_pitchUV*(2-field);
const unsigned char *prvppY = prvpY - prv_pitchY;
const unsigned char *prvppV = prvpV - prv_pitchUV;
const unsigned char *prvppU = prvpU - prv_pitchUV;
const unsigned char *prvpnY = prvpY + prv_pitchY;
const unsigned char *prvpnV = prvpV + prv_pitchUV;
const unsigned char *prvpnU = prvpU + prv_pitchUV;
prv_pitchY *= 2;
prv_pitchUV *= 2;
const unsigned char *srcpY = src->GetReadPtr(PLANAR_Y);
const unsigned char *srcpV = src->GetReadPtr(PLANAR_V);
const unsigned char *srcpU = src->GetReadPtr(PLANAR_U);
int src_pitchY = src->GetPitch(PLANAR_Y);
int src_pitchUV = src->GetPitch(PLANAR_V);
int WidthY = src->GetRowSize(PLANAR_Y);
int HeightY = src->GetHeight(PLANAR_Y);
int WidthUV = src->GetRowSize(PLANAR_V);
int HeightUV = src->GetHeight(PLANAR_V);
srcpY += src_pitchY*(2-field);
srcpV += src_pitchUV*(2-field);
srcpU += src_pitchUV*(2-field);
const unsigned char *srcppY = srcpY - src_pitchY;
const unsigned char *srcppV = srcpV - src_pitchUV;
const unsigned char *srcppU = srcpU - src_pitchUV;
const unsigned char *srcpnY = srcpY + src_pitchY;
const unsigned char *srcpnV = srcpV + src_pitchUV;
const unsigned char *srcpnU = srcpU + src_pitchUV;
src_pitchY *= 2;
src_pitchUV *= 2;
const unsigned char *nxtpY = nxt->GetReadPtr(PLANAR_Y);
const unsigned char *nxtpV = nxt->GetReadPtr(PLANAR_V);
const unsigned char *nxtpU = nxt->GetReadPtr(PLANAR_U);
int nxt_pitchY = nxt->GetPitch(PLANAR_Y);
int nxt_pitchUV = nxt->GetPitch(PLANAR_V);
nxtpY += nxt_pitchY*(2-field);
nxtpV += nxt_pitchUV*(2-field);
nxtpU += nxt_pitchUV*(2-field);
const unsigned char *nxtppY = nxtpY - nxt_pitchY;
const unsigned char *nxtppV = nxtpV - nxt_pitchUV;
const unsigned char *nxtppU = nxtpU - nxt_pitchUV;
const unsigned char *nxtpnY = nxtpY + nxt_pitchY;
const unsigned char *nxtpnV = nxtpV + nxt_pitchUV;
const unsigned char *nxtpnU = nxtpU + nxt_pitchUV;
nxt_pitchY *= 2;
nxt_pitchUV *= 2;
const unsigned char *nxt2pY = nxt2->GetReadPtr(PLANAR_Y);
const unsigned char *nxt2pV = nxt2->GetReadPtr(PLANAR_V);
const unsigned char *nxt2pU = nxt2->GetReadPtr(PLANAR_U);
int nxt2_pitchY = nxt2->GetPitch(PLANAR_Y);
int nxt2_pitchUV = nxt2->GetPitch(PLANAR_V);
nxt2pY += nxt2_pitchY*(2-field);
nxt2pV += nxt2_pitchUV*(2-field);
nxt2pU += nxt2_pitchUV*(2-field);
nxt2_pitchY *= 2;
nxt2_pitchUV *= 2;
unsigned char *maskwY = mask->GetWritePtr(PLANAR_Y);
unsigned char *maskwV = mask->GetWritePtr(PLANAR_V);
unsigned char *maskwU = mask->GetWritePtr(PLANAR_U);
int mask_pitchY = mask->GetPitch(PLANAR_Y);
int mask_pitchUV = mask->GetPitch(PLANAR_V);
memset(maskwY,10,mask_pitchY*HeightY);
memset(maskwU,10,mask_pitchUV*HeightUV);
memset(maskwV,10,mask_pitchUV*HeightUV);
maskwY += mask_pitchY*(2-field);
maskwV += mask_pitchUV*(2-field);
maskwU += mask_pitchUV*(2-field);
mask_pitchY *= 2;
mask_pitchUV *= 2;
int x, y;
unsigned char val1;
bool t1, t2, t3, t4, t5, t6, t7;
if (field^order)
{
val1 = mtnmode > 1 ? (accumP <= accumN ? 10 : 30) : 40;
if (n <= 1 || n >= nfrms-1)
{
for (y=1; y<HeightY-1; y+=2)
{
for (x=0; x<WidthY; ++x)
{
t1 = n == 0 ? false : (abs(srcppY[x] - prvppY[x]) < mthreshL);
t2 = n == 0 ? false : (abs(srcpnY[x] - prvpnY[x]) < mthreshL);
t3 = n == nfrms ? false : (abs(srcppY[x] - nxtppY[x]) < mthreshL);
t4 = n == nfrms ? false : (abs(srcpnY[x] - nxtpnY[x]) < mthreshL);
t5 = n == 0 ? false : (abs(srcpY[x] - prvpY[x]) < mthreshL);
t6 = n == nfrms ? false : (abs(srcpY[x] - nxtpY[x]) < mthreshL);
t7 = n >= nfrms-1 ? false : (abs(nxtpY[x] - nxt2pY[x]) < mthreshL);
if (t6 && ((t1 && t2) || (t3 && t4) || (t2 && t4 && (t5 || t7)) || (t1 && t3 && (t5 || t7))))
maskwY[x] = val1;
else if (t1 && t2 && t3 && t4 && t5 && t7) maskwY[x] = val1;
else if (t1 && t5 && t2) maskwY[x] = 10;
else if (t3 && t7 && t4) maskwY[x] = 30;
else if (abs(srcpY[x]-srcppY[x])<4 && abs(srcpY[x]-srcpnY[x])<4) maskwY[x] = 110;
else if (abs(nxtpY[x]-srcppY[x])<4 && abs(nxtpY[x]-srcpnY[x])<4) maskwY[x] = 130;
else maskwY[x] = 60;
}
prvppY += prv_pitchY;
prvpY += prv_pitchY;
prvpnY += prv_pitchY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -