压制基础教程(FXXS出品)

  • ~22.64K 字
  1. 1. 源、编码、透明度对比
  2. 2. x264 与 x265
  3. 3. 压制环境构建
    1. 3.1. 编码器
    2. 3.2. VapourSynth
    3. 3.3. 常用其他软件
  4. 4. 压制步骤
    1. 4.1. 压制源分析
    2. 4.2. 分离提取(Demux)与音频转换
    3. 4.3. 输入脚本编写
      1. 4.3.1. 片源载入(Index a video)
      2. 4.3.2. 切除边缘
      3. 4.3.3. 变换大小
      4. 4.3.4. 抽取测试
      5. 4.3.5. 压制测试
        1. 4.3.5.1. 压制参数配置
        2. 4.3.5.2. CRF测试
          1. 4.3.5.2.1. 合理码率评判方式
            1. 4.3.5.2.1.1. 追求体积
            2. 4.3.5.2.1.2. 保证与原盘相似透明度
        3. 4.3.5.3. 其他参数
        4. 4.3.5.4. 最终CRF测试
        5. 4.3.5.5. 压制对比脚本编写
      6. 4.3.6. 正式压制
      7. 4.3.7. 封装
  5. 5. VapourSynth 脚本(vpy) Filtering 基础滤镜以及处理
    1. 5.1. 缩放(Resizing)
    2. 5.2. 修复脏线(Dirty Lines)及不合适的边缘(Borders)

源、编码、透明度对比

:源是指高质量可以用于进行压制编码的视频,一般包括蓝光圆盘、高质量的Web(一般4K的SDR)等。压片时应采用 最优质的源 进行压制,提高压制质量。

随着很多老片的BD推出,很多蓝光源是从低分辨率拉到高分辨率,被称为 Upscaled,在压制时应注意复原为原版的分辨率,不要压制过高的分辨率。关于WEB源应谨慎使用,尤其1080p的web-dl一般都为低质量不可以进行二次压制源,如非必要请勿压制,4k的SDR web源目前评价较好,往往好于1080p的BD来源,对于压制1080p的视频可以进行比较使用。

!!!对于已经编码过的视频禁止二次编码!!! (通常而言,二次编码违反选择最优质源进行压制的原则。)

编码:编码是指对于高质量来源进行压缩编码,进一步节约体积。编码过程种主要进行片源处理,修复源较为明显常见问题,通常包括脏边、色带、碎块、颜色偏差、伽马矫正等;切除黑边,去除源中16:9比例下的黑色边框;压制空间,主要将源采用更高的压缩方式进行重新编码,通常为有损方式。

透明度(Transparency):透明度是评价源于编码之间的相似程度的指标。良好的透明度是指在有经验的编码人员下都不能较为明显区分压制作品与源之间的差距。(此条不适用于 Anime 环境,二次元压制组看法不尽相同)

这个概念在外站(指PT)会比较流行

“透明度”指的是编码输出与源视频的匹配程度。一个更“透明”的编码成品会看起来更接近原始视频,而透明度较低的成品则会有明显的压缩瑕疵(compression artifacts)和/或失真。
实现完美的透明度几乎是不可能的(尤其是在考虑到诸如抖动(dithering)之类的随机变量后)。编码的最终目标之一就是获得“透明”的编码成品,也就是尽可能地接近源视频。

一个“透明度”较高的视频通常意味着码率很高,通常高于源视频码率的50%。比较直观的说明是,当我觉高码给9000kbps(x265)的时候,外站压制给的20Mbps(x264)。

而对于我们组,我们并没有硬性要求,你可以基于透明度压制,也可以适当的控制码率。

根据I、P、B帧的功能,在编码过程中,编码器一般会尊重I帧内容,哪怕再劣质的压制,都不会对其进行明显的转换;而针对p帧,编码器可以转化为B帧进行编码节约空间,对于B帧进行重新编码。因此透明度应该从源与压制中P->B以及B->B的转换质量对比评判的压制质量。

码率:码率是视频质量的基石,在编码一样,参数不乱给的情况下,不存在任何魔法能做到低码吊打高码。大部分视频压制参数或压制脚本的调整主要是为了码率分配以及视觉上的优化。如果你的目标是学习魔法的话,再次提醒,不存在这种东西,也注意不要在这块浪费精力。如果你想学习压制,你需要做的是根据视频画面给到足够的码率。再再次提醒,如果你之前没接触过相关信息,那么请忘掉你现有的对压制的任何观点,因为大部分都是错的。

Bloating:称为臃肿,是指实现在相同透明度情况下,码率较高。根据压制较为广泛接受的规则,当压制作品太过接近源的码率也被认为 Bloating,数值如下表:(x265建议更小的比例)

1080p 720p 576p 480p
原盘码率比例 75% 50%

x264 与 x265

在获取比 VapourSynth 更容易找到的 x264 和 x265 编码器前,你也可以选择使用它们的修改版。 最主流 x264 的修改版是 tmod 。值得注意的改进包括 淡化补偿(fade-compensate) ,在 宏块树(mbtree) 开启的情况下对淡入淡出进行编码,以及更多的 自适应量化(aq-mode) 选项。而如果你希望在转码时更加精确地控制,毫无疑问你应该尝试使用 tmod 并捆绑使用它提供的aq-mode,这样你就能够从中榨取出更高的质量,从而在保护噪点的同时不至于破坏线条。

x265的优势在于它能够存储HDR信息,而且效率高得多,特别是类似低码率动漫这样的简单内容。

最主流的 x265 修改版则是 yukki ,相比 x264 的修改版它却没有那么让人印象深刻。所有这一切都包括一些外观上的变化,比如更准确的预计完成时间。

8-bit 与 10-bit

x264 8-bit,x265 10-bit。对于x264,8-bit有更多的硬件兼容性(10-bit几乎没有),而且速度明显更快。然而,10-bit x264通常能够节省相当多的空间,同时仍然比x265快。此外,10-bit编码在保留梯度方面要好得多(也就是说,你不必担心色带再次出现),这使得它在编码无噪点内容(比如动漫)方面非常受欢迎。

参数
x264参数(1080p)
注意事项,level 4.1 不支持 1080p@60fps,,4.2 ptp 会提示 DXVA: Incompatible,这主要涉及一个早期设备的硬解兼容性问题,比较直观的解释就是 6年前的 firefly-rk3288 的开发板都支持 2160p@60fps 的 H264 硬解。

而 x265 吃了后出的红利,基本不用担心这块,不过也有逗逼不懂喜欢瞎设 level-idc,遇到这种的你知道他是菜逼就行了。

1
--crf * --preset placebo --profile high --level 4.1 --no-fast-pskip --threads auto --deblock -3,-3 --me umh --subme 11 --vbv-bufsize 78125 --vbv-maxrate 62500 --colormatrix bt709 --colorprim bt709 --merange 48 --rc-lookahead 60 --aq-mode 2 --no-mbtree  --no-dct-decimate --min-keyint 24  --ipratio 1.3 --pbratio 1.2 --aq-strength 0.8 --qcomp 0.65 --psy-rd 1.05:0.00 --bframes 16

(crf可以用18)
ref说明

  • 480p ref=16
  • 576p ref=14
  • 720p ref=9(-12)
  • 1080p ref=5

ref开太高的话,ptp会提示 DXVA: Incompatible

请注意ref的计算,分辨率切黑边会导致 ref 可设置值下降,留空会自动计算

ref计算方法(机翻):

对于 --level 4.1,根据 H.264 标准,最大 DPB(解码图片缓冲区)大小为 12,288 千字节。由于每个帧都以 YV12 格式存储,即每像素 1.5 字节,因此 1920x1088 帧为
1920 × 1088 × 1.5 = 3133440 字节 = 3060 千字节。
12,288 ÷ 3060 千字节 = 4.01568627,因此您最多可以使用 4 个参考帧。
请记住,在进行计算时,将两个维度向上舍入为 mod16 值,即使您没有对 mod16 进行编码!让我们对 1920x800 进行计算。
1920 × 800 × 1.5 = 2304000 字节 = 2250 千字节。12,288 ÷ 2250 千字节 = 5.45777778,因此最多可 以使用 5 个参考帧。请注意,这些转换使用基数 2,
1 千字节 == 1024 字节。如果计算错误,也没关系 - 如果使用太多,x264 将显示警告,你会知道是否需要更改它。

x265 1080p 非HDR参数(仅供参考)

1
-D 10 --preset veryslow --ctu 32 --rd 6 --subme 7 --ref 6 --no-rect --no-amp --rskip 0 --tu-intra-depth 4 --tu-inter-depth 4 --range limited --no-open-gop --no-sao --rc-lookahead 100 --no-cutree --bframes 8 --vbv-bufsize 160000 --vbv-maxrate 160000 --colorprim bt709 --transfer bt709 --colormatrix bt709 --deblock -3:-3  --no-strong-intra-smoothing --ipratio 1.3 --pbratio 1.2 --qcomp 0.65 --aq-mode 2 --aq-strength 1.0 --psy-rd 1.00 --psy-rdoq 1.00

x265的HDR参数(仅供参考,HDR参数需要计算,不能直接使用)

1
-D 10 --crf * --preset veryslow --bframes 8 --me 3 --subme 7 --ref 6 --ipratio 1.3 --pbratio 1.2 --aq-mode 2 --aq-strength 1.00 --qcomp 0.60 --psy-rd 1.5 --psy-rdoq 1.00 --ctu 64 --rc-lookahead 100 --deblock -3:-3 --no-strong-intra-smoothing --cbqpoffs 0 --crqpoffs 0 --qg-size 8 --range limited --no-frame-dup --selective-sao 0 --no-cutree --tu-intra-depth 4 --no-open-gop --tu-inter-depth 4 --rskip 0 --no-tskip --no-early-skip --min-keyint=1 --no-rect --no-amp --vbv-bufsize 160000 --vbv-maxrate 160000 --no-sao --aud --repeat-headers --hrd --hdr-opt --colorprim bt2020 --colormatrix bt2020nc --transfer smpte2084 --chromaloc 2 --master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(40000000,50)" --max-cll=577,512

其中的HDR参数应根据源进行计算设置

压制环境构建

全套软件打包(请联系相关人员获取)

便携版压制软件带集成环境

https://github.com/FXXS-Encoder/MediaTool (私有,需要申请权限)

VS集成环境(其他人维护,脚本可能不太全,ffms2等版本存在已知issue)

https://github.com/theChaosCoder/vapoursynth-portable-FATPACK

vapoursynth-classic 老版本维护(组内成员请勿使用)
https://github.com/AmusementClub/vapoursynth-classic

通常建议及时更新工具版本。

编码器

使用压制工具大部分核心都是x264和x265(x265如无必要不在重复)。本人推荐压制软件功能越为简单越好,比如适合新手的Simple x264/x265 Launcher或纯命令行(CLI)。Simple x264/x265 Launcher下载安装即可使用,本教程将以此为基础进行讲解。工具需要简单的设置,推荐log文件保存等设置,根据个人习惯修改。

image-20200210024626480

VapourSynth

官方文档

VapourSynth是基于python编写新一代的视频处理工具,解决了许多AVS遗留的问题,显著提高了运行速度。

Python : 安装VS之前必须装好Python环境,不同VS版本要求的Python版本不同,下载安装前请先看好所需要的Python版本。安装时候必须选择 Add Python to PATH !!

VapourSynth : VapourSynth的主体安装程序,安装过程推荐安装所有推荐内容。除了安装位置外推荐使用默认设置。安装完后只包括主程序,以及官方的自带的插件,VS使用过程需要大量的插件以及脚本:主要分为 Script(.py)脚本Plugins(.dll)插件 两个部分。安装插件脚本,需要将对应文件放入对应目录,目录在官方文档内有详细介绍。在Windows下官方提供了方便的下载管理。下文对于使用到部分将会介绍。

请注意脚本主要是 Python 环境,Python 版本兼容,通过 import 加载,而dll加载与VS本身,是需要考虑系统兼容,通过 core.XXX 加载,很多插件没有 Release Linux 版本,所以 Linux 环境可能会有部分插件需要自己想办法编译或者没法编译。

口语环境里,很多人会把脚本也叫成插件,但自己注意区分,以免造成混淆

VS 最新提供了制作便携版的脚本,但需要注意,升级会需要一些手动操作,如 python 的 vs 包无法卸载。如果是个人使用搭建,建议用安装包

VapourSynth 文档中列出了放置插件的路径。

Windows 的推荐路径<AppData>\VapourSynth\plugins32<AppData>\VapourSynth\plugins64。Unix 用户可以创建一个配置文件来指定路径。

VapourSynth的Python脚本应该放在你的Python site-packages文件夹中。在 Arch Linux上,位于 /usr/lib64/Python3.*/sitepackages/。Windows 用户可以在本地AppData文件夹【译者注:即C:\Users\<用户名>\AppData\Local】中找到这个文件夹。

需要注意的是 Python 自身也会有个 site-packages 文件夹,注意不要放错位置或者混放,可能会造成不知道加载了什么东西的问题

VSRepoGUI :官方提供了方便的下载管理插件以及脚本的GUI界面,下载解压后点开后即可使用,推荐放在VS的安装目录内。

通过软件可以查看对应的VS安装信息和脚本插件的所在位置,同时可以实现对插件的脚本安装、更新和卸载,软件插件安装位置,再右上角可以快速点开。在Windows下推荐本软件进行维护插件和脚本。

VSRepoGUi 操作的是 vsrepo.py,这个脚本也可以手动使用,只是要在相应的路径里用,它会维护一个 json.一般来说,直接使用脚本可以看到报错。

VapourSynth 编辑器

VapourSynth Editor :VS Editor是目前较为广泛使用的VS编辑器(目前会使用Mod版本)。下载后,直接解压即可使用。第一次使用时候,需要配置VapourSynth文件的位置。VS plugins paths 可以是用VSRepoGUI中的路径进行查看。

Yuuno 是 Jupyter 记事本的一个扩展,允许你编辑和导出 VapourSynth 脚本。你可以通过以下代码来安装。

1
2
$ pip install yuuno
$ yuuno jupyter install

注意你需要安装 Jupyter 或 Jupyter Lab。

VapourSynth Preview 需要一个单独的文本编辑器或 IDE 来编写脚本,这使得它对那些不喜欢 VSEdit 中内置编辑器的人来说非常有用。
AvsPmod是用于 AviSynth 的编辑器,但它也支持 VapourSynth。

它们都有各自的优点和缺点,但对于新手来说,我更推荐 VSEdit 进行本地编辑,而希望在服务器上也能够写脚本的用户,更推荐 Yuuno。这是因为 Jupyter 只需要少量配置就可以远程使用。建议 Yuuno 用户试试使用 Jupyter Lab 替代 Jupyter。

此处举例两者最大的差别:

VSEdit

  • 不需要保持浏览器开启
  • 内置基准和编码工具
  • 通过CTRL + SHIFT + 方向键轻松浏览视频
  • 更稳定
  • 几乎无需二次开发
  • 大多数PT用户在使用它,因此它可能更容易获得帮助与支持
  • VapourSynth 特有的语法高亮及输入建议
  • 允许你存储片段和模板

Yuuno

  • 非常易于远程使用
  • 可以通过 iPython magic 轻松导出
  • 更好的比较工具,通过使用%%vspreview clipa --diff clipb ⇒ 实现鼠标悬停即可预览更改效果
  • 程序不太成熟,因此更可能发生崩溃
  • 允许你在一个 Jupyter 编辑器中处理和导出多个脚本

常用其他软件

  • Mediainfo :媒体信息检查软件,查看片源以及压制信息使用。
  • MKVToolNix: mkv混流软件,也能实现以下基本的视频分割。
  • SubtitleEdit: 字幕编辑软,可以实现ORC等功能。
  • DGDemux: Demux 软件,目前作为默认标准的Demux软件
  • eac3to: 存在已知Issue音轨转码编辑软件,也可实现Demux等功能。推荐使用eac3to with UsEac3to版本,并应包含一些对应的其他转换格式插件。
  • BDinfo: 蓝光原盘信息检测分析软件。
  • VLC: 能播放蓝光菜单,辅助确认音轨字幕章节信息

其他请参考 软件列表

基础部分软件直接使用或者安装即可。
AVS和VS为两种方向,推荐选VS

AVS相关教程Archive

压制步骤

压制源分析

要想做一个较为高质量作品,应采用最好的来源进行压制。HDR电影来源较为单一,4k的原盘和Remux资源为主,版本较少能选择不多。SDR目前可用压制版本较多,各个发行商的在不同时期也发行过不同蓝光版本,随着web的兴起,AZ和NF也都发布了较高码率的4k的sdr版本,所以在SDR压制时,需要对于来源进行对比,选取最为高质量的来源进行压制。对于蓝光原盘与remux两者相同时候,推荐使用Remux的更为方便。

对于原盘使用 BDInfo 检查原盘信息,查看原盘主要视频对应播放列表。对于复杂原盘,可能出现多版本混合的情况,需要确定所需要版本对应的MPLS,并确定原盘的主要码率 。在压制前推荐进行分离提取(Demux)后再进行压制。

image

分离提取(Demux)与音频转换

Demux&Remux以及Audio

输入脚本编写

压制前一般需要对片源就行处理,一般包括去除黑边、修复脏边脏线、去除片源的一些问题等,并且在压制时一般需要进行部分压制测试,也需使用脚本进行实现。本节将对介绍压制中的最基本脚本的编写,分为VS和AVS两个部分。编写脚本使用对应的编辑器较为方便。以及基础例子如下

avs例子

1
2
3
4
5
FFVideoSource("J:\BluryBD\After.the.Storm.2016.BluRay.Remux.1080p.AVC.TrueHD.5.1-HiFi.mkv")
Crop(0, 20, -0, -22)
FillBorder(0,1,0,0)
bbmod(2,0,0,0,128,21)
Z_Spline36Resize(1280, 692,dither="error_diffusion")

VS例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import vapoursynth as vs
#import kagefunc as kgf
import fvsfunc as fvf
import havsfunc as haf
#import vsTAAmbk as taa
#import mvsfunc as mvf
#import muvsfunc as muf
#import nnedi3_resample as nnrs
#import nnedi3_rpow2 as nnrp
import awsmfunc as awf
#import vsscale
import vsutil
#导入相关函数(上面导入的很多范例脚本中没有使用,不过去交错那用到了haf),awsmfunc早期包没包含,故先注释掉
#core = vs.core 在R55 API4及之后版本使用,早期版本可以使用vs.get_core()
#core = vs.get_core()
core = vs.core
#请依据自己内存调整(单位MB),通常16GiB的内存,设到8000左右就好了,x265还会占用一定内存,复杂脚本内存占用较高,开高了别的进程会卡慢。如果有这现象,可以再调低一些。大内存的话可以调高或者取消限制
core.max_cache_size = 8384

#加载片源输入即为16bit色深
src = core.lsmas.LWLibavSource(source=r"J:\BluryBD\After.the.Storm.2016.BluRay.Remux.1080p.AVC.TrueHD.5.1-HiFi.mkv",format="yuv420p16")


#另一种加载片源
#src = core.ffms2.Source(source=r'J:\BluryBD\After.the.Storm.2016.BluRay.Remux.1080p.AVC.TrueHD.5.1-HiFi.mkv')

#通常来说,有些比较特殊的片源可能在ffms2或lsmas下会有不正常的表现或者报错,故有时候需要更换使用,例如 VC-1 lsmas 下不正常

#PsF (站内搜索) 部分插件会检测是否交错 > UnsupportedFieldBasedError('Only progressive video is supported!', func)
#src = core.std.SetFieldBased(src, 0)


#处理前调整为16bit色深,可以降低运算带来的损失,lsmas不需要这个步骤
#src = fvf.Depth(src, 16)

#切边
src=core.std.Crop(src, left=0, right=0, top=20, bottom=20)

#脏边处理相关
#FillBorders基本是复制一条或几条线,作为填充,在任何情况下都不建议超过一条使用
#src = core.fb.FillBorders(src, 0, 1, 0, 0, mode="fillmargins")
#src = core.edgefixer.Continuity(src,left=4, right=4, top=0, bottom=0)
#src = awf.fb(src, top=1,bottom=1)
#如果边缘呈灰色,awf.fb 可以填充 luma&chroma
#src = awf.bbmod(src,left=3, right=6, top=10, bottom=4, thresh=30, blur=20)
#对于边缘本身不是正常画面的,可以接一下bbmode,但请注意,严禁乱用,具体参数请看Pro mit 翻译的AHD压制指南(Others里)

#AutoDeblock(请在指导下使用)
#src = fvf.AutoDeblock(src)

#将分辨率(压制为720p)
#src=core.resize.Spline36(src, 1280, 692)

#另一种缩小算法,gamma是HDR才需要开启
#src = muf.SSIM_downsample(src, 1280, 692, use_fmtc=False,gamma=True)
#src =vsscale.scale.ssim_downsample(src, width=None, height=720)

#去交错(正常不需要使用)
#src = haf.QTGMC(src, Preset="slow", TFF=True)

#setFPS
#部分情况下,软件会判断错误的FPS,例如mediainfo里同时包含 Frame rate 和 Original frame rate
#src = core.std.AssumeFPS(src,fpsnum=60000, fpsden=1001)

#去锯齿
#src = taa.TAAmbk(src, aatype=-3, preaa=-1, strength=0, mtype=2, opencl=True)

#转为10bit再输出,x265一般压制为10bit,x264为8bit
#之前得降bit函数
#src = fvf.Depth(src, 10)

src = vsutil.depth(src, 10, dither_type='error_diffusion')
src.set_output()

Tips:

修复脏边脏线以及去色带等属于进阶部分,将单独介绍

VS由C++编写的核心库和允许创建视频脚本的Python模块组成,脚本部分作为Python模块实现,因此脚本完全使用Python语法

看这里以便于理解vpy写法以及含义

Python 文档https://docs.python.org/zh-cn/3.9/reference/index.html

VS文档http://www.vapoursynth.com/doc/pythonreference.html

其中最前面的

1
2
3
4
5
6
7
8
9
10
import vapoursynth as vs
import kagefunc as kgf
import fvsfunc as fvf
import havsfunc as haf
import vsTAAmbk as taa
import mvsfunc as mvf
import muvsfunc as muf
import nnedi3_resample as nnrs
import nnedi3_rpow2 as nnrp
#import awsmfunc as awf

就是 python 的 模块/modules导入/import

片源载入(Index a video)

载入片源需要使用对应的解码器

可用的索引器可供考虑

  • bestsource
    最准确但最慢的索引器。
  • lsmas
    速度快,基本可靠。
  • ffms2
    最新版本与 lsmas 相当,甚至可能更快。

DGIndexNV 在技术上也是您可以使用的,但最新版本存在错误,并且仅限于 Nvidia GPU。

avs语法

1
FFVideoSource(str filePath) #指定文件的路径

VS语法

1
src = core.ffms2.Source(str source) #指定文件的路径

Tips:

1.右键可以直接选择插入文件完整路径。

2.首次执行载入预览会卡死,需要等待一定时间。

切除边缘

avs语法

1
Crop(clip, int left=0,int top=0,int -right=0,int -bottom=0) #切割必须为偶数,right与bottom为负数

VS语法

1
clip=core.std.Crop(clip, int left=0, int right=0, int top=0, int bottom=0) #切割必须为偶数

Tips:

1.Crop切割方式只能以偶数方式切割,奇数切割属于进阶内容

2.切割奇数边需要使用下节介绍的resize方法

变换大小

avs语法

1
z_Spline36Resize(int Width, int height, int src_left=?, int src_top, int src_width, int src_height, str dither) #

VS语法

1
clip = core.resize.Spline36(clip clip, int Width, int height) #

抽取测试

压制前使用脚本一般间断抽取共约5k~10K帧进行参数测试,需要在脚本进行抽取。

avs语法

1
SelectRangeEvery(int every, int length, int offset) #every为间隔,length为长度,offset为启示帧数

VS语法

1
2
select=core.std.SelectEvery(clip[8000:-8000],cycle=4000, offsets=range(10))
clip= core.std.AssumeFPS(select, fpsnum=clip.fps.numerator, fpsden=clip.fps.denominator)

压制测试

在压制前应该进行参数测试,以便获取较高的压制质量,一般需要确定合理码率大小(crf)以及对于码率分配参数(ap-mode、ap-s、qcomp)以及psy等重要参数进行测试。使用抽取测试代码,大约抽取6k帧进行参数测试,送入Simple-x264进行测试。

压制参数配置

使用Simple进行压制,其设置如下所示。在设置界面记得开始log自动保存!!!

image-20200220003824403

1
--level 4.1 --threads auto --vbv-bufsize 78125 --vbv-maxrate 62500 --colormatrix bt709 --colorprim bt709 --no-mbtree --no-dct-decimate --min-keyint 24 --me umh --merange 48 --deblock=-3,-3 --ipratio 1.3 --pbratio 1.2 --qcomp 0.6 --aq-mode 1 --aq-strength 0.8 --psy-rd 1.00:0.00

CRF测试

CRF测试主要确定合适码率,根据压制目标,确定合理的码率。推荐测试起始CRF为17,根据范围码率以0.5步进进行CRF测试。

合理码率评判方式
追求体积

压制效果受码率影响很大,在追求体积时,很容易造成欠码的问题。所以要设置合理的码率范围,防止出现因为码率不足导致的质量问题。需要主要检查需要码率较高的场景,例如,复杂的场景和暗的场景。

主要辨别问题有:

  • 是否新产生了新的block
  • 复杂的场景的细节是否丢失
  • 是否压出明显的色带
保证与原盘相似透明度

前景无损失,背景没有明显损失

其他参数

本部分十分建议进行,但是对于一些压制组不是强制要求。可以编写脚本进行批量测试

确定合理的码率后,切换2-pass方式使用预计码率,采用单一变量方式进行参数测试,每次测试只改变一个参数,每个参数推荐测试范围如下:

参数 真人类型 步进
qcomp

最终CRF测试

在新参数下,进行最终使用的crf测试。

压制对比脚本编写

avs语法

1
2
3
4
5
6
7
8
# 导入压制使用的脚本文件,并添加帧信息与名字
a=import("C:\Path\To\source.avs").subtitle("Source", align=9).ffinfo(framenum=true,frametype=true,cfrtime=false,vfrtime=false,version=false,cropping=false,colorrange=false,colorspace=false,sar=false)
# 导入压制后的对比的视频文件
b=ffvideosource("C:\Path\To\b.mkv").subtitle("b", align=9).ffinfo(framenum=true,frametype=true,cfrtime=false,vfrtime=false,version=false,cropping=false,colorrange=false,colorspace=false,sar=false)
# 其他的压制文件
c=ffvideosource("C:\Path\To\c.mkv").subtitle("c", align=9).ffinfo(framenum=true,frametype=true,cfrtime=false,vfrtime=false,version=false,cropping=false,colorrange=false,colorspace=false,sar=false)
# 交错视频文件
interleave(a,b)

VS语法

下面的代码大部分已经不能在最新的VS里使用,仅作参考,请使用 awf 以及 Scrips 里的 snap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import vapoursynth as vs
core = vs.get_core()

# 生成帧信息,并打入标签
def FrameInfo(clip, title,
style="sans-serif,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,7,10,10,10,1"):
import functools
def FrameProps(n, clip):
clip = core.sub.Subtitle(clip, "Frame " + str(n) + " of " + str(
clip.num_frames) + "\nPicture type: " + clip.get_frame(n).props._PictType.decode(), style=style)
return clip

clip = core.std.FrameEval(clip, functools.partial(FrameProps, clip=clip))
clip = core.sub.Subtitle(clip, ['\n \n \n' + title], style=style)
return clip

# VS editor输出显示bug,对于压制后的文件需要进行,进行处理。
def outfix(clip):
encode = core.std.SetFrameProp(clip,prop="_Matrix",delete=True)
encode = core.std.SetFrameProp(encode,prop="_Transfer",delete=True)
encode = core.std.SetFrameProp(encode,prop="_Primaries",delete=True)
return encode

#-------------用于压制脚本的滤镜部分(例子)----------------#
#复制自己脚本出了导入,和输出部分内容
video = core.ffms2.Source(source=r'/Users/hujingyu/Encode/Paris.Texas.1984.1080p.BluRay.Remux.AVC.DTS-HD.MA.5.1-PmP.mkv')
video=core.std.Crop(video,64,64, 0, 0)
select=core.std.SelectEvery(video[8000:-8000],cycle=4000, offsets=range(80))
video= core.std.AssumeFPS(select, fpsnum=video.fps.numerator, fpsden=video.fps.denominator)
#-------------用于压制脚本的滤镜部分----------------#
video=FrameInfo(video,"source")# 标记信息
#-------------encode文件-------------------------#
encode=core.ffms2.Source(source=r"/whalehu/Encode/encode.mkv") # 载入视频
encode=FrameInfo(encode,"encode") # 标记信息
encode=outfix(encode)# 输入修复

out = core.std.Interleave([video,encode]) # 交叉帧
out.set_output()

正式压制

将压制脚本中的测试抽帧代码注释掉,进行正式压制。

清晰度越高需要的时间越长,推荐使用较低的分辨率入门

封装

封装是将所有素材合成一个mkv的视频文件,封装是一个很简单的工作,没有技术难点,但是封装的好坏会对压制作品评价很为重要,封装主要是认真。这里主要介绍被广泛接受的封装细节,不同压制组对这个有具体的细节要求。

一般封装主要注意以及下内容:

  • 视频、音轨和字幕是否匹配

  • 音轨和字幕是否设置了正确的语言标签

  • 需要标准命名的音轨是否正确

  • 章节信息和标题是否添加并正确命名

  • 正确命名文件标题

文件标题并不是文件名!!!一般主要为IMDB的英文标题并可以添加小组信息

VapourSynth 脚本(vpy) Filtering 基础滤镜以及处理

缩放(Resizing)

首先请注意,后面会有一个单独的部分来介绍 还原分辨率(Descaling) 。而在这,我将解释调整大小的方法以及哪种调整器分别适合什么情况。
如果你想调整大小,重要的是不要超过必要的长宽比的改变。如果你要缩小尺寸,首先要搞明白宽度和高度应该是多少。如果你想缩小分辨率到720p,首先要裁剪,然后弄清楚你是缩放至720高还是1280宽。如果是前者,你的宽度应该是:

1
width = round(720 * src.height / (2 * src.width)) * 2

对于后者,你会发现高度的代码与其非常相似:

1
height = round(1280 * src.width / (2 * src.height)) * 2

你也可以使用 awsmfunc 中封装的 cropresize 函数来处理这些计算并调整大小。

现在有多种调整工具可选,其中最主要的有:

  • Point 临近点,也被称为临近采样(nearest neighbor resizing),是最简单的缩放方式,因为除了放大每个像素或缩小时获取周围每个像素的平均值,并没有真正做任何事情。它产生的结果很糟糕,但在放大时不做任何模糊处理,因此它非常适用于放大检查每个像素的值。它也是自我矛盾的,所以你可以用它放大然后再缩小,得到与开始时相同的结果。
  • Bilinear 双线性,缩放处理速度非常快,但会导致非常模糊的结果,并有明显的 锯齿(aliasing) 现象。
  • Bicubic 双立方,缩放处理速度同样很快,但也会导致相当模糊的结果和明显的锯齿。你可以在这里修改参数以获得更清晰的结果,但这将导致更多的锯齿。
  • Lanczos 缩放速度较慢,但可以得到非常清晰的结果。然而,它会产生了非常明显的振铃(ringing) 伪影(artifact) 。
  • Blackmanminlobe 一个 lanczos 的改良版(需要通过 fmtconv 来调用它缩放)具有较少的振铃伪影。这种调整工具对于YUV444编码的色度提升绝对值得考虑(稍后会详细介绍)。
  • Spline 其缩放速度相当慢,但可以得到非常好的结果。有多种 Spline 调整工具可用,Spline16Spline36 快,但效果稍差,而 Spline36Spline64 效果十分相似,所以没有理由使用后者。推荐在缩小分辨率(downscaling)时使用 Spline36
  • nnedi3 其调整大小的速度相当慢,而且只能以2的幂数进行 放大像素(upscale) 。它也可以与 Spline36 结合起来,先将其分辨率放大,而后缩小所需的分辨率。结果明显好于前述的内核。
  • FSRCNNX 是一个用于 mpv 的着色器,可以通过 vs-placebo 插件使用。它提供了远比 nnedi3 更清晰的结果,但需要GPU的支持。如果可以的话,建议使用它来进行放大分辨率。

附录中提供了这些调整工具的效果比较,图16为降低分辨率,图17为放大像素。此外,由于更改 bicubic 的参数将输出非常显着区别的结果,因此在附录图18还包括了对不同参数配置的 bicubic 放大比例的比较示例。为了满足更强的好奇心,我在图19中加入了缩小至原始分辨率后的对比,并且在附录中的图20中展示了同一调整工具先缩小再放大的情况。

虽然这些截图应该可以帮助你对不同缩放方法之间的差异有一个大致的了解,但它们只是单个画面的一小部分。如果你想更好地了解这些调整工具对整体画面的影响,我建议你自己动手使用,在动态中观察它们,并将它们交错在一起(std.Interleave)进行对比。

降低分辨率时不同调整工具之间的差异比放大时要小得多。 但不建议以此为借口,在降低分辨率时因偷懒而随意选择调整工具。

简而言之: 用 core.resize.Spline36 来缩小分辨率。

修复脏线(Dirty Lines)及不合适的边缘(Borders)

另一个非常常见的问题,至少在真人电影的内容中,是脏线。这类问题通常出现在视频的边界上,与周围的行相比,某一行或某一列的像素通常表现出过低的亮度值。通常情况下,这是由于不适当地缩小分辨率,更明显的是在应用边框后的缩小分辨率。脏线也可能发生,因为视频编辑者往往不知道他们是在YUV422下工作的,这意味着他们的竖向像素值不必是偶数;而消费者内容将是YUV420,意味着竖向像素值必须是偶数,导致额外的黑行。

另一种形式的脏线是在黑条上出现色度平面时表现出来的。 通常情况下,这些应该被裁剪掉。然而,相反的情况也可能发生,即具有合法的亮度信息的平面但缺乏色度信息。 有六种常用的滤镜用于修复脏线。

  • cfContinuityFixer

    ContinuityFixer 的工作原理是将指定的行/列与周围范围指定的行/列数量进行比较,通过最小二乘法再回归找到新值。其设置如下:

    1
    fix = core.cf.ContinuityFixer(src=clip, left=[0, 0, 0], right=[0, 0,0], top=[0, 0, 0], bottom=[0, 0, 0], radius=1920)

    这是假设你使用的是1080p的素材,因为半径的值被设置为源的分辨率所定义的最长的集合。我建议使用一个更低的值,但不要低于3,因为在这一点上,你可能是在复制像素(参见下面的FillBorders)。可能会让大多数新手感到困惑的是,我输入了一个数组,作为要固定的行/列的值。这些值表示要应用到三个平面上的值。通常情况下,脏线只会发生在亮度平面上,所以你通常可以把其他两个平面的值保持为0。 请注意,数组并非必须,因此您也可以只输入希望应用修复的行/列的数量,所有平面都会被处理。
    ContinuityFixer 最擅长的一点是去除不规则的东西,比如点。 它也比 bbmodFixBrightnessProtect2 快,但它应该被视为这两者的备选方案。

  • awsmfuncbbmod

    这是原BalanceBorders 函数的一个修改版。它与 ContinuityFixer 非常相似,但在更高的 模糊值(blur)阈值(thresh) 的情况下会产生更好的效果。如果它没有产生去分的结果,可以改变这些,但是你设置的模糊值越低,这个函数的破坏性就越大。它也比 havsfuncsgvsfunc 中的版本快得多,因为只有必要的像素被处理。

    1
    2
    import awsmfunc as awf
    bb = awf.bbmod(src=clip, left=0, right=0, top=0, bottom=0,thresh=[128, 128, 128], blur=[20, 20, 20], scale_thresh=False,cpass2=False)

    threshblur 的数组也是Y、U和V的值。建议先试试 blur=999,然后尝试降低这个和 thresh 的值,反复尝试,直到你得到合适的效果。
    thresh指定了结果可以和输入值相差多少。blur 是过滤器的强度,数值越低越强,数值越大则越弱。如果你设置 blur=1 ,你基本上就等同于复制行。

  • fbFillBorders

    这个函数几乎就是复制下一列/行的内容。虽然这听起来很傻,但当分辨率缩小导致更多的行在底部而不是顶部,并且由于YUV420的偶数的竖向像素值,我们不得不填充一行时,它就会非常有用。

    1
    fill = core.fb.FillBorders(src=clip, left=0, right=0, bottom=0, top=0, mode="fillmargins")

    这个函数的一个非常有趣的应用是类似于只对色度平面应用 ContinuityFixer,它可以用在灰色边界或无论应用什么亮度平面修复的修复方法都与边界不匹配他们的环境时。这可以用下面的脚本来完成:

    1
    2
    fill = core.fb.FillBorders(src=clip, left=0, right=0, bottom=0, top=0, mode="fillmargins")
    merge = core.std.Merge(clipa=clip, clipb=fill, weight=[0,1])

    你也可以分离平面并单独处理色度平面,尽管这只是稍微快一点。允许您为fb【译者注:core.fb】指定每个平面值的封装函数是 awsmfunc 中的 FillBorders

  • edgefixerReferenceFixer

    这需要原始版本的edgefixer(cf只是它的一个旧的移植版本,但它使用起来更漂亮,处理过程也没有改变)。我从来没有发现它有什么用处,但从理论上讲,它是很好的。它与一个参考素材进行比较,以调整其边缘固定。

    1
    fix = core.edgefixer.Reference(src, ref, left=[0, 0, 0], right=[0, 0,0], top=[0, 0, 0], bottom=[0, 0, 0], radius = 1920)
  • rektrektlvls

    这基本上是 FixBrightnessProtectFixBrightness 的合二为一,另外还有一个事实,即不是整个画面都被处理。它的参数非常简单明了,提高调整值可以变亮,降低调整值可以变暗。将 prot_val 设置为0时,它的功能就与 FixBrightness相同,意味着调整值需要改变。

    1
    2
    from rekt import rektlvls
    fix = rektlvls(src, rownum=None, rowval=None, colnum=None, colval=None, prot_val=20)

    如果你想一次处理多行,你可以输入一个列表(例如,rownum=[0, 1, 2])。

有一点不应该被忽视的是,对太多的行/列应用这些修正(除了 rektlvls 之外)可能会导致最终结果看起来很模糊。正因为如此,我们建议尽可能使用 rektlvls,或只在必要的行上使用亮度修复。如果失败了,最好在使用 ContinuityFixer 之前先试试 bbmod

值得注意的是,你总是应该在调整大小之前修复脏线,否则做会引入更多的脏线。然而,更需注意的是,如果你在边缘使用 FillBorders 填充了一条黑线,你应该使用调整大小的工具来删除它。例如,要将一个顶部有一条填充线的片段从1920 × 1080调整为1280 × 536时应该这么做:

1
2
3
4
5
6
7
8
top_crop = 138
bot_crop = 138
top_fill = 1
bot_fill = 0
src_height = src.height - (top_crop + bot_crop) - (top_fill + bot_fill)
crop = core.std.Crop(src, top=top_crop, bottom=bot_crop)
fix = core.fb.FillBorders(crop, top=top_fill, bottom=bot_fill, mode="fillmargins")
resize = core.resize.Spline36(1280, 536, src_top=top_fill, src_height=src_height)

如果你要处理对角线的边框,正确的做法是使用蒙版覆盖源,用FillBorders 调用合并源。为此举一个例子(来自D-Z0N3压制的作品《你的名字》):

Figure5

图5:该示例为《你的名字》(Your Name (2016))中不恰当地使用边框。D-Z0N3的使用了蒙版,而Geek没有。 因此,Geek缺乏任何类似的纹理,而D-Z0N3则尽可能地保留它。使用 FillBorders 中的镜像模式可能更明智,但事后看来是20/20【译者注: “20/20视力”称为“完美”视力】。

D-Z0N3使用的代码(16-bit下):

1
2
mask = core.std.ShufflePlanes(src, 0, vs.GRAY).std.Binarize(43500)
cf = core.fb.FillBorders(src, top=6).std.MaskedMerge(src, mask)

在附录中的图22下有一个例子,说明为什么要使用蒙版。

为了说明脏线可能是什么样子,这里有一个 ContinuityFixer 和纯色的 FillBorders 对比的例子。

Figure6

图6:来源于的D-Z0N3的压制作品《无声的声音》(A Slinet Voice (2016))的脏线修复与过滤。在最上面的三行使用 ContinuityFixer,在最左边的两列使用FillBorders。 当前画面放大15倍。

脏线很难发现。如果你在随机检查不同帧的边界时候不能发现存在脏线,那么可能就没有问题。如果你发现有每边都有小黑线边界,那么可以使用类似下面的脚本:

1
2
3
4
5
6
7
8
9
10
11
def black_detect(clip, thresh=None):
if thresh == None:
thresh = (25 * (1 << clip.format.bits_per_sample) - 1) / 255
mask = core.std.ShufflePlanes(clip, 0, vs.GRAY).std.Binarize({0}".format(thresh)).std.Invert().std.Maximum().std.Inflate().std.Maximum().std.Inflate()
l = core.std.Crop(mask, right=clip.width / 2)
r = core.std.Crop(mask, left=clip.width / 2)
mask_test = core.std.StackHorizontal([r, l])
t = core.std.Crop(mask_test, top=clip.height / 2)
b = core.std.Crop(mask_test, bottom=clip.height / 2)
mask_test = core.std.StackVertical([t, b])
return mask_test

这个脚本将 threshold 以下的数值(即黑色边框)在大部分黑色背景的中部显示为垂直或水平白线。你可以运用这个函数来浏览并检查你的视频。你也可以尝试使用 blckdtct27,它可以为你扫描视频。

其他类型的可变脏线是一个修复难题(a bitch to fix),需要手动检查场景。

一个与脏线非常相似的问题是糟糕的边界(bad borders)。在不同场景中(例如IMAX或4:3),黑色边框有时可能不完全是黑色的,或者完全被打乱了。为了解决这个问题,只需将其裁剪并重新添加。你也可能想修复过程中可能出现的脏线:

1
2
3
crop = core.std.Crop(src, left=100, right=100)
clean = core.cf.ContinuityFixer(crop, left=2, right=2, top=0, bottom=0, radius=25)
out = core.std.AddBorders(clean, left=100, right=100)
打赏
打赏提示信息
分享
分享提示信息