自动化破解Kindle图书到图片

今天购入了日亚的Kindle Unlimited,瞬间有一大堆电子版的杂志要转换格式。

数量多了再用上文提到的手动方法就不行了,会烦死。于是琢磨着怎么能自动化。首先我想到一个简单的办法:既然高清图片都在.res文件里,那就直接把.res文件关联到那个python2脚本,然后直接extract图片就完了。

方法么自然就是修改注册表,也很简单,就加这么一句:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.res\shell\extract\command]
@="py -2 \"E:\\sync\\code\\python\\_example\\DumpAZW6_v01.py\" \"%1\""

(根据自己具体目录修改)也好使,使用之后会自动把图片提取到和输入文件相同的目录里。

然而好景不长,我刚搞了两本,就发现有的是只有部分图片有高清图——所以你得从.azw里提取所有的标清图片,然后把有高清版那些页数逐个替换进去。如此看来,不写个脚本是不可能简单实现了。

要写脚本,我们用到的工具都得有命令行版本才行。从azw提取图片可以用calibre的命令行工具ebook-convert.exe,或者用上述提取res文件的脚本作者开发的KindleUnpack(这个其实有图形界面,但是可以直接调用kindleunpack.py)。

但是有个重大问题:这两个工具都不支持有DRM的书(见追记)。所以,我们得先破解。calibre的命令行工具都是无法支持插件的见追记),所以我们得找到那个DeDRM插件作者单独提供的stand-alone版本

好不容易调试好python 2的环境,结果这工具一用就报错(已经装了pyCrypto)。自己debug了半天,发现是他藏得很深的用了一个lzma库,我没安装。按照代码去装backports.lzma,结果……装不上。在issues里看了下,果然有人报过,说白了就是作者的setup.py写的太烂对Windows不兼容。更囧的是作者研究了下,发现他自己搞不定所以这个issue就这么在这摊着。

说到这里不得不吐槽下python开发的库管理简直烦,所谓的platform independent某种意义上是个笑话,有许多库的开发者可能只用Linux/MacOS,这已经不是第一个我遇到的在Win下连安装都有问题的库了,更不要说使用了。

还好有人在另外一个issue里提供了一个wheel(编译好的版本),虽然非常老(0.0.3,现在已经是0.1.0),但是能用(见追记)。

这里其实有个插曲,我一开始装了这wheel之后还是不能用(连直接from backports import lzma都能报错),于是我一怒之下把deDRM工具里ion.py调用lzma的部分给删掉了,结果反而能用了,因为lzma其实只有对付上文提过的Kindle最新KFX格式才用得到。至于lzma不能用的问题?我干掉几个后台卡住的python.exe进程之后就好了。

OK,工具准备齐全,我们接下来要做的就是几步走:

  1. 用上文所述的azw6抽取脚本提取res里的高清图片
  2. 用deDRM tool的Windows application破解azw文件
  3. 用Calibre的命令行工具提取破解后的no_drm azw3里的图片
  4. 对比两组图片,把3里的部分用1里的高清图片替换。
  5. (可选)利用calibre命令行工具获取meta tag来给文件夹改名
  6. (可选)自动打包

其中1、2两步都有source code,理论上可以import进我的脚本里,但是因为这是python 2写的我决定还是直接process.call

虽然调试耗了不少功夫,但是最后结果还是相当满意的。代码比较丑陋这里就不放了,中间遇到的两个坑:

  1. 那个抽取AZW6的脚本里有句话是平淡无奇的print self.title(这是py2,print书籍的title而已)但是如果是飞ASCII的标题经常会在控制台卡住,报错“no such file or directory”(??)(经常是我手动运行不卡,用VS调用就卡),烦得很直接注释掉了。
  2. Python的re.match原来和re.search不一样……不一样。

追记

5月20日追记三点。

1是backports.lzma的第三方wheel版可以在这里下载。另外,DeDRM工具那边也已经修改了代码,让缺少LZMA有正确的提示(也在说明里提到了要有LZMA),并且也增加了对pylzma(另外一个py2有的lzma库,上面那个链接里也有wheel可以下,PyPI好像也有)的支持。

2是解压电子书。如上文所述,我现在用的是Calibre带的ebook-convert。这个的本质是把电子书转成网页/压缩包的形式,然后再解压(命令行就是ebook-extract 你的azw文件.azw temp.zip --extract-to 解压到的dir)。有个小问题就是转换成网页的时间有时候会很长。所以我又去试了下那个KindleUnpack——快是快很多没错,但是这个有个问题就是出来的图片名并不是从1开始,感觉上似乎是直接按照原始包的section来命名,比如第一页经常就是40多编号了。这个在后续处理,尤其是替换HD图片的时候非常不方便,所以还是放弃了。另外提示一下,这个的GUI还是CLI都要用py -2运行:否则虽然GUI能跑起来但是实际转换是要报错的。

3是ebook-convert无法处理deDRM的问题。我上面提过这个工具不支持deDRM——其实我是错的。理论上,Calibre的命令行工具都支持各种插件的。事实上,如果你用命令行工具calibredb:

calibredb.exe add book.azw

来加入一本encrypted的书,会自动调用插件deDRM。

但是问题在于,那个deDRM的插件在设置里把自己的类型设成了“仅添加时调用”。所以,在单纯convert的时候,并不会参与。这个是我去mobileread的论坛问了下才明白(顺便一提,那边的人回复好快!我发帖不到半小时就N个回帖了…)。

我自行修改了那个插件的__init__.py,添加了on_preprocess=True,立刻就可以在ebook-convert里调用了。而且,似乎没什么副作用,不会影响正常转换noDRM的图书。我在犹豫要不要建议插件作者自行加上。

这么搞了之后,上面的流程的第一步和第二步就可以合并了。但是我暂时还没这么做,因为这样得保证使用环境的calibre必须装了修改版的DeDRM插件才能用,不是很便于部署。

Advertisements

提取Kindle的azw+azw.res格式里的图片

Kindle之前如果在PC端下载,一直是只有单一的.azw文件,破解起来非常简单,用calibreDeDRM插件,可以轻松导入,然后就可以随便转成什么格式了(我一般买的都是画集之类的,转ZIP直接无损提取JPEG图片)。

但是,最近碰到两起,会遇到类似这样的情况:

QQ截图20180510204423
这是一本图片格式的杂志,其实azw文件里已经包含完整的内容——但是看大小,明显那个resource文件要大很多。事实上解包后可以看到,azw里含的图片是高压缩率的图片:每张图都控制在250K以内(有些的JPEG质量因子已经达到了40-60%之差),更可怕的是如果这样压缩还不够,它还会降分辨率,最差的一张直接从默认的1920px高降低到1242px。

QQ截图20180510205232
一张高压版的样图,惨不忍睹

这样的质量显然是无法接受的,那么自然可以想到,.res文件里包含了高清的图片版本。事实也是如此。实际上,这个.res文件,本质上是无DRM的azw6资源文件。解包方法藏得比较隐蔽,在mobileread的论坛里有个大神写了个脚本。注意要用Python 2运行(先把文件名改成.azw6,因为里面有判断)。遗憾地是calibre似乎暂时并不支持合并azw3+res的格式,所以是无可能简单把高清图和azw一起导入进去的。不过我反正只要dump图片而已所以也无所谓。

其实本文的正文到此就结束了,但是想稍微谈一下研究过程中绕的一个弯路,所谓的kfx格式。

附录:什么是KFX格式

Kindle从2017年起逐渐对新书引入所谓的KFX格式。说叫KFX,其实你用PC下载并不会见到这个后缀,只有在Kindle上下载才会:

Kindle content device

(图像出处,下同)

如果是直接用PC,下下来的其实是类似这样的文件夹:

Kindle KFX download via Kindle for pc/mac

可以看到,和我上面的格式很接近(虽然少了不少文件,汗),所以我一开始误以为我的也是kfx了。其实这是由于新版的Kindle for PC不管什么格式都会用.azw后缀,我的其实是古老的AZW3/KF8格式

因为早期KFX破解不成熟,所以网上流传着多种规避KFX、让Kindle(软件)fallback到老格式(azw3)的方法。随便列几种:

  1. 安装Kindle 1.17版(我是这里下的,请自行查毒)并不要再升级;
  2. 找到Kindle安装目录下的renderer-test.exe删除/修改名称。这个的原理是,Kindle依赖这个引擎来渲染KFX,如果删掉就只能回归老格式。
  3. 直接从Amazon网站下载选择USB导入到设备,这个会提供文件给你下。但是我没Kindle,这个选项是灰的。

因为我以为我的是KFX嘛,所以这前两种我都试了,没想到确实也有“效果”……但是,效果就是Kindle会只下载上面的azw文件而完全放弃下载.res文件,囧。

不过去年起kfx的相关第三方支持已经开始成熟了。上文提到的deDRM工具已经支持了KFX,calibre也有了KFX input/output插件(需要手动安装)。还有个收费软件epubor也号称支持KFX转其他格式。

最近遇到的几个视频相关的问题

没什么条理的一篇,主要记录下昨/前天遇到的几个小事,以后自己查询用。这种是不是记录到私人的OneNote里好点……

视频播放反交错处理

其实一直很好奇“反交错”处理到底在哪一步。因为据我所知,LAV、PotPlayer和MadVR都有处理反交错的能力。我用一个古老的自抓DVDISO:河合その子 – その子の夏(2004年发行)来进行测试,因为我发现近年的DVD大多都是progressive的了。

具体测试过程不赘述了,虽然费了蛮多功夫。总体而言,就是三者都能处理,但是有一个容易有误解的地方是LAV的设置里,有两个不同的设置:

QQ图片20180422185941

其中左上角那个,其实是决定了如何对视频流进行逐行/隔行标记,所以请务必选成“Auto”或者Agressive(后者是完全按照视频文件的metatag来,前者则是还有一定的检测成分)。如果选成disable,后面所有步骤(Lav自带的反交错、Pot转换滤镜、MadVR等)都会把视频流完全当成逐行来处理(OSD里也能看出),不会再尝试进行反交错。

至于右下角那个则是真正的反交错处理,可以看到我这里是设置成禁用的(软硬都)。所以LAV这里并不会进行真正的反交错处理,只是标记它是隔行视频。

那么接下来,在Pot(如果开启了转换滤镜)和MadVR里都可以反交错,这个没啥多说的。根据我个人的播放的workflow(开启转换滤镜,原因上文说了)的话,会被Pot处理,所以Mad那个就用不到了(虽然也没关就是,留着自动)。

在测试过程中,我还发现一个奇怪的现象,手头有几个TrySail的HDTV源的TS文件(均录制自索尼家的M-ON!),虽然标记也是隔行,但是用肉眼完全看不出任何一帧有交错条纹。又看了硬盘里有的其他一些M-ON!录制的,似乎这种现象还挺普遍(但是也有有的,比如20170119043000_「リスアニ!LIVE 2017」出演アーティスト特集▼LiSA、三森すずこ、南條愛乃 他_エムオン!HD).ts这个)。搞不懂是源就是这样,还是录制视频的人其实已经做了处理,却没有修改元数据。

试用StaxRip

StaxRip是S1看到有人推荐的一个视频压制工具集。其思路和megui差不多,而且附带的组件意外地全。其操作思路比较接近megui里的OneClickEncoder(如果用megui推荐一般就用这个,megui的主UI很反直觉),而且一些地方比如resize设定、DAR/SAR/PAR展示比megui的好用多了(megui的avs creator里的resize用起来也很别扭)。

[这里再吐槽一下,SAR一般是指Storage aspect ratio……也就是实际存储的像素数量的width/height比。但是在x264的argument里却是“Sample Aspect Ratio”——相当于别人的PAR(像素宽高比)!]

这工具的完成度很高,在一些细节上蛮用心(比如AVS编辑器、log等)。但是BUG也挺多的,UI上短暂试用了一下就发现不少bug(例如:如果选了一个没安装的组件无法取消安装对话框,无限循环;DAR的显示经常错误),更严重的是有个audio copy/mux时不会apply的delay的恶性bug(大概搜了下,15年doom9似乎都有人提过?)。

而且作者似乎是孤军奋战,更新频率感觉不是很乐观,不知道未来会如何。

Remux到MKV的音频Delay“问题”

如上所述,音频delay这玩意是在encode甚至是remux视频时经常会搞糟的一个头疼问题,之前在压制某演唱会的文章里也提过megui在拼接视频的时候也做得很差,倒是fffmpeg相当靠谱。今天又发现一个奇怪的:我手头这个TS文件的audio的metatag有

Delay relative to video : -368 ms

但是,如果直接用mkvmerge或者ffmpeg remux成MKV,就会变成

Delay relative to video : -377 ms

由于这俩差别不到100ms,我肉耳无法听出是否有区别,所以不清楚是真的有偏差、还是因为封装的时候有别的因素考虑,才变成这个数值的。姑且问了下mkv的作者,过几天看看有没有回复。

如果用ffmpeg直接remux成MP4,则并不是用metatag的方式实现的(metatag里并没有相关的),所以也无从得知结果如何。至少耳朵收货是没有明显的音画不同步的。

x264编码速度问题

在测试StaxRip的时候,发现其编码速度比megui快得多(几乎快1倍)。经过控制变量,发现主要影响的是:StaxRip默认用的是MPEG2DecPlus64.dll插件来做MPEG2Source,而megui那边则是DGDecode.dll。顺便一提,前者是x64的,需要用x64的Avisynth来加载;后者是x86所以也得用对应的x86版Avisynth,但是因为后面要调用x64的x264,所以得用avs4x26x辅助一下,类似这样:

"D:\Program Files\MeGUI\tools\x264\avs4x26x.exe" --x26x-binary "D:\Program Files\MeGUI\tools\x264\x264.exe" --preset medium --crf 17 --output "E:\aaaa\output2.264" "E:\aaaa\bbb.avs"

另外,我发现StaxRip带的旧版(2017年)x264的速度也比megui带的最新版快那么10%。

虽然不清楚为什么区区Source滤镜的不同会影响这么大,但是我发现当我使用正常的压制preset(medium或者slow,之前为了测试都用的ultrafast)时,两者的区别就小多了。这也可以理解:当压制的复杂度上升之后,自然主要的时间都花在这边了,avs那边多浪费一点时间的区别也就不明显。

顺便提一下反交错滤镜——因为AVS能用的至少十几二十几种,我也搞不清楚哪个算是业界主流,一般都用megui自动分析出来的囧。开了这个滤镜之后,对压制速度影响也是蛮大的。

碎碎念

视频压制界的工具、技术的混乱程度之高简直叹为观止。如果只是随便玩玩,倒是用好ffmpeg就基本能解决90%的问题;但是正是那剩下的10%要花费大量精力才能掌握。同样的Task,有4、5种工具是常事,而且还是经常是互有优缺,哪个都不能丢。与之相对的,却是开发者的缺乏:大多数工具多是个人开发(尤其是早期,可以说整个生态圈都是个位数个geek一手打造出来的),无论是更新还是维护都很难得到保证。这导致了两个截然相反的现象:一是“技术栈”(笑)得要经常更新,毕竟新来的高手们都是喜欢重新造轮子的;二是经常有那种作者早就不知所踪、却又无法丢掉历史遗留产物,mod了又mod还得咬着牙用。

另外,documentation的匮乏也是个很严重的问题,经常有许多问题(比如某些软件的奇怪quirk)要翻遍doom9才能在漫漫几千楼里找到答案。这也是我坚持写blog记录自己遇到的各种技术问题的原因,哪怕能给1、2个“后人”指个路也是好的。

外挂LAV+开启PotPlayer转换滤镜时的最佳设置方案

自从前一段发现PotPlayer播放10bit视频惨到不行的banding问题之后(目测是直接把10bit砍到8bit,没有使用正确的抖动,甚至连设置的地方都没有!),就换用了LAVfilters来作为主力滤镜。既然都换了LAV,顺便也把EVR换成了MVR——因为我发现我之前一直无法忍受MVR的一点,全屏和窗口化切换会卡一下的问题现在没有了(即使是非exclusive模式)——不过这是后话。

但是,PotPlayer调用外部滤镜的兼容性实在是惨不忍睹,其实这也是我之前为啥一直坚持使用内置滤镜的原因。短短用了这半个月,遇到过的问题就包括但不限于某些视频直接无法播放freeze、拖动进度条卡顿、PotPlayer.dll报错崩掉等等。无奈之下,我尝试了下升级到最新dev版,结果发现更可怕了,比如之前我发现banding的那个[LoliHouse] A.I.C.O.用LAV直接无法播放(稳定版没问题,已经报错到论坛了)。

PotPlayer的转换滤镜

我后来发现,在依然使用LAV的前提下,如果开启PotPlayer的所谓“转换”(transform)滤镜,则可以大幅度缓解不兼容的各种问题。上述的那个视频可以正常播放了没问题,崩溃的次数也大幅减少。另外,这个滤镜是PotPlayer用来实现PotPlayer内置的一些功能的,所以只有开启之后一些功能(比如视频调色,虽然我从来不用就是了)才能正常工作,而且不开启的情况下还会有截图错帧的问题。

当然,这个功能之所以之前我选择不开启,是因为它是有不少副作用的。其最大的问题就是在不同Pixel format之间转换会有很大的精度和算法问题。Pixel format就是形如NV12、YUY2、RGB24等等各类色彩的数据存储格式——包括但不限于colorspace、位深、通道数、通道混合方式等。对于YUV色彩空间的几种常见的格式VLC的wiki有篇详尽的文章可以参考,这里不再赘述。

要谈论transform的对pixel format转换的影响,得先说说如果不用它,直接LAV输出到渲染器是怎样的一个流程。例如最常见的YUV 4:2:0(YUV色彩空间,纵向横向均有2:1的色度抽样)的8 bit视频(注意:俗称的8 bit、10 bit指的是单通道。实际上,对于YUV 4:2:0,每个pixel平摊下来有一个Y通道像素+1/4个U通道像素和1/4个V通道像素,所以一共有8+2+2=12bit)在LAV勾选默认所有输出方式(除了AYUV)的情况下,会用NV12输出给渲染器。这里罗列一下常见的几种格式都会是怎样:

原始格式 LAV输出格式
YUV 4:2:0 8 bit NV12
YUV 4:4:4 8 bit YV24
YUV 4:2:0 10 bit P010

可以看到,LAV自动选用的位深和色度抽样都是和原来一样的,不会进行多余的操作。

顺便一提,如果细心看,会发现LAV会输出2048×1080,而不是1920,这是因为使用了叫做Image stride的技巧,把图像尺寸填充到2的整数幂来加快GPU运算。LAV作者的原帖见此

YUV 4:2:0 8 bit视频

现在来看看如果开启PotPlayer的转换滤镜,会发生什么。还是先看看最常见的YUV 4:2:0 8 bit格式:

QQ图片20180325012835

从OCD信息可以看出,LAV依然输出的是NV12(这里写“Input”,因为是相对Pot的转换滤镜而言),不过经过了转换滤镜之后就变成了YUY2这个4:2:2(水平有色度抽样,纵向没有)的格式——也就是说Pot自作多情地把U、V通道给upscale了一倍。很显然,我们是希望所有的upscaling工作全部在MadVR进行,因为其拥有最优秀的算法;Pot的算法?已经不能用“一般”来形容了——事实上可以看出,他根本就是用的nearest neighbor(截图均为200%缩放,下同):

yuy2
Pot转换滤镜,默认(YUY2)输出
disabled
转换滤镜禁用,LAV直出MVR

这个结果显然是无法接受的,那么怎么能拯救一下呢?PotPlayer相关的选项有这些:

QQ图片20180325013808

这里我们主要可以调整的是三个:一个是输出格式(Output color space),一个是所谓的“直接转换”(Direct conversion),一个是下面那个高质量(High quality YUY2/RGB24/32 conversion)选项。

首先想到的自然是勾选那个high quality选项了。勾选之后,PotPlayer会用比NN高级那么一点的算法,结果如下:

yuy2hq
Pot转换滤镜,默认(YUY2)输出+HQ

比上面那个锯齿到爆的自然是好多了,但是理想情况下我们还是希望能让MVR来处理,所以我们还可以选成强制NV12输出(注意,非YUY2输出的话那个HQ选项勾选与否没有任何区别):

nv12
Pot转换滤镜,NV12输出

这里可能几乎看不出区别,不过如果放再大点可以看出这个会比上面那个稍微锐化那么一点。另外很奇怪的是,即使是选成NV12输出,结果也和直接禁用转换滤镜(LAV用NV12直传MVR)不是逐像素相等,我初步怀疑是截图的帧数不同(虽然这是我拿静止图片做的视频,但是毕竟是有损压缩每一帧还是略有区别的)导致的,也有可能Pot的转换滤镜还干了其他什么,但是无论如何,这个区别是肉眼完全没有可能区分的了。

哦其实还有个直接转换的选项——有啥用呢?具体原理不明,不知道所谓的“直接”是指什么,但是选了之后YUY2(默认)会变成“Direct YUY2”,NV12会变成“Direct NV12”,其中前者结果和默认+HQ一样,后者和NV12一样,所以感觉意义不大。

你当然也可以选成那些4:4:4的格式来输出(而且不用勾选HQ选项,自动会使用比NN强的算法),来获得能接受的结果,但是这样完全是把MadVRupscaling的工作给做了,自然不是我们想要的。

值得一提的是RGB输出的选项……首先RGB24+HQ选项=直接崩溃,是很彻底那种,连用Pot内置滤镜解码都崩(啥时候抽空汇报一下)。RGB32+HQ倒是不会崩溃,但是这下不但U/V的upscaling、连YUV->RGB都在Pot做了,不是很让人放心。不过也算有个优点:PotPlayer至少可以手动改Color matrix,放到MadVR或者LAV里做的话全靠自动判断了,如果有什么文件的元数据不对,没办法纠正。

题外话,RGB32比起24是多了8位的Alpha通道这点没错,但是绝大部分情况,alpha通道是根本不会使用的。那为啥会用32?其实是因为可以在x86(32位机)下做到下完全对齐,这会显著影响到内存和运算单元的速度。参见[1][2]

关于Color matrix

嗯这里得插播一段。上图中出现的那个视频其实是我当初研究浏览器色偏问题时,自己拿一张RGB图片用ffmpeg做的。当时用的命令很简单就是:

ffmpeg -loop 1 -i colortest_hd.bmp -c:v libx264 -t 30 -pix_fmt yuv420p out.mp4

出来之后至少0,0,0、16,16,16、235,235,235、255,255,255等几个灰色很准所以我一直没注意过。知道今天才偶然发现,我在里面用的纯红色文字,也就是255,0,0的,显示出来居然是255,25,0!

究其原因,原来用ffmpeg将RGB的图转换成YUV视频时,默认是使用的Rec. 601的转换矩阵。但是,如果不手动指定,是不会把转换矩阵写入元数据的。而由于生成的视频是HD的,会默认为Rec. 709的矩阵,所以最后渲染回RGB的时候,就出现了色偏。

解决这个问题可以这么写:

ffmpeg -loop 1 -i colortest_hd.bmp -vf scale=out_color_matrix=bt709 -color_primaries 1 -color_trc 1 -colorspace 1 -t 30 -pix_fmt yuv420p out2.mp4

其中-vf scale=out_color_matrix=bt709部分是把图片转换成BT.709(Rec. 709的另外一个名称),后面的-color_primaries 1 -color_trc 1 -colorspace 1的是在元数据里标注。当然,如上所述,如果是HD视频可以略去不写。

也可以选择保留BT.601,但是就要显式声明了:

-color_primaries smpte170m -color_trc smpte170m -colorspace smpte170m

(NTSC和PAL还略有不同,参见此文。另外不推荐这种做法。有的滤镜/渲染器根本无视元数据。HD视频还是老老实实用BT.709就好。)

除了-vf scale,似乎还可以用-vf colormatrix=bt601:bt709,不知道有没有本质区别。几个讨论可以参见这帖这帖

在测试过程中我发现PotPlayer一个BUG:

LAV输入NV12+转换滤镜+RGB输出(RGB24/32+MVR或RGB32+EVR)+Auto color matrix的情况下,永远使用Rec. 601。不但不会自动识别HD视频,连有显式Ret. 709的tag都不行。所以Pot转换滤镜RGB输出这条心还是死了吧。

YUV 4:2:0 10 bit视频

一般的8 bit视频还是比较容易找到一个靠谱的方案,我们再来看看10 bit。和8 bit相比,主要的问题在于,Pot这个transform滤镜能接受的输入很少[主要包括:NV12/YV12、YUY2/UYVY、RGB32,基本和EVR能接受的输入差不多。不支持任何10 bit及其以上或者4:4:4的YUV的格式]。前面提到LAV一般是直出P010给MadVR,而transform滤镜恰恰不接受这个输入。所以,默认情况下,LAV会选择抖动降低8bit然后NV12输出给转换滤镜。

这之后的流程自然和上面就一样了,Pot这边也选择NV12输出的话,无非就是把10->8转换的步骤从MAR变到了LAV,两者的dither质量都OK(虽然MVR的选项更多)。

YUV 4:4:4视频

其实这个没什么测试的意义,因为你99%根本不会见到这类视频,纯粹是为了蛋疼。而且这个的毛病可就太多了:首先,PotPlayer也不接受YV24输入,所以LAV会直接转换好RGB32送过来。接下来怎么办?显然不能再用NV12或者默认的YUY2了,我们本来明明没有任何色度抽样的,不能自降质量。最简单的就是这边也设成RGB32输出——由于无色度抽样完全不牵扯到resizing,所以这样的结果和LAV YV24直出MVR完全没有区别,锐度满分。不过兼容性还是有点,经常视频如果不重头开始播放就会出现这种屌炸天的现象:

QQ图片20180325034639.png

如果你手贱一定要用NV12输出,也就是让转换滤镜从RGB32转换成NV12,那么除了显而易见的视频会变模糊以外(你自己引入了色度抽样),PotPlayer还会莫名地引入color range压缩的问题(最后出来的视频是16-235的)。而且我LAV那边无论是设成输出full还是limited的RGB都不行,PotPlayer一定会搞糟。结合MVR的OSD,我们来猜测下发生了什么:

如果LAV输出full的RGB:

Pot将full的RGB转换成limited的YUV,但是不修改stream的信息,所以MVR会认为还是full,不伸张,导致最后输出limited RGB;

如果LAV输出limited的RGB:

Pot根本不知道还有Limited的RGB一说,当成full来用又再压缩一次变成double limited的YUV;stream信息依然不修改(limited),所以MVR那边会伸张一次,但是结果依然是limited的。

你倒是可以在Pot这边手动修改YCbCr的color range为full来修复,但是这样你如果用Pot做YUV→RGB转换又要遭重… 嗯,前面提到过的Pot只用Rec. 601的color matrix问题在反向的RGB→YUV也存在。总之,就是Pot对上流的metadata的识别能力非常弱智,或者说根本不读取的。

不过,就在我无计可施的时候,我发现之前提到过的Direct conversion选项能用上!如果选成“Enable: change default output color space”,即使上的么color space选的是NV12(或者Auto),那么当输入时RGB32的时候也会自动触发“Direct RGB32”,完美规避了各种色彩空间转换的BUG!试了下4:4:2的视频,结果也是一样喜人。

结论

一言以蔽之,要避免让Pot的transform滤镜干任何事(……),我们用他的唯一目的就是防止PotPlayer崩溃。由于它夹在LAV和MVR中间,所以最简单的办法就是把10bit->8bit交给LAV,把色彩空间转换和resizing交给MVR。因此,对于99%的4:2:0视频,把PotPlayer的输出选成NV12即可——反正转换滤镜不支持10 bit输入,LAV那边也会先dither到NV12的。之所以要手动设一下而不用默认的Auto,是因为Pot默认会自作主张upscale到YUY2。对于高于4:2:0的视频,通过把Direct conversion设为Enable: change default output color space,会自动复制输入的格式(YUY2或者RGB32),依然完美规避转换问题。

Lav那边不需要做任何调整,默认输出全勾的状态就OK。

补记

呃我都忘了补记一下了,我后来发现如果开启了Direct conversion,部分视频(还不少…)会直接崩掉Pot。所以这个选项暂时改回去了,反正非4:2:0的视频实践中基本没有。

百万现场《LTP》系列歌曲的音频质量问题的研究

上文中我有提到,一直觉得初代ML CD系列《THE IDOLM@STER LIVE THE@TER PERFORMANCE》(下称LTP)的某些歌曲听上去很怪,其中比较明显的是03的『素敵なキセキ』、『ハッピー☆ラッキー☆ジェットマシーン』『Happy Darling』三首Solo,其他也有,比如『オリジナル声になって』等。具体什么问题说不清,可以粗略概括成中频(人声)解析不行,外加整体发扁(动态范围低)。这还是在我没有任何玄学设备、纯粹用几十块钱的破音响听出来的。

虽然也有可能是有意为之(即:我们就是想要这样的听感),但是考虑到ML系列是首次把音乐制作交给lantis(而不是哥伦比亚),我还是怀疑是技术上搞砸了。

来自Hi-res的救赎?

昨天写上文的时候实在忍不住,去mora买了一首hi-res的『Happy Darling』来对比。之前有买过一次mora,记得是不用挂日本代理、但是必须浏览器语言设成ja;不过这次清了下cookie才好使。

对于hi-res,我一直是不怎么感冒的:我并不相信人耳可以听出44.1kHZ或者16bit位深以上的区别。所以如果在音源完全一致的前提下,如果仅仅是把更高精度的数字档放出来,我不觉得比起CD级音质有多大优势(体积还大了N倍)。更不要提谁也无法保证最初的制作精度几何,所谓的hi-res是不是干脆是interpolate上去的?这种事儿在影像、平面印刷等出版物可屡见不鲜。

不过,hi-res有一个优势,和“hi-res”本身没什么关系,就是它相当于是一次重新的发行。也就是说,它可能会使用不同的、或者修复过的音源(尤其是对于这种非同步发行的就更有可能)。这种事情在单纯的CD复刻里都有(之前的[两篇][文章]全在讲这个),更不要提以质量为卖点的hi-res release了。所以,我报的希望就是Lantis发现了当初制作的问题,借着hi-res的春风进行修复。

下载完毕不听不知道,听了发现真的有非常显著的区别!一上来的伴奏(贝斯?吉他?请原谅我贫乏的音乐常识…),两者的声场位置就完全不同,hi-res版更立体;但是hi-res里的钹的声音相对就小了很多。进入人声部分,hi-res版的解析/清晰度也上去了。虽然以我的口味不算完美,但是绝对远强于CD版。

那么上面是听感,果然还是得上一下大杀器Welch’s method的频谱分析(具体请参见各种前文)。

hd

呃,我只能说,差别这么大的同一首歌两个版本,我研究了这么久,分析过那么多音频,还真的是第一次见。而且,CD版这个曲线非常不科学,从来没有见过有歌在5k-10k Hz区间有个坑比高频段强度低这么多的(一般都是大趋势准·单调减)。

这里说明下,从legend可以看到,我测试的时候都是先把hi-res版本转成了44100Hz、16bit的CD音质。Resampling我用的是FB2k自带的PPHS resampler,变16bit没有开dither。我需要声明无论是不同的resampler还是开不开dither,我全都是和原始hi-res文件对比过的,和想象的一样,没有任何听感上和频谱上的区别。哦唯一点是如果用高sample rate的音频,Matlab里跑Welch’s method函数出来的结果分辨率会减半(因为range翻倍成96kHz了但是总点数不变),所以这个必须得resample结果才好看。

全面对比Hi-res和CD版的《LTP》

既然这歌区别能这么大了,接下来自然是要杀全家全测试一遍咯。当然让我买13张hi-res我表示财力不足,于是去tsdm全撸了下来(暂时缺少07)。

当然这一共几十首一次次手动改目录跑我的MATLAB脚本会死人的(虽然之前我一直是这么过来的),于是吭哧了半天增强了下脚本的自动化。这里吐槽下,MATLAB文件操作、字符串操作真的是累,不过现在有struct(类似于object)和cell比起当年纯matrix操作还是方便多了。

上文我是对一定频段的dB数取平均值比较,现在发现不是很合适,比如上面『Happy Darling』这个先低后高的就抵消了。只有两个互相对比的话,可以有更好的办法。我还是用了部分频段(0-14.4kHz)的dB,误差计算经过几次测试后决定用MSE(还是那句话,不要问我对dB进行MSE是否科学w)。

具体操作起来,就是先用foobar批量对所有hi-res进行resample+降位深,然后存到X目录的\%title%\hi-res.wav。再把CD版直接转换(相当于截取,因为没有额外修改)成\%title%\cdrip.wav。这样,同一首歌就会在同一个子目录下。然后用循环处理、做Welch’s method、计算MSE、绘图就行了。

我设定了一个阈值,只有MSE大于这个阈值的才会Plot和输出结果,其他的忽略。另外,因为Welch’s method计算非常费时,所有的结果无论如何都会存在各个子目录中(data.met),以后可以直接提取绘图或者数据分析。

经过多次测试,阈值在5比较合适,在这个条件下有8首歌会中枪——也就是说这8首频谱差别很大(嗯,『Happy Darling』鹤立鸡群……比第二名高一倍还多)。

Title MSE
Bigバルーン◎ 9.8826
Happy Darling 23.6898
ココロがかえる場所 8.8515
ハッピー☆ラッキー☆ジェットマシーン 6.2445
ビギナーズ☆ストライク 6.0709
微笑んだから、気づいたんだ。 10.154
恋心マスカレード 7.9994
朝焼けのクレッシェンド 10.1786

曲线图如下:

可以看到,大部分的区别其实都是高频段会莫名高一些,听感上区别不大就是,包括那个也有奇怪下凹的『恋心マスカレード』。

之前提到的03的另外两首Solo,『ハッピー☆ラッキー☆ジェットマシーン』虽然确实误差勉强上了5,但是听感基本没什么提升。另外『素敵なキセキ』、『オリジナル声になって』更是几乎没什么变化。所以指望hi-res拯救这几首的愿望落空了。而且为什么只有『Happy Darling』会有这么dramatic的区别,外人估计也无从得知了。

Hi-res版max’d out带来的爆音问题

另外值得一提的是,hi-res带来的也并不是只有优点。LTP CD版有很多轨的peak都是只有0.9x的,在hi-res里,所有的音量全部拉满了:

QQ图片20180321023838

拉满本身不应该造成任何问题,实际上,大部分歌曲的平均音量其实是变小了的,这样还能拉满,那说明动态范围有提升,是好事情,例如这是『Happy Darling』(上CD,下hi-res):

hd01hd02

不过有些则是反其道而行之(上CD,下hi-res):

dear01dear02

还是那句话,之前没拉满的话单纯拉peak到0dB这步更不会有动态范围的损失;而且一般而言,只要Limiter做得对,稍微砍掉一些动态范围也没啥。

但是在试听中,我遗憾地发现有些歌曲有明显的爆音,最典型的是『Dear…』(上图)的2:21.5处等。

后记

最后随便提两个东西。第一个我其实之前也说过一次,就是我惊奇地发现用我的破音响来进行主观听感对比,明显程度远高于我手头的几个耳机/耳塞。感觉音响哪怕是这种地摊货,中/高音解析就是强很多(虽然低音基本不存在w),而且声场定位也很厉害。注意这里说的是辨析不同版本,要说单纯听音乐哪个听感好,耳机还是有独到之处的。

另外一个是在对比hi-res之前,有几张CD我是同时收过某ftp下的整轨版和来源不明的某分轨版FLAC,两者居然不是bitwise identical的(而且用golden wave看波形,区别还蛮大)。不知道是哪边搞糟了(虽然听感和频谱完全一致啦…)。