From f9816d31c2831c58329db0c661e0307a22766025 Mon Sep 17 00:00:00 2001 From: louis Date: Mon, 31 May 2021 16:59:32 -0400 Subject: [PATCH] tensura2: bd: vol1 --- Tensei Shitara Slime Datta Ken S2/01/01.vpy | 54 +++++++++ Tensei Shitara Slime Datta Ken S2/02/02.vpy | 58 ++++++++++ Tensei Shitara Slime Datta Ken S2/03/03.vpy | 57 ++++++++++ Tensei Shitara Slime Datta Ken S2/04/04.vpy | 58 ++++++++++ Tensei Shitara Slime Datta Ken S2/05/05.vpy | 81 ++++++++++++++ Tensei Shitara Slime Datta Ken S2/06/06.vpy | 85 ++++++++++++++ Tensei Shitara Slime Datta Ken S2/README.md | 2 + .../tensura_common/__init__.py | 2 + .../tensura_common/config.py | 21 ++++ .../tensura_common/filter.py | 104 ++++++++++++++++++ .../tensura_common/final-settings | 1 + .../tensura_common/py.typed | 0 yt_common/yt_common/antialiasing.py | 98 +++++++++++++++++ 13 files changed, 621 insertions(+) create mode 100644 Tensei Shitara Slime Datta Ken S2/01/01.vpy create mode 100644 Tensei Shitara Slime Datta Ken S2/02/02.vpy create mode 100644 Tensei Shitara Slime Datta Ken S2/03/03.vpy create mode 100644 Tensei Shitara Slime Datta Ken S2/04/04.vpy create mode 100644 Tensei Shitara Slime Datta Ken S2/05/05.vpy create mode 100644 Tensei Shitara Slime Datta Ken S2/06/06.vpy create mode 100644 Tensei Shitara Slime Datta Ken S2/README.md create mode 100644 Tensei Shitara Slime Datta Ken S2/tensura_common/__init__.py create mode 100644 Tensei Shitara Slime Datta Ken S2/tensura_common/config.py create mode 100644 Tensei Shitara Slime Datta Ken S2/tensura_common/filter.py create mode 100644 Tensei Shitara Slime Datta Ken S2/tensura_common/final-settings create mode 100644 Tensei Shitara Slime Datta Ken S2/tensura_common/py.typed diff --git a/Tensei Shitara Slime Datta Ken S2/01/01.vpy b/Tensei Shitara Slime Datta Ken S2/01/01.vpy new file mode 100644 index 0000000..564bea1 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/01/01.vpy @@ -0,0 +1,54 @@ +import vapoursynth as vs + +from tensura_common import TenSuraConfig, antialias, deband, denoise, descale, finalize, regrain + +from yt_common.automation import SelfRunner +from yt_common.chapters import Chapter +from yt_common.source import FileTrim, SimpleSource + +from lvsfunc.types import Range + +from typing import List + +import os + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: TenSuraConfig = TenSuraConfig(EPNUM) +BDMV: str = "../bdmv/[BDMV][210326][Tensei Shitara Slime Datta Ken 2nd Season][Vol.1]/BDMV/STREAM" +SOURCE: SimpleSource = SimpleSource( + FileTrim(os.path.join(BDMV, "00006.m2ts"), (24, -50)) +) + +CHAPTERS: List[Chapter] = [ + Chapter("Intro", 0), + Chapter("OP", 6570), + Chapter("Part A", 8726), + Chapter("Part B", 21123), + Chapter("ED", 31768), + Chapter("Next", 33926), +] + +AA_STRONG: List[Range] = [ + (15605, 15772), +] + +core = vs.core + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + den = denoise(src) + descaled = descale(den) + deb = deband(descaled) + aa = antialias(deb, strong=AA_STRONG) + grain = regrain(aa) + final = finalize(grain) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, chapters=CHAPTERS) +else: + filter() diff --git a/Tensei Shitara Slime Datta Ken S2/02/02.vpy b/Tensei Shitara Slime Datta Ken S2/02/02.vpy new file mode 100644 index 0000000..7eab2dd --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/02/02.vpy @@ -0,0 +1,58 @@ +import vapoursynth as vs + +from tensura_common import TenSuraConfig, antialias, deband, denoise, descale, finalize, regrain + +from yt_common.automation import SelfRunner +from yt_common.chapters import Chapter +from yt_common.source import FileTrim, SimpleSource + +from lvsfunc.types import Range + +from typing import List + +import os + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: TenSuraConfig = TenSuraConfig(EPNUM) +BDMV: str = "../bdmv/[BDMV][210326][Tensei Shitara Slime Datta Ken 2nd Season][Vol.1]/BDMV/STREAM" +SOURCE: SimpleSource = SimpleSource( + FileTrim(os.path.join(BDMV, "00007.m2ts"), (None, -49)) +) + +CHAPTERS: List[Chapter] = [ + Chapter("Intro", 0), + Chapter("OP", 960), + Chapter("Part A", 3117), + Chapter("Part B", 14170), + Chapter("ED", 31769), + Chapter("Next", 33927), +] + +AA_STRONG: List[Range] = [ +] + +DEBAND_NUCLEAR: List[Range] = [ + (15473, 15592), + (15772, 15919), +] + +core = vs.core + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + den = denoise(src) + descaled = descale(den) + deb = deband(descaled, nuclear=DEBAND_NUCLEAR) + aa = antialias(deb, strong=AA_STRONG) + grain = regrain(aa) + final = finalize(grain) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, chapters=CHAPTERS) +else: + filter() diff --git a/Tensei Shitara Slime Datta Ken S2/03/03.vpy b/Tensei Shitara Slime Datta Ken S2/03/03.vpy new file mode 100644 index 0000000..8367da1 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/03/03.vpy @@ -0,0 +1,57 @@ +import vapoursynth as vs + +from tensura_common import TenSuraConfig, antialias, deband, denoise, descale, finalize, regrain + +from yt_common.automation import SelfRunner +from yt_common.chapters import Chapter +from yt_common.source import FileTrim, SimpleSource + +from lvsfunc.types import Range + +from typing import List + +import os + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: TenSuraConfig = TenSuraConfig(EPNUM) +BDMV: str = "../bdmv/[BDMV][210326][Tensei Shitara Slime Datta Ken 2nd Season][Vol.1]/BDMV/STREAM" +SOURCE: SimpleSource = SimpleSource( + FileTrim(os.path.join(BDMV, "00008.m2ts"), (None, -50)) +) + +CHAPTERS: List[Chapter] = [ + Chapter("Intro", 0), + Chapter("OP", 336), + Chapter("Part A", 2494), + Chapter("Part B", 18198), + Chapter("ED", 31768), + Chapter("Next", 33926), +] + +AA_STRONG: List[Range] = [ + (3084, 3125), +] + +DEBAND_NUCLEAR: List[Range] = [ +] + +core = vs.core + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + den = denoise(src) + descaled = descale(den) + deb = deband(descaled, nuclear=DEBAND_NUCLEAR) + aa = antialias(deb, strong=AA_STRONG) + grain = regrain(aa) + final = finalize(grain) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, chapters=CHAPTERS) +else: + filter() diff --git a/Tensei Shitara Slime Datta Ken S2/04/04.vpy b/Tensei Shitara Slime Datta Ken S2/04/04.vpy new file mode 100644 index 0000000..5d8313c --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/04/04.vpy @@ -0,0 +1,58 @@ +import vapoursynth as vs + +from tensura_common import TenSuraConfig, antialias, deband, denoise, descale, finalize, regrain + +from yt_common.automation import SelfRunner +from yt_common.chapters import Chapter +from yt_common.source import FileTrim, SimpleSource + +from lvsfunc.types import Range + +from typing import List + +import os + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: TenSuraConfig = TenSuraConfig(EPNUM) +BDMV: str = "../bdmv/[BDMV][210326][Tensei Shitara Slime Datta Ken 2nd Season][Vol.1]/BDMV/STREAM" +SOURCE: SimpleSource = SimpleSource( + FileTrim(os.path.join(BDMV, "00009.m2ts"), (None, -51)) +) + +CHAPTERS: List[Chapter] = [ + Chapter("Intro", 0), + Chapter("OP", 3237), + Chapter("Part A", 5395), + Chapter("Part B", 18484), + Chapter("ED", 31767), + Chapter("Next", 33925), +] + +AA_STRONG: List[Range] = [ + (6038, 6117), + (7301, 7348), +] + +DEBAND_NUCLEAR: List[Range] = [ +] + +core = vs.core + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + den = denoise(src) + descaled = descale(den) + deb = deband(descaled, nuclear=DEBAND_NUCLEAR) + aa = antialias(deb, strong=AA_STRONG) + grain = regrain(aa) + final = finalize(grain) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, chapters=CHAPTERS) +else: + filter() diff --git a/Tensei Shitara Slime Datta Ken S2/05/05.vpy b/Tensei Shitara Slime Datta Ken S2/05/05.vpy new file mode 100644 index 0000000..f9bbfd7 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/05/05.vpy @@ -0,0 +1,81 @@ +import vapoursynth as vs + +from tensura_common import TenSuraConfig, antialias, deband, denoise, descale, edgefix, finalize, regrain + +from yt_common.automation import SelfRunner +from yt_common.chapters import Chapter +from yt_common.source import FileTrim, SimpleSource + +from lvsfunc.mask import BoundingBox +from lvsfunc.types import Range + +from typing import List, Tuple + +import os + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: TenSuraConfig = TenSuraConfig(EPNUM) +BDMV: str = "../bdmv/[BDMV][210326][Tensei Shitara Slime Datta Ken 2nd Season][Vol.1]/BDMV/STREAM" +SOURCE: SimpleSource = SimpleSource( + FileTrim(os.path.join(BDMV, "00010.m2ts"), (None, -24)) +) + +CHAPTERS: List[Chapter] = [ + Chapter("Intro", 0), + Chapter("OP", 2086), + Chapter("Part A", 4245), + Chapter("Part B", 13141), + Chapter("ED", 31770), + Chapter("Next", 33928), +] + +AA_STRONG: List[Range] = [ +] + +SANGNOM: List[Tuple[Range, List[BoundingBox]]] = [ + ((11212, 11301), [ + BoundingBox((463, 945), (223, 135)), + BoundingBox((932, 1052), (33, 28)), + BoundingBox((0, 0), (346, 272)), + BoundingBox((529, 758), (72, 42)), + BoundingBox((503, 569), (81, 54)), + ]), + ((14864, 14924), [ + BoundingBox((36, 805), (670, 225)), + BoundingBox((1028, 899), (109, 143)), + BoundingBox((1280, 817), (640, 174)), + ]), + ((16570, 16790), [ + BoundingBox((836, 873), (46, 188)), + ]), +] + +DEBAND_NUCLEAR: List[Range] = [ +] + +EDGEFIX: List[Range] = [ + (0, 2085), + (4245, 31769), +] + +core = vs.core + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + ef = edgefix(src, EDGEFIX) + den = denoise(ef) + descaled = descale(den) + deb = deband(descaled, nuclear=DEBAND_NUCLEAR) + aa = antialias(deb, strong=AA_STRONG, sangnom=SANGNOM) + grain = regrain(aa) + final = finalize(grain) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, chapters=CHAPTERS) +else: + filter() diff --git a/Tensei Shitara Slime Datta Ken S2/06/06.vpy b/Tensei Shitara Slime Datta Ken S2/06/06.vpy new file mode 100644 index 0000000..32a6ced --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/06/06.vpy @@ -0,0 +1,85 @@ +import vapoursynth as vs + +from tensura_common import TenSuraConfig, antialias, deband, denoise, descale, edgefix, finalize, regrain + +from yt_common.automation import SelfRunner +from yt_common.chapters import Chapter +from yt_common.source import FileTrim, SimpleSource + +from lvsfunc.mask import BoundingBox +from lvsfunc.types import Range + +from typing import List, Tuple + +import os + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: TenSuraConfig = TenSuraConfig(EPNUM) +BDMV: str = "../bdmv/[BDMV][210326][Tensei Shitara Slime Datta Ken 2nd Season][Vol.1]/BDMV/STREAM" +SOURCE: SimpleSource = SimpleSource( + FileTrim(os.path.join(BDMV, "00011.m2ts"), (24, -25)) +) + +CHAPTERS: List[Chapter] = [ + Chapter("OP", 0), + Chapter("Part A", 2159), + Chapter("Part B", 17311), + Chapter("ED", 31769), + Chapter("Next", 33927), +] + +AA_STRONG: List[Range] = [ + (11640, 11685), + (12437, 12488), + (12745, 12754), + (12959, 13129), + (13130, 13193), + (13432, 13479), + (13662, 13700), + (13845, 13915), + (14619, 14642), + (14779, 14801), +] + +SANGNOM: List[Tuple[Range, List[BoundingBox]]] = [ + ((2159, 2206), [ + BoundingBox((0, 945), (1218, 135)), + ]), + ((7269, 7360), [ + BoundingBox((714, 481), (24, 44)), + ]), + ((11640, 11685), [ + BoundingBox((1449, 53), (471, 224)), + ]), + ((14490, 14522), [ + BoundingBox((0, 794), (1920, 170)), + ]), +] + +DEBAND_NUCLEAR: List[Range] = [ +] + +EDGEFIX: List[Range] = [ +] + +core = vs.core + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + ef = edgefix(src, EDGEFIX) + den = denoise(ef) + descaled = descale(den) + deb = deband(descaled, nuclear=DEBAND_NUCLEAR) + aa = antialias(deb, strong=AA_STRONG, sangnom=SANGNOM) + grain = regrain(aa) + final = finalize(grain) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, chapters=CHAPTERS) +else: + filter() diff --git a/Tensei Shitara Slime Datta Ken S2/README.md b/Tensei Shitara Slime Datta Ken S2/README.md new file mode 100644 index 0000000..e9d1d09 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/README.md @@ -0,0 +1,2 @@ +# Tensei Shitara Slime Datta Ken S2 +Encoded for [Asakura]. diff --git a/Tensei Shitara Slime Datta Ken S2/tensura_common/__init__.py b/Tensei Shitara Slime Datta Ken S2/tensura_common/__init__.py new file mode 100644 index 0000000..fb320c0 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/tensura_common/__init__.py @@ -0,0 +1,2 @@ +from .config import TenSuraConfig # noqa: F401 +from .filter import antialias, deband, denoise, descale, edgefix, finalize, regrain # noqa: F401 diff --git a/Tensei Shitara Slime Datta Ken S2/tensura_common/config.py b/Tensei Shitara Slime Datta Ken S2/tensura_common/config.py new file mode 100644 index 0000000..90d6182 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/tensura_common/config.py @@ -0,0 +1,21 @@ +from yt_common.config import Config, FlacMixin + +from typing import Union + +import os + +TITLE: str = "TenSura S2" +TITLE_LONG: str = "Tensei Shitara Slime Datta Ken S2" +RESOLUTION: int = 1080 +DATAPATH: str = os.path.dirname(__file__) + + +class TenSuraConfig(FlacMixin, Config): + def __init__(self, desc: Union[str, int]) -> None: + super().__init__( + desc, + TITLE, + TITLE_LONG, + RESOLUTION, + DATAPATH + ) diff --git a/Tensei Shitara Slime Datta Ken S2/tensura_common/filter.py b/Tensei Shitara Slime Datta Ken S2/tensura_common/filter.py new file mode 100644 index 0000000..91ed198 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/tensura_common/filter.py @@ -0,0 +1,104 @@ +import vapoursynth as vs + +from yt_common.antialiasing import mask_strong, sraa_clamp, supersample_aa +from yt_common.data import FSRCNNX +from yt_common.scale import nnedi3_double + +from lvsfunc.aa import upscaled_sraa +from lvsfunc.kernels import Bicubic +from lvsfunc.mask import BoundingBox, detail_mask +from lvsfunc.misc import replace_ranges, scale_thresh +from lvsfunc.scale import descale as ldescale +from lvsfunc.types import Range + +from awsmfunc import bbmod +from debandshit import f3kbilateral +from kagefunc import retinex_edgemask +from vardefunc import dumb3kdb, fsrcnnx_upscale +from vsutil import depth +from vsutil import Range as CRange + +from typing import List, Optional, Tuple + +core = vs.core + + +def _fsrlineart(clip: vs.VideoNode, width: int, height: int) -> vs.VideoNode: + clip = clip.resize.Point(1440, 810) + assert clip.format is not None + nn = depth(nnedi3_double(depth(clip, 16)), clip.format.bits_per_sample) + fsr = fsrcnnx_upscale(clip, width, height, upscaled_smooth=nn, shader_file=FSRCNNX) + mask = retinex_edgemask(depth(fsr.std.ShufflePlanes(0, vs.GRAY), 16)) + mask = mask.std.Binarize(scale_thresh(0.65, mask)).std.Maximum() + mask = depth(mask, clip.format.bits_per_sample, range_in=CRange.FULL, range=CRange.FULL) + return core.std.MaskedMerge(nn.resize.Bicubic(width, height, filter_param_a=0, filter_param_b=1/2), fsr, mask) + + +def edgefix(clip: vs.VideoNode, ranges: Optional[List[Range]] = None) -> vs.VideoNode: + bb: vs.VideoNode = bbmod(clip, top=1, bottom=1, left=1, right=1, blur=500) + return replace_ranges(clip, bb, ranges or []) + + +def descale(clip: vs.VideoNode) -> vs.VideoNode: + return depth(ldescale(clip, height=810, kernel=Bicubic(b=0, c=1/2), upscaler=_fsrlineart), 16) + + +def denoise(clip: vs.VideoNode, h: float = 0.7) -> vs.VideoNode: + den = core.std.ShufflePlanes([ + clip.knlm.KNLMeansCL(d=3, a=2, h=h, channels="Y"), + clip.knlm.KNLMeansCL(d=3, a=2, h=0.2, channels="UV"), + ], planes=[0, 1, 2], colorfamily=vs.YUV) + return core.std.MaskedMerge(den, clip, detail_mask(den)) + + +def deband(clip: vs.VideoNode, strong: Optional[List[Range]] = None, + nuclear: Optional[List[Range]] = None) -> vs.VideoNode: + dmask = detail_mask(clip) + deb = dumb3kdb(clip, radius=16, threshold=30) + debs = dumb3kdb(clip, radius=24, threshold=60) + deb = replace_ranges(deb, debs, strong or []) + debn = core.std.ShufflePlanes([ + core.std.MaskedMerge( + f3kbilateral(clip.std.ShufflePlanes(planes=0, colorfamily=vs.GRAY), y=60), + clip.std.ShufflePlanes(planes=0, colorfamily=vs.GRAY), + detail_mask(clip) + ), + deb + ], planes=[0, 1, 2], colorfamily=vs.YUV) + deb = replace_ranges(deb, debn, nuclear or []) + return core.std.MaskedMerge(deb, clip, dmask) + + +def antialias(clip: vs.VideoNode, strong: List[Range], + sangnom: Optional[List[Tuple[Range, List[BoundingBox]]]] = None) -> vs.VideoNode: + clamp = sraa_clamp(clip, mask=mask_strong) + sraa_13 = upscaled_sraa(clip, rfactor=1.3, downscaler=Bicubic(b=0, c=1/2).scale) + sraa_13 = core.std.MaskedMerge(clip, sraa_13, mask_strong(sraa_13)) + clamp = replace_ranges(clamp, sraa_13, strong) + if sangnom: + sn = supersample_aa(sraa_13, rfactor=1.5, aafun=lambda c, s: c.sangnom.SangNom()) + sn = core.std.MaskedMerge(sraa_13, sn, mask_strong(sn)) + for r, ms in sangnom: + mask = core.std.BlankClip(clip.std.ShufflePlanes(planes=0, colorfamily=vs.GRAY)) + for m in ms: + mask = core.std.Expr([mask, m.get_mask(clip)], "x y max") + clamp = replace_ranges(clamp, core.std.MaskedMerge(clamp, sn, mask), r) + return clamp + + +def regrain(clip: vs.VideoNode) -> vs.VideoNode: + # doing a fairly heavy regrain since the source was so insanely grainy + # but still nowhere near to the extent the source was + mask_bright = clip.std.PlaneStats().adg.Mask(5) + mask_dark = clip.std.PlaneStats().adg.Mask(15) + sgrain_l = core.std.MaskedMerge(clip, clip.grain.Add(var=0.15, constant=True, seed=393), mask_bright.std.Invert()) + sgrain_h = core.std.MaskedMerge(clip, clip.grain.Add(var=0.25, uvar=0.1, constant=True, seed=393), mask_bright) + sgrain_h = core.std.MaskedMerge(clip, sgrain_h, mask_dark.std.Invert()) + sgrain = sgrain_h.std.MergeDiff(clip.std.MakeDiff(sgrain_l)) + dgrain = core.std.MaskedMerge(clip, clip.grain.Add(var=0.35, uvar=0.1, constant=False, seed=393), mask_dark) + grain = dgrain.std.MergeDiff(clip.std.MakeDiff(sgrain)) + return grain + + +def finalize(clip: vs.VideoNode) -> vs.VideoNode: + return depth(clip, 10) diff --git a/Tensei Shitara Slime Datta Ken S2/tensura_common/final-settings b/Tensei Shitara Slime Datta Ken S2/tensura_common/final-settings new file mode 100644 index 0000000..957b876 --- /dev/null +++ b/Tensei Shitara Slime Datta Ken S2/tensura_common/final-settings @@ -0,0 +1 @@ +x265 --input - --y4m --input-depth 10 --output-depth 10 --input-csp i420 --profile main10 --colormatrix bt709 --colorprim bt709 --transfer bt709 --preset slower --rc-lookahead 72 --keyint 360 --min-keyint 23 --subme 5 --qcomp 0.7 --crf 15 --aq-mode 3 --aq-strength 0.9 --bframes 16 --psy-rd 2.0 --psy-rdoq 1.8 --rdoq-level 1 --deblock -2:-2 --no-sao --no-open-gop --no-strong-intra-smoothing --frames {frames:d} --output {filename:s}.h265 diff --git a/Tensei Shitara Slime Datta Ken S2/tensura_common/py.typed b/Tensei Shitara Slime Datta Ken S2/tensura_common/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/yt_common/yt_common/antialiasing.py b/yt_common/yt_common/antialiasing.py index b807c90..0411e79 100644 --- a/yt_common/yt_common/antialiasing.py +++ b/yt_common/yt_common/antialiasing.py @@ -7,11 +7,14 @@ from lvsfunc.aa import nnedi3, clamp_aa, upscaled_sraa from lvsfunc.kernels import Bicubic from lvsfunc.misc import replace_ranges, scale_thresh from lvsfunc.types import Range +from lvsfunc.util import pick_repair from typing import Any, Callable, Dict, List, Optional, Union from .scale import nnedi3_double +from vsutil import get_w, get_y + core = vs.core @@ -91,3 +94,98 @@ def zastinAA(clip: vs.VideoNode, rfactor: float = 2.0, aa = eedi3s(aa, mclip=mclip).resize.Spline16(y.width, y.height) return core.std.ShufflePlanes([core.std.MaskedMerge(y, aa, mask), clip], planes=[0, 1, 2], colorfamily=vs.YUV) + + +def supersample_aa(clip: vs.VideoNode, + rfactor: float = 1.5, + rep: Optional[int] = None, + width: Optional[int] = None, height: Optional[int] = None, + downscaler: Optional[Callable[[vs.VideoNode, int, int], vs.VideoNode]] + = Bicubic(b=0, c=1/2).scale, + aafun: Optional[Callable[[vs.VideoNode, vs.VideoNode], vs.VideoNode]] = None, + nnedi3cl: Optional[bool] = None, + **eedi3_args: Any) -> vs.VideoNode: + """ + A function that performs a supersampled single-rate AA to deal with heavy aliasing and broken-up lineart. + Useful for Web rips, where the source quality is not good enough to descale, + but you still want to deal with some bad aliasing and lineart. + It works by supersampling the clip, performing AA, and then downscaling again. + Downscaling can be disabled by setting `downscaler` to `None`, returning the supersampled luma clip. + The dimensions of the downscaled clip can also be adjusted by setting `height` or `width`. + Setting either `height` or `width` will also scale the chroma accordingly. + Original function written by Zastin, heavily modified by LightArrowsEXE. + Alias for this function is `lvsfunc.sraa`. + Dependencies: + * RGSF (optional: 32 bit clip) + * vapoursynth-eedi3 + * vapoursynth-nnedi3 + * vapoursynth-nnedi3cl (optional: opencl) + :param clip: Input clip + :param rfactor: Image enlargement factor. 1.3..2 makes it comparable in strength to vsTAAmbk + It is not recommended to go below 1.3 (Default: 1.5) + :param rep: Repair mode (Default: None) + :param width: Target resolution width. If None, determined from `height` + :param height: Target resolution height (Default: ``clip.height``) + :param downscaler: Resizer used to downscale the AA'd clip + :param aafun: Single-rate antialiaser to apply after supersampling. + Takes an input clip and an sclip. (Default: eedi3) + :param nnedi3cl: OpenCL acceleration for nnedi3 upscaler (Default: False) + :return: Antialiased and optionally rescaled clip + """ + if clip.format is None: + raise ValueError("upscaled_sraa: 'Variable-format clips not supported'") + + luma = get_y(clip) + + nnargs: Dict[str, Any] = dict(field=0, nsize=0, nns=4, qual=2) + # TAAmbk defaults are 0.5, 0.2, 20, 3, 30 + eeargs: Dict[str, Any] = dict(field=0, dh=False, alpha=0.2, beta=0.6, gamma=40, nrad=2, mdis=20) + eeargs.update(eedi3_args) + + if rfactor < 1: + raise ValueError("upscaled_sraa: '\"rfactor\" must be above 1'") + + ssw = round(clip.width * rfactor) + ssw = (ssw + 1) & ~1 + ssh = round(clip.height * rfactor) + ssh = (ssh + 1) & ~1 + + height = height or clip.height + + if width is None: + width = clip.width if height == clip.height else get_w(height, aspect_ratio=clip.width / clip.height) + + def _nnedi3(clip: vs.VideoNode, dh: bool = False) -> vs.VideoNode: + return clip.nnedi3cl.NNEDI3CL(dh=dh, **nnargs) if nnedi3cl \ + else clip.nnedi3.nnedi3(dh=dh, **nnargs) + + def _eedi3(clip: vs.VideoNode, sclip: vs.VideoNode) -> vs.VideoNode: + return clip.eedi3m.EEDI3(sclip=sclip, **eeargs) + + aafun = aafun or _eedi3 + + # Nnedi3 upscale from source height to source height * rounding (Default 1.5) + up_y = _nnedi3(luma, dh=True) + up_y = up_y.resize.Spline36(height=ssh, src_top=0.5).std.Transpose() + up_y = _nnedi3(up_y, dh=True) + up_y = up_y.resize.Spline36(height=ssw, src_top=0.5) + + # Single-rate AA + aa_y = aafun(up_y, _nnedi3(up_y)) + aa_y = core.std.Transpose(aa_y) + aa_y = aafun(aa_y, _nnedi3(aa_y)) + + scaled = aa_y if downscaler is None else downscaler(aa_y, width, height) + scaled = pick_repair(scaled)(scaled, luma.resize.Bicubic(width, height), mode=rep) if rep else scaled + + if clip.format.num_planes == 1 or downscaler is None: + return scaled + if height is not clip.height or width is not clip.width: + if height % 2: + raise ValueError("upscaled_sraa: '\"height\" must be an even number when not passing a GRAY clip'") + if width % 2: + raise ValueError("upscaled_sraa: '\"width\" must be an even number when not passing a GRAY clip'") + + chroma = Bicubic().scale(clip, width, height) + return core.std.ShufflePlanes([scaled, chroma], planes=[0, 1, 2], colorfamily=vs.YUV) + return core.std.ShufflePlanes([scaled, clip], planes=[0, 1, 2], colorfamily=vs.YUV)