《再战视频渲染器:nVidia D3D11的BUG和应对方案》的小更新

短文。快速描述一下前文成文之后的一些变动。

直接concat HLS切片产生的TS用ffmpeg重封装后的视频,使用内置解码器播放拖进度条会卡顿

这个是最离奇的问题,而且我觉得99%的人都不会遇到,但是还是描述一下。这个问题和 PotPlayer 更新无关,因为用23年的旧版本也会复现。但是我只是在最近才注意到这个问题,因此我只能怀疑是显卡驱动什么的触发了这个bug了。

首先Pot复现需要的设置:只要用Pot全默认就好,或者更具体说只要使用内置的AVC解码器就会出现。如果用硬解,则更为明显。

出现问题的片源:这个则比较复杂。简单来说,就是对于HLS下载的ts切片,通过 binary concatenation 的方式合并(也是我最常用的方式),然后再用 ffmpeg 转一遍MP4或者MKV之后的文件。我经常这样处理我下载的 livestream,因为直接合并出来的TS文件本身播放时经常有奇怪的bug,转一遍mp4解千愁,连拖动进度条都会顺畅许多。其实mkv更好,但是mkv由于有时间戳精度的问题毫无意义的完美主义比较抗拒。其中许多视频由于HLS切片的方式,本身就有各种时间戳(TS)的问题,转换时ffmpeg会抱怨诸如:

[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=3060, dts=9000, size=148
[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=9000, dts=11970, size=113
[vost#0:0/copy @ 000002a34f474ac0] Invalid DTS: 9000 PTS: 3060, replacing by guess
[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=15030, dts=20970, size=116
[vost#0:0/copy @ 000002a34f474ac0] Invalid DTS: 11970 PTS: 9000, replacing by guess
[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=20970, dts=23940, size=106
[vost#0:0/copy @ 000002a34f474ac0] Invalid DTS: 20970 PTS: 15030, replacing by guess
[vost#0:0/copy @ 000002a34f474ac0] Invalid DTS: 23940 PTS: 20970, replacing by guess
[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=27000, dts=32940, size=114
[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=33030, dts=36000, size=122
[vost#0:0/copy @ 000002a34f474ac0] Invalid DTS: 32940 PTS: 27000, replacing by guess
[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=39060, dts=45000, size=115
[vost#0:0/copy @ 000002a34f474ac0] Invalid DTS: 36000 PTS: 33030, replacing by guess
[mpegts @ 000002a34ea91500] Invalid timestamps stream=1, pts=45000, dts=47970, size=113
[vost#0:0/copy @ 000002a34f474ac0] Invalid DTS: 45000 PTS: 39060, replacing by guess

云云。转换出来的文件自然也会有dts/pts不太连续的问题:

Image

可以看到,这个文件不但PTS不连续,甚至会有重复的 packets;比如0.066秒就有两个。片源(eplus streaming+)估计切片的方式有点不标准,切割点前后估计有重复的数据包。事实上,如果用 mkvmerge transmux 一次,体积可以缩小27%!

但是正常来说,即使是这样的文件,也不是不影响正常播放的。

但是这次的问题恰恰就出在这样的文件:如果用Pot播放并快速地在进度条上seek,会发现每次seek完(关键帧seek)的前100毫秒左右播放时会出现卡顿、慢动作、快动作等反常现象。

另外注意制作测试视频时,只要使用 ffmpeg -c copy,不管是输出mp4还是mkv都会有问题。但是原始的.ts反而不会,或者ffmpeg输出也是.ts也不会。用 mkvmerge 输出 mkv 也不会。

如果改解码器为LAV,或者使用内置,但是修改为这个“System MFT Decoder”:

Image

此BUG都会消失。而且这个bug只有在片源比较长(比如2hr+)的时候才会很明显,从中间切十几分钟几乎感知不出来,所以也很难做一个最小重现的示例片源。

但是这个“System MFT Decoder”又会有一个其他的bug,就是之前 Pot 其实一直会有的,播放TS封装的H.264/Main时,会导致视频比例显示不对(1920x1080p的视频显示为1920×1084)。这个BUG在用默认的Built-in FFMPEG Decoder的时候已经修复,但是看上去没有修复几乎没有人用的System MFT Decoder的情况。

为了规避这个bug,我现在又全盘换成了LAV解码器了(参见上文LAV方案的2)。

但是用LAV解码器通到Pot,并且使用D3D11渲染器时,又有个另外的BUG:就是对于没有色彩信息bitstream tag的视频(也就是用mediainfo查看信息,看不到诸如“Color range : Limited”这样的信息的),在240305版本后,会默认被视为PC range(然而实际上99%的情况都是Limited range的),导致显示变灰。关于这个问题,我几个月前已经发邮件给作者了,但是他坚称这不是bug,而且“don’t comment any further on this matter, and if you think current is problem, just use another program”。我也是很无语,那如果要用LAV的时候,请改回使用EVR渲染器(或者默认的auto)吧。

Pot最新版使用D3D11解码+D3D11渲染10bit视频时又没有dithering了

之前说过 PotPlayer 使用 D3D11 硬解码 + D3D11 渲染器时,虽然依然有发绿的 bug,但是至少 10to8 是有 dither 的。

然而我在 231220 到 240509 这两个版本之间,PotPlayer 不知道修改了什么,导致这个 dither 没有了,于是瞬间有了巨明显的 banding 问题:

ImageImage

请看这个对比。左边是 231220 版本,右边是最新的 240827。图片经过对比度增强。可以看到人嘴附近,从之前的几乎看不到 banding 变成了非常明显的 banding。

对比两者的 OSD,可以看到区别在于之前的 BackBuffer 这一层是工作在BGRA,也就是说已经进行了有 dither 的10to8才到 BackBuffer;现在则是 RGB10A2。也就是说 10to8 的步骤发生在了这后面的BackBuffer 到 Display 之间;而这一步是没有 dither 的(也符合上一文的分析)。其具体原理我就说不清楚了,因为我根本不知道 BackBuffer 是个什么东西。

我不知道为什么会有这样的改动。介于开发作者回邮件的态度我也不是很想给他再写信了,反正我个人也不用这个组合。

顺便贴一下从我测试的最早的 bad 版本 240509 到最后一个 good 版本之间的 changelog:

[240509]
----------------------------------------------------------
- Fixed an issue where the screen did not appear when playing some MP4 files
- Improved built-in D3D9 renderer stability
- Fixed an issue where files in compressed files could not be played properly
- Fixed an issue where the screen was broken after navigation when playing certain MPEG 2 with DXVA

----------------------------------------------------------
[240305]
----------------------------------------------------------
+ Added NVIDIA RTX Video HDR function
+ Added ability to move files to playlist

- Fixed an issue where damaged WAV files could not be played
- Fixed an issue where the screen was broken when playing certain MPEG4 codecs
- Fixed an issue where the screen did not appear when playing certain WMV videos
- Fixed an issue where certain SRT protocols did not work
- Fixed an issue where an error occurred when playing certain TS files
- Fixed an issue where an error occurred in certain situations when playing some VP8/9 codecs.

nVidia 修复了缩放糊的BUG

上文提过最离大谱的是 nV D3D11 video processer 缩放的 bug,更具体地说就是如果缩小到小于原始大小50%(长度比?)时会出现整个画面完全糊掉重影的现象。

果然这么过分的 bug 还是相对比较快地修复了。在 nV 驱动 560.70 的 changelog 中,有这么一条:

  • [OBS] Scaling 10-bit HVEC or AV1 content down below 50% in viewport shows corruption for some configurations [4496901]

说的就是这个bug啦。

再战视频渲染器:nVidia D3D11的BUG和应对方案

没想到又要再搞这个话题(叹气)。

在上一篇(PotPlayer无MadVR设置方案),因为我当时使用一台没有独立显卡的电脑,完全跑不动 MadVR,所以我研究了下 MadVR 之外的渲染器的方案,很欣喜地发现 D3D11 的效果其实很不错,故用之。

最近,添了一张 nV 4系的显卡,理论上很简单,只要再回到上上文用 MadVR 的方案不就行了呗?呃,其实用习惯了D3D11,发现MadVR有些小问题还能挺烦的:

  1. 估计是因为MadVR“太重”的缘故,在用它的时候,拖拽视频进度条有时候还是不够流畅。尤其是反向拖动的时候。实话说并不是很严重,一般来说你拖动前几次都非常流畅,但是如果你狂拖进度条几十次,前后来回(一般是找某个场景的时候),就会出现卡顿现象。
  2. 在开启反交错(双倍帧率)的时候,无论是LAV中开启还是Pot开启还是MadVR开启,在暂停的时候都会跳帧(画面往回跳一帧)。这个真的是个非常非常小的问题,但是强迫症很难忍受。

另外,每次放个高清视频动辄50%的GPU占用率感觉还是挺没必要的,不够环保。

那有人会问了,好吧,那你直接换回你上文说的D3D11渲染器的方案不就行了?没错,我就是这么干的。结果一干就出事了:nVidia GPU下的的D3D11,和iGPU的行为完全不一样,甚至有很多BUG!下面详述。

在开始之前,我先提一下另外一个渲染器,MPC Video Renderer(下称MPC-VR)。这个渲染器根据我的理解并不是MPC的一部分,但是是针对给MPC-BE使用为第一目标而开发的(反正他们的开发者都是那一堆人就是啦)。我第一次知道这个东西是之前搜索如何在视频播放器中调用nV的超分辨率功能时看到的。但是除了这个功能(和本文无关,后面附录谈一下)之外,这也是一个蛮优秀的渲染器,安装之后PotPlayer里也能调用(但是有坑,后谈)。

这个渲染器其实是一个很轻量的渲染器,其主要目的是方便你调用显卡自带的渲染器,再加上了一些很少的HDR相关和部分放缩算法调整,总体上而言和Pot用EVR-CP时,自带的一些设置选项差不多:

Image

但是对于本文的目的就非常合适:非常便于我们测试各种DXVA2/D3D11相关的参数。

另外我们可以同时在MPC-BE和Pot中使用,这样可以控制变量,防止被一些PotPlayer自身引入的、而不是nVidia驱动的BUG干扰。而且其有极其详尽的OSD信息。

nVidia的D3D11视频处理器对于P010格式的BUG

要触发BUG,首先视频格式是 P010(一个10-bit的YUV格式,几乎所有的10-bit和HEVC和H.264解码后都是这个格式)。根据MPC-VR判断,这个错误其实发生在“D3D11 video processor”这一层。使用上图所示的默认设置就可以触发。如果用PotPlayer,最简单使用D3D11硬解+D3D11渲染器即可触发(不过还有一些其它条件)。

BUG1:整体颜色发绿

ImageImage
左为使用MPC-BE的默认渲染器(EVR-CP),右为Mad-VR

图片经过对比度、亮度加强。可以看到,右侧的使用MPC-VR明显有绿色的色调。

如果在MPC-VR的设置中进行以下任意修改:

  1. 去掉 Use Direct3D 11,也就是用 DXVA2(D3D9);
  2. 或在 DXVA2 and D3D11 video processor 中去掉P010/P016

这个BUG立刻就不见了。所以我的推测,这个BUG出现在 P010 转换到 R10G10B10A2_UNORM 这个YUV转RGB的过程中。因为如果用 D3D9,是转换成 A2R10G10B10 这个格式:

Image

再放一张PotPlayer的绿图。作为对比的左边是使用 Intel iGPU 同样设置的结果。可以看到,颜色没有任何问题(但是有很严重的banding,这个下面单独说)。

ImageImage
左为使用Intel (正常),右为使用nVidia (发绿),其他设置完全一致

其实用Pot的时候(MPC-BE+MPC-VR不会),还有其他一种情况也会触发发绿BUG,就是使用D3D9解码+D3D9渲染器。但是使用D3D9解码+D3D11就不会:

ImageImage
左为D3D9+D3D11 (正常),右为D3D9+D3D9 (发绿)

虽然不是很确定,但通过观察 Renderer OSD里列出来的格式,我们可以揣测一下发生了什么。可以看到左边是从P010(被Pot自己?)先转成了RGB10A2才进的 Video Processor,所以规避了BUG;而右边则是很奇妙地直接P010一把梭转成了XRGB(一种4:4:4的RGB格式),可能这个过程中也触发了类似原理的变绿的BUG。

OK,所以为什么会这样?其实我很多年前就发现 nVidia 和视频相关的技术栈会有发绿的问题,当时是发现用 ShadowPlay 录制视频,有时候会发绿。虽然没有任何证据,但是我强烈怀疑这个bug和我之前在ffmpeg静态图转视频这篇blog里提过的、ffmpeg的swscale组件的一个有十几年的bgr->yuv颜色和rgb->yuv颜色不一致的BUG有关(虽然我们这里的 bug 是反向转换)。

更两人恼火的是我不知道应该去哪里汇报这个BUG。这种应该是得自己写一个不牵扯到视频渲染等一系列客户端软件layer、而是直接调用 Windows的 D3D11 API 的最小实现,再去nVidia Developers 相关论坛或者 bug tracker 汇报才会比较被重视,但是我实在没这个水平,更完全不懂C++,不知道从何下手。而且我想各种第三方渲染器的开发者应该早就知晓此问题了,但是也没有搜到比较任何相关的 documentation。比如我在MPC-VR的issues中发现了至少三个相关的问题:

https://github.com/Aleksoid1978/VideoRenderer/issues/48

这个完完全全就是这个BUG!开发者提到:

To convert from NV12 and P010 to RGB you use D3D11 VP. This conversion is controlled by the driver manufacturer and MicroSoft.
But you can disable NV12 and P010 options and convert with our shader.

v0lt

因此,提问者在关闭了 D3D11 的 Video Processor 选项(上述)之后就规避掉了bug,TA也就没有再深究。

https://github.com/Aleksoid1978/VideoRenderer/issues/98

这个虽然是HDR视频,但是我怀疑也是同样的问题,因为也是P010格式的。

https://github.com/Aleksoid1978/VideoRenderer/issues/22

这个其实是最有趣的:提报者(后来才知道,原来是某群群友)使用的其实并不是原生的 D3D11 VP,而是 MPC-VR 自带的 Shader 来做 Video process,但是居然出现了同样的bug!MPC-VR后面修复了这个BUG,理论上可以根据改动一窥端倪;但是我完全搞不懂是怎么修复的:因为并没有链接到对应的commit,根据评论中提供的2个分别反馈为bad和good的测试版本的commit hash,应该是这个diff——但是感觉完全没有相关的啊?!线索断了。

BUG2:Downscale时整个画面边糊出现重影

如果说上面那个BUG可能不是太明显,有的人估计看不出来的话,那么下面这个就非常离谱了。当使用 nVidia 的 D3D11 Video Processor(VP)进行 resize 时,如果是缩小,则整个画面会变得非常模糊且出现重影,这点在比较锐利的线条尤其是硬字幕的时候非常明显:

Image
Image

我相信不瞎的应该都能看出来吧!要规避这个BUG,除了上面的说的完全禁用D3D11 VP的办法之外,也可以在MPC-VR中单独关闭“Use for reszing“,或者在Pot里把 resizer 改成其他任意的。再次强调,这个BUG依然是只有P010格式的视频会触发。

实话说,很难相信这么明显的bug会一直没人修复!有点怀疑是不是最近的驱动才引入这个bug的。我又去MPC-VR的repo瞅了下,确实有两个汇报(第一个第二个),都是比较近期的。

再测 nVidia 语境下的 D3D11 渲染器的质量

OK,BUG说完,让我们来回到这一切折腾的起因——渲染器的质量。先回顾一下:

  1. MadVR质量最好/最可控,但是太重,在Pot调用时连带还有一些UX上的小毛病;
  2. 之前惊喜发现 D3D11 video renderer (Intel) 的效果其实非常好,尤其是缩放锐度和 halo 都很不赖,故用之。不过,10bit视频是直接截取,所以有非常明显的 banding 的问题,所以我们采用一些措施来尽量软解,靠前面的解码器部分来给我们dither到8bit再渲染(如果硬解会 P010 直通到 renderer)。主要的难点是Pot很弱智的内置解码器HEVC强制硬解,需要调用LAV来克服。

所以我们现在需要重新调研一下 nVidia 的D3D11(以及D3D9)在缩放和10 to 8这两个重点上的表现,毕竟已经知道了和 Intel 完全不同。当然还有 HDR tone-mapping 的问题。

不过我们先试试MPC-VR这款不错的渲染器在Pot上表现如何。如果不错,我们完全可以改用这个。很可惜,虽然没有上面提到的MadVR那些UX上的小bug,但是有个更离谱的:在调整播放窗口大小(包括切到全屏)时,会非常的卡,外加闪烁。同样,这只是个一个非常小的问题,但是我表示不能接受,故放弃。

缩放

OK,那么我们就来比较最常见的4:2:0 8-bit的1080p视频缩放到1440p的表现吧:

Image

呃,这一比就比较尴尬了——nVidia的渲染效果比Intel差了不是一点半点。锐度不如而且 ringing 更大。

D3D9(DXVA2)和基于D3D9的EVR则更差,整体又多糊了一档;而且还有很奇怪的图像整体向左偏移约1像素的问题(假设MadVR为 ground truth),不过这个倒是不影响观看。加强对比度后对比:

Image

当然,我们可以在 Pot 选用其他的基于 shader 的 resizer,但是那些效果也都挺差的,毕竟都是一些比较基础的算法。

10 to 8

上文提过, Intel 的渲染器上文有提到过完全没有 dithering,所以如果在那里进行10转8,会出现非常严重的 banding。这点 nVidia 这边终于有改善了!如果用 D3D11 renderer,会有 ordered dithering,而且还是渲染像素级的(非原始分辨率级),效果很好:

Image

但是!别忘了我们上面提到的发绿的BUG!(其实这图里都能看出来绿了。)所以说,这个我们其实还是享受不到,还是得老老实实把 P010的解码设置为软解,让解码器输出NV12(也就是已经降过位深),然后再给 D3D11 VP/VR。

那么在nV下,其他几款渲染器效果如何呢?直接上结论,结合上面的BUG一起说:

  • D3D9解码+D3D9渲染:发绿,downscale重影,banding
  • D3D11解码+D3D11渲染:发绿,downscale重影
  • D3D9解码+EVR-VP渲染:完全OK!

怪了,说好的 EVR-CP 是基于 D3D9 的呢,怎么现在居然有 dithering 了?虽然不是工作在渲染分辨率(而是视频分辨率),但是效果完全OK啊!

Image

从 OSD 可以看到其格式流程是 P010 先到 A2RGB10 进 Mixer,然后在 RGB 空间 dither 到 XRGB 进行后面的步骤。

也就是说,如果不是缩放质量太差,我们甚至可以换回 EVR-VP 了。

另外还有一点,上文提到修改内置解码器设置中,把 HEVC 的解码器改成 ffmpeg.dll 来强制软解,很可惜现在已经没有这个选项了!所以说现在没有任何办法可以关闭 Pot 对 HEVC 的硬解(也就是会导致10-bit输出 P010 导致 BUG),所以 HEVC 必须得调用外部的 LAV。

所以,最后下来,我的配置其实和之前差不多:

Pot 内置解码器设置中不开启硬解(但是先勾选一下然后勾选下面的D3D11后再取消以防万一:

Image

对于HEVC,手动设置LAV为编码器,来规避P010直通D3D11 renderer导致的BUG:

Image

使用内置解码器的时候(所有非HEVC的格式),其实都等价于会自动使用转换滤镜。对于调用LAV的情况(HEVC),开不开出来的结果对于D3D11渲染器其实都没差,我就开了。

Image

不过要注意,如果 LAV 勾选了 P010、且开启转换滤镜的时候,LAV播放10-bit 会出P010给D3D11,导致触发 BUG。而且不管你在 Pot 的 Colorspaces 那里怎么设置都不行。如果真的不想开转换滤镜,那一定要进 LAV 把 P010 输出取消勾选。这点我们下面详细总结里会再赘述一遍。

BT.2020/HDR

设置完后,我们再去验证一下几个非标情况的播放结果。首先是 HDR——其实这个东西我也不是很熟,纯粹靠自己瞎看了。说错了请指教。

因为我的屏幕是SDR,所以需要tone mapping到 SDR。如果用MPC-BE先做个简单测试,会发现播放的时候其实MPC-VR端收到的 Transfer Function 变成了BT.709了(但是 Matrix 和 Primaries 还是 BT.2020):

Image
MPC-VR OSD

EVP-CP的话则是显示了两个BT.709,搞不清楚哪个是哪个。

Image
EVR-CP OSD

这个转换是完全不可控的,似乎也没有任何选项,无论硬解软解都会转换。当然我也不是想折腾,毕竟颜色是对的就行了。

而如果你用 MadVR,则是显示了两个BT.2020:

Image

而且颜色是错的,你需要单独设置MadVR显示器校准那边才能把颜色给整对。而且MadVR那边的设置非常迷惑,我之前提过一次

(题外话,在MPC-VR的repo里有搜到有人说 VR 的 OSD 显示的 Primaries 和 Matrix 是和 MediaInfo 正好反了但是开发者不置可否,介于这三个东西经常有各种奇怪的别名,我不好说也不深究了。)

同理,用 Pot 调用各种渲染器也有这个类似的操作,但是有的时候没有 MPC-BE 那么灵光。比如,如果用LAV 输出 NV12(输出 P010 同理)然后喂给 MPC-VR:

Image

可以看到和 MPC-BE 不同,这里 MPC-VR 是收到了 BT.2020 transfer function。然后出来的颜色也不对。虽然 MPC-VR 里有转换 SDR 的选项:

Image

但是我折腾了一万年也没整明白怎么能触发他(触发了的话 OSD 中应该会有一行后处理:转换到 SDR 云云)。不过,如果我把 HEVC 的解码器改回内置(并被 Pot 强制硬解),则一切就又正常了,和 MPC-BE一致:

Image

搞不懂啊搞不懂。还好,用 D3D11 renderer 的话没这毛病,无论什么解码器,都可以正常转 SDR。

另外有个细节,如果 resizer 选的是 auto,这里这个测试用的 4K BT.2020 视频无论解码器用的啥(Pot 自带硬解,LAV 各种格式输出,etc.),resizer都会变成 Texture Bilinear 而不是一般常见的 D3D11 Video Processor,也就是类似 EVR-CP 的画质。当然你可以手动选回去(我有想是不是因为视频是4K的缘故,但是另外找了一个 4K BT.709 的视频,没触发)。

Image

Full range, 4:2:2, 4:4:4 等各种情况总结

还是直接先上表吧!

Image

这次和上次的比稍微复杂了点,多加了几列,有两列还调换了下顺序,如果要对比请注意。标注思路还是一样:绿色 good,黄色可忍,红色不能忍。EVR Vista 啥的那个就不测试了,反正没人会用到。

我上次的表格没有区分是否勾选Pot的视频“转换滤镜”,后来发现这个对于LAV的还是有些区别的,故加上。

第四列那个再罗嗦一次,就是这个选项,名字太长了:

Image

中文是叫:

Image

下称“直接转换输出色彩空间”。其大概意思就是,如果条件允许绕过Pot自带的转换滤镜,直接从解码器通到渲染器。因此,3、4列也不是所有组合都会有区别,简单来说:

  • 使用内置解码器时,相当于始终启用了“转换滤镜”。实际上是否能跳过,取决于“直接转换输出色彩空间”是否启用。
  • 使用 LAV 等外部解码器时,只有开启转换滤镜时,开启“直接转换输出色彩空间”才有意义。因为如果不开启转换滤镜,其实就相当于可以直接转换输出色彩空间。唯一的区别就是,如果使用开启转换滤镜+直接转换输出色彩空间的组合时,Pot 不会接受LAV的P010输出为输入(所以 LAV 会变成NV12 喂 Pot),但是不开启转换滤镜则可以。

那么让我们仔细端详下这个表。

可以看到,D3D9对于 full range 的视频束手无策,总会clip,我们先一票否决。

使用内置解码器时:

Image

对于422和444只能软解。如果不开启直接转换输出色彩空间,因为转换滤镜的缘故会用NV12,所以自然损失了不少 Chroma 空间的质量;即使开启,renderer最大也只吃422,所以444还是会损失。

对于视频本来就是8 bit YUV的,无论软硬解都OK,反正都是NV12。对于10-bit则比较tricky。如果是软解(H264的情况),内置的 ffmpeg 解码器会帮你 dithering 后 NV12 输出,除非开启了直接转换输出色彩空间,则会直通 P010。而硬解怎么搞都是 P010 ——别忘了,如果是 HEVC,Pot 的内置解码器是强制硬解的。

如上文所述,我们的渲染器碰到 P010,EVR-CP 是很OK的,D3D9、D3D11 都有严重的问题。所以如果和我一样要用 D3D11,就得不开启直接转换输出色彩空间来保证软解时输出正确。至于硬解的情况?我们直接选择 HEVC 的解码器为 LAV 来解决。

再来看看LAV:

Image

基本来说,使用“禁用转换滤镜”和”启用转换滤镜+同时开启直接转换输出色彩空间”这两个组合都可以完美处理所有格式:对于 10-bit,如果是 D3D11 渲染器的情况,要手动取消掉 LAV 里的 P010 输出,在 LAV 中直接 dither 到 NV12。

如果使用转换滤镜但是却不开启直接转换输出色彩空间,因为Pot的转换滤镜只能工作在 NV12,这两种色彩空间,所以即使是10-bit 视频,也是会直接找 LAV 要 NV12,即使你 LAV 没有取消 P010 输出。所以很OK。但是副作用是,无法正确处理442和444的视频,这个和上面原因类似,就不赘述了。

介于我们想用 D3D11 渲染器,然后还要应对 P010 的BUG,我们其实有以下几种选择:

  1. 全局使用 LAV + 禁用转换滤镜 + LAV 中禁用 P010:所有格式都OK。缺点是如果其他情况调用LAV时无法用 P010。
  2. 全局使用 LAV + 转化滤镜 + 直接转换输出色彩空间:所有格式都OK。
  3. AVC使用内置(软解),HEVC 使用 LAV,同时禁用“直接转换输出色彩空间”防止内置软解直通 P010:422、444效果差。

理论上自然应该用2,但是因为某些很纠结的原因(主要是用内置滤镜比较流畅),我实际上是用的3……呃。我就是有毛病我承认。

再看看默认的 EVR-CP:

Image

其中真·默认设置的是倒数第二行。可以看到,效果还是挺不错的(和我改了半天的结果基本一样)。

也就是说,如果不在意缩放画质(这个其实也可以修改算法来稍微改善),Pot的默认设置现在已经完全可以用了,因为实际上他现在已经解决了 banding (or lack of dithering) 这一大痛点。我突然感觉到一阵空虚:我干嘛要折腾这个!

附录:nVidia RTX Video Super Resolution

顺便提一嘴这个(下称VSR)。毕竟我最开始折腾有这个的因素。目前为止支持这个的播放器还不是很多,Chrome 是原生支持的,什么都不需要设置。VLC有个专门的魔改版,但是这个版本有个非常恶性的bug,播放一切非16:9等非标准宽屏分辨率的视频时会显示比例错误

说个题外话:这个BUG已经提出了9个月了,但是根本没人修复。对于这种大型知名开源项目,经常看到这种核心功能还算维护的OK、但是稍微非核心功能的、即使是严重bug也没人修复的窘状。但是与之相反,有些明明理论上规模相当的项目,比如MPV,就有非常充裕的核心开发者和路人在进行快速迭代。搞不懂这是什么原因,是项目太老不够吸引新人?还是PR审核太慢,久而久之就没有人愿意参与?(嘛,想起 ffmpeg 现在还得在 mailing list patch……)哦,对于 VLC 这个特例,丫的 repo 和报错网站(https://code.videolan.org/)居然需要审批才能注册账号,这能好吗?

对于 MPC-VR,已经很早就加入了对VSR的支持,勾选一个选项即可(必须得用D3D11,所以连带着上面各种BUG)。另外还有个fork据说是加强了对HDR的支持,不过我没试过。

至于Pot这边,虽然已经加上了选项:

Image

(要启用D3D11渲染器才能选)但是我这边实际上并不好使,无法调用到 VSR。更离谱的是,如果我改用MPC-VR 渲染器,然后再里面勾选,在 Pot 里还是无法触发 VSR。所以我放弃了。(我有发邮件问作者,但是他说他没问题。)

效果方面,我只测试了开到4(最大):denoise 的强度还是蛮高,对于那种 compression artifact极多的超低分辨率视频效果还行:

ImageImage

但是看 720P 或者 1080P 之类的本身就不是很模糊的视频就油画感很强了,感觉没有必要,不如传统缩放算法。

哦对了,这个 VSR 对于小于 360P(以及大于 1080P?)的视频是无效的,这是 nV 那边写死的,不是播放器/渲染器的问题。

PotPlayer无MadVR设置方案

又来折腾这玩意了。其实之前的方案完全正常啦,但是最近组了个新电脑没买显卡,本来以为反正自己也不玩游戏够用了,没想到居然用MadVR随便播个东西就GPU占用100%:

Image

直接卡到12fps!把所有的缩放算法全部改成最低端的Cubic也只能勉强到50多fps(显示器是75的),看来是没得救了。那让我们找个替代品吧。

面临的问题

如果有读过前文和前前文就应该知道,之所以用MadVR并不是我对画质有什么极致的追求,而是在很多基础的东西譬如10bit抖8、格式转换等上PotPlayer是非常的差,MadVR恰好可以简单地修正这些问题罢了。

具体系统性的细节就不再赘述,如果需要可以复习前面两篇文章。这里直接说我们要解决哪些问题。

其实对于最常见的,4:2:0、limited range、8bit的视频,PotPlayer开箱的默认配置也不是完全不能用。但是有以下三个特例需要处理:

  1. 10bit视频——显示器是8bit的,所以10需要抖到8,无抖动大量banding。10bit视频现在已经非常常见了,动画民间压制组几乎全都是用HEVC 10bit出片。所以这个dithering是必须要有的,否则白瞎了。
  2. full range视频——商业发行的影音产品不算太常见,但是直播等非常常见。
  3. 非4:2:0视频(例如4:2:2、4:4:4视频)——更少见,除了某些民间压制组会用,其他基本见不到。

例如,Pot默认的用EVR (Custom Preset) (下面简称EVR)这个渲染器的最大问题就是不能正常显示full range视频。无论用软解硬解还是外置LAV都不行:

Image

所以我们直接pass。

另外,一个thumb rule是所有转换都应该只做必要的转换,比如如果本来是422,那就不要劣化成420再转RGB;本来是8bit也别转10bit,反之亦然。

PotPlayer近年来的改进以及10bit输出

在最早那篇文章提过,PotPlayer当年最大的问题是他内部默认使用YUY2这个4:2:2的格式来处理,所以常见的8bit 4:2:0格式会被Pot拉伸一次,而且默认还是极差的NN算法。现在,Pot修复了这个问题,基本正常情况都会用NV12、YV12之类的格式通到渲染器。单这一点就把其播放一般普通视频的画质提升了一个量级,完全达到了能用的水平。所以如果没有特殊需求(下述),这两个之前提过的选项可以用Auto不用动了:

Image

不过为了以防万一,还是把下面的高质量也给勾上吧。

另外,在输出方面增加了10bit的输出的选项:

Image

开启10bit输出后会尽量在解码器端输出为10bit,然后到renderer会转成A2RBGB10之类的10bit RGB格式。但是因为我显示器只有8bit,最后还是会banding成8bit(且和P010这类10bit YCbCr格式直接转RGBA的banding还不太一样)。这里自然不开启。而且这个10bit输出还有一些bug:

  • 用EVR,会发生奇怪的颜色反转。蓝色变成黄色
  • 用D3D9 native 解码再输出到D3D9 renderer,会出现一个奇怪的绿条在下面:
Image

最糟糕的问题其实是8bit的视频会被拉成10bit(然后最后在display层面再降回去)——据我观察D3D11 renderer即使这样折腾一次也问题不大,但是D3D9 renderer整个画面会变得超级糊,一定要避免。

处理10bit视频

这里先明确几个前提:我们只追求抖动的有无,质量不关键。另外我是8bit屏幕,所以一定要10转8;如果是用的原生10bit,则自行保证最后renderer是10bit输出即可。

这个转换,可以在编码器阶段进行,也可以在renderer阶段进行。之前用MadVR的时候就是在renderer阶段进行,所以一定要把解码后的视频保持10bit的格式(一般为P010)输送到renderer。

不过现在不用MadVR了,我们应该在哪里进行效果好呢?经过一些基本的测试,结论如下:

首先,如果在硬解native里进行10转8,是没有dithering的,效果很差。

如果用LAV调用硬解,我测试中是发现用DXVA2 native或者 D3D11都会banding,DXVA2 copy-back和软解则无问题:

Image

测试时强制了LAV用RGB输出,这样保证不会在接下来的任何步骤再修改。LAV自己的10转8是有dithering的。我的理解是,用了DXVA2和D3D11 native的话,LAV就完全放手了让他们来输出为NV12之类的的格式,自己仅负责转换为RGB的样子。

240105更新:上面的DXVA的测试结果仅限于 Intel CPU 带的 iGPU;我使用N卡测试时,即使使用native也是自带dithering的!

如果用Pot内置解码测试,默认是用D3D9,只有用D3D11的renderer的时候才会用D3D11的解码,不过可以手动修改。也可以用D3D9 copy-back和D3D11 copy-back。搭配MadVR的时候,这里无论选哪个都是可以直出P010的,也是我之前一直用的。顺便一提,我在这台电脑上用D3D9 native + madVR播放full range视频,会出一个很奇妙的问题:

Image

可以看到色域虽然没有错误伸张、压缩,但是16/235外的被clip掉了。然而我用我的笔记本无法复现。不过无伤大雅,改成copy-back或者D3D11即可。

回到正题。既然我们不能用MadVR,我们可以用默认的EVR、D3D9 renderer或者D3D11的renderer。使用硬解的时候,基本都会直出10bit的P010给renderer。但是凡是在上述三个renderer里发生P010转RGBA(即10转8),也都会banding。开启10bit输出虽然可以正常转成RGB10,但是最后在display层也会转到8bit所以也是同理。一言以蔽之,不要在非MadVR之外的renderer这一层来进行10转8,因为没有dithering。

所以,如果要用LAV内置解码器,就一定要用软解或者硬解copy-back(copy-back的硬解基本在实践上和软解区别不大,应该也是用了ffmpeg来处理)来输出NV12,然后renderer直接转RGB就完事儿了。Pot默认设置不开硬解其实就是这样的。注意一点就是如果你开启了direct conversion (change default output color space) 这个选项的话,可能又变回P010输出坏事儿。

另外一个小细节:不能选D3D11 native解码+D3D9渲染。会强制给你改成D3D9。反之则可以。

总结一下:

  • 硬解直接10转8输出:banding
  • 无论软解硬解如果输出10bit,渲染器里10转8:banding
  • 所以要用:软件解码器或者硬解copy-back来完成10转8的过程。

软解的选择可以用Pot内置(即FFmpeg)、LAV(可以手选dithering的方式)。记住,Pot默认强制HEVC用硬解,即使不勾“Use DXVA”也是。可以通过修改这里为FFmpeg.dll来强行取消:

Image

FFmpeg根据我的观察应该是用的ordered dithering。

这里来比较一下。先来一张banding的(所有的截图都是1080p片源1440p播放,然后截图后调整曲线来增加对比度,最后再NN放大到3x):

Image

再比较一下dithering:

Image

可以很明显看到两种dithering的区别。观感上来说其实都差不多,不过还是用random吧。中间的则是对比用的MadVR——MadVR dithering最好的地方在于他工作在全分辨率(也就是1440p),所以pattern极其小,可以说100%时肉眼完全看不出任何颗粒感。别的都是先生成dithering、然后再被放大,那自然效果远不如。不过,看片的时候还是OK的。

至于渲染器的选择在这里不影响,我们都是8bit输出了反正。

视频resize的表现

确定了10bit没问题,我们再回来看看经典8bit视频resize的效果。这里有点出乎我的意料:无论是用D3D默认的DXVA Video Processor,还是D3D11带的D3D11 Video Processor(Pot里选成Auto就好),效果都出奇的好,可以和说我MadVR拉满不相上下!

Image

我的理论是,他这个不知道用了什么Intel的劳什子视频后处理科技,估计是在全屏分辨率级别搞了点锐化之类的?无论如何,至少看高锐度的东西效果很好,清晰,也没有太明显的ringing,远强于Cubic之类的了。我们尽量选用能调用Video Processor来resize的方案。顺便一提,EVR默认也是调用DXVA Video Processor来当resizer。

Full range、422/444视频

Full range视频不出意外地都没有问题,甚至EVR (Vista/.NET3)那个都没问题——只要别用EVR custom preset那个。

422/444视频则比较tricky。理想情况,当然是422就全程用YUY2,444就全程AYUV,不要出现被转化为420格式再喂给渲染器的现象,自降分辨率是大忌。

但是现实很骨感,这里面有好几个局限性:

  • Renderer只能接受部分格式输入
  • 某些格式用LAV+开启Pot转换滤镜时,Pot不收(虽然用内置的可以)
  • Pot的自动格式选择非常的弱

让我们先来个一览表:

Image

这里面绿色是我们想要的,黄色的是非最佳的,红色的是无法接受的。这里面第三列就是前面提过那个开关:所谓的“direct conversion (auto change color space)”是开还是关。

简单概括下:如上面说的第三点,Pot如果把输出设为Auto,其实基本就是只会用NV12/YV12这种8bit/420的格式。唯一的例外是用硬解native的时候,会直通P010(10bit 420)到renderer(但是我们已经说过我们不想这样,因为非MadVR的renderer没有dithering)。所以,这样下来面对422/444的视频,都会被Pot给降低到420,bad。

这个问题可以通过这个开关来改善——开了之后,对于EVR,解码器会自动改用422和444的输出,对于D3D9,至少能修复422(但是444会crash)。D3D11则比较怪,即使开了开关,还是只能被喂420(或者RGB);我稍微查了下应该是支持至少422才对,可能是Pot的implementation有问题吧。

但是这个开关也有个副作用,就是用内置解码器的时候,会把10bit本来我们想要的8bit输出(抖动后)也给变成了10bit直通。

如果是用LAV,就很容易解决这个问题,LAV里把10bit的格式全部去掉,自然就只可能输出抖动后的8bit。

(这里有个疑似BUG:Pot的转换滤镜开启时,它并不收来自LAV的P010,如果你强制在LAV那边只勾选P010,Pot会直接强制自行关闭转换滤镜……嘛,纯粹是好奇罢了,毕竟我们的目的恰恰是LAV不要用10bit输出。)

另外,使用“LAV+EVR (Custom Present)+开启auto coloir space开关”这个组合时,除了会有前面多次提过的full range色域错误的问题(未伸张,即0变成16),另外播放444视频时,会出现色域过度伸张的错误(即16变成0)。

但是如果把渲染器换成EVR (Vista/.net3),看表格里似乎完美?

很可惜,EVR (Vista/.NET3)有个更阴间的BUG……字母某些特效会变成这鸟样(请无视我没安装字体。下面是对比用的EVR (CP)):

Image

结语

既然没有一个完美方案,我们只能两害取其轻了。我最后采用的是内置软件解码器+D3D11渲染器+不开auto色域转换开关的方案(换成D3D9渲染器也行)。这样只有422、444不能完美播放(但是也不至于不能播放),而我除了我自己造的测试视频其实根本没下过这种视频w。我还检查了下BT601的视频,也是没问题的。

哦,其实还有个方案就是上面提过的LAV+强制RGB输出的方案。可以一揽子规避所有转换的坑。但是,这样就没法享受到高质量的DXVA/D3D11 Video Processor做resizer,所以还是算了。

20230520补记

最近碰到一个视频是 SMPTE 240M 的matrix,发现用D3D9的 renderer 有问题,D3D11的OK(和MPV的效果一致),所以虽然都行还是推荐用D3D11。

另外,我发现我上面明明还有一个全绿的组合:使用LAV+D3D9渲染器+开启auto coloir space开关,但是我为啥没使用?我自己也忘了,大概还是为了尽量不用外部滤镜来让截图不偏差吧。

个人用视频播放器最新设置方案

本文是前文,外挂LAV+开启PotPlayer转换滤镜时的最佳设置方案的追记或者说更新。

本文大纲:

  1. 重新总结下视频播放中Pot无法胜任的部分和原因;
  2. 我现在如何设置PotPlayer来workaround这些问题;
  3. 我的备胎播放器;
  4. 为什么如此忍辱负重也无法抛弃PotPlayer。

视频播放的几个转换

视频播放,宏观上通常需要经历这么几个的转换步骤到输出(不按顺序,也不一定都有):

  1. 解码
  2. 色度抽样还原 (420或者422->444)
  3. 缩放
  4. YUV->RGB
  5. 降位深(10bit -> 8bit)
  6. 反交错

解码没什么好说的,其他大部分逐条说一下。

色度抽样还原

色度抽样还原 (420->444) 就是把被缩放到(面积)1/4大小(420)或者一半大小(422)的U、V channel放大到原始尺寸,和缩放本质没有区别。无非就是点对点播放时,Y通道不需要缩放而色度通道依然需要而已。

这个工作LAV、Pot和渲染器都能做,做的最好的是MadVR这个大家都知道了,LAV可以接受,Pot如果如上文所说,如果使用了转换滤镜(下边凡是提到Pot,都是指如果使用了Pot的转换滤镜)会默认强制将420的转换一次422且使用最差的硬差值算法,勾选“高质量转换”可以改善但仍然一般——推荐不在Pot进行。

缩放

都能做,MadVR最佳。

YUV->RGB

都能做。这个的质量问题我不是很敏感,但是Pot有诸多BUG。不推荐在Pot进行YUV和RGB的转换(一般也不会)。

降位深(10bit->8bit)

都能做,但是如果被Pot降位深会完全无任何dithering,效果完全不能忍,巨大banding,故实际上必须要在LAV或者MadVR进行。

反交错

都能做,但是LAV和MadVR的算法好一些。Pot有一堆选项,但是却没有感觉特别好用的。我个人对于反交错的要求其实不多,就一条:真·交错内容一定要还原成原始拍摄帧率(60 / 59.94 fps),否则流畅度不能忍。这点MadVR和LAV的3种算法都能做到,如果用Pot,要选2x frame的,我现在选用的是“motion adpative (2x frame)”这个。

另外对于IVTC的内容,即时反交错的效果都差强人意,但是Pot的更差些。

具体设置方案

那么有了上面那些预备知识,我们可以来对比下几种设置方案。当然,我们只考虑高画质的方案。

LAV->Pot(禁用转换滤镜)->MadVR

分工:

  • LAV:解码
  • Pot:什么也不做
  • MadVR:色度抽样还原、缩放、YUV->RGB、降位深、反交错

设置方法:

  • Pot里转换滤镜disabled
  • LAV全默认设置

另外,可以通过修改LAV的输出或者反交错选项来把部分工作移动到LAV中(比如如果你比较喜欢LAV的反交错滤镜),但是整体区别不大。

优点:最高画质设置,完全不会被Pot劣化。

缺点:导致Pot非常容易崩溃——尤其是播放TS文件的时候(原因不明),这也是为什么会纠结这一切的原因。

LAV->Pot(开启转换滤镜)-> MadVR

分工:

  • LAV:解码、降位深、反交错
  • Pot:什么也不做
  • MadVR:色度抽样还原、缩放、YUV->RGB

也就是前文提到过的方案。首先,我们知道一旦开启了转换滤镜,由于Pot内部处理精度只有8bit且没有dithering,所以降位深必须在Lav做好。事实上,由于Pot的转换滤镜根本不接受10bit的输入,Lav那边会自动diether成NV12再输入Pot,所以无需专门设置。

至于反交错,Pot有个弱智问题就是一旦进入了他的转换滤镜,无论你的反交错是enabled还是disabled,后面都会强制输出deinterlacing=off的flag,导致无法在MadVR中进行。所以必须在Lav或者Pot自身里完成反交错才行。这两个选的话,当然是Lav的好些。

设置方法:

Lav:选一个反交错滤镜开启,其他默认。

Pot里:

  • 开启转换滤镜
  • Video->colorspaces中,选择NV12或者其他4:2:0的色彩空间
    • 目的:防止Pot自做多情的420 to 422转换
  • “Direct conversion”选择“Enable: change default output color space”
    • 目的:直通YUV422/444/RGB内容到MadVR
  • 反交错:disabled

优点:由于大部分MadVR的优势部分依然是在MadVR进行,所以基本可以维持最高画质。非YUV420的内容会直传MadVR所以不会被Pot劣化。

缺点:依·然·会·崩·溃。

Pot(解码+转换滤镜)->MadVR

分工:

  • Pot:解码、反交错
  • MadVR:降位深、色度抽样还原、缩放、YUV->RGB

在上面那个方法依然会导致Pot不时崩溃的情况下,我开始思考:能否完全绕过Lav,直接用Pot内置解码?对于我来说,解码器的质量并不是关键的,因为解码本身是个deterministic的过程(而且Pot其实就是用的ffmpeg,质量不会有大问题)。但是通过使用Pot自带的内部工作流程,应该会明显改善崩溃问题。

我的第一直觉是这个流程对10bit会不行——从上文可知,Pot的转换滤镜甚至不接受(LAV的)P010的输入,怕不是直接就给我砍成8bit了?结果不试不知道:在开启“Direct conversion”的前提下,Pot用内置解码器居然反而可以直通P010到MadVR!

blog01

那么赶紧来试一下其他几种色彩空间:

YUV422:YUY2直通MadVR; YUV444:AYUV直通MadVR。

很完美!当然,对于YUV420的视频,Pot那个自作多情的伸张成422的问题依然存在,所以手动设置色彩空间为NV12依然是必要的。

设置方法:

Pot里:

  • 开启转换滤镜
  • Video->colorspaces中,选择NV12或者其他4:2:0的色彩空间
    • 目的:防止Pot自做多情的420 to 422转换
  • “Direct conversion”选择“Enable: change default output color space”
    • 目的:直通YUV422/444/RGB内容到MadVR
  • 反交错:enabled,选一个喜欢的。个人用motion adpative (2x frame)

优点:终于不会崩溃了!另外,除了反交错由于Pot的限制必须在Pot进行无法达到最高质量以外,其他的转换都正常在MadVR进行,接近完美。

缺点:反交错效果略微差点。

另外,稍显遗憾的是,无论是上面哪种方案,之前提到的截图问题都存在。我以为改用内部解码器就能解决这个问题呢,看来似乎只要用MadVR就会这样?

音频解码

音频解码可以继续用LAV,或者也换回Pot自带,我感觉区别不大。因为这个并没有太多可以搞糟的部分嘛。

唯一一个需要注意的是5.1->2.0转换。LAV默认的设置是这样的:

QQ图片20190713212105

也就是说,Center和Surround都会降低到71%、LFE直接完全关闭之后再mix到Front——据LAV的作者在Doom9说,这是标准里写的。那么我们把Pot也改成一致的呗:

QQ截图20190713212326

这里我改了几个地方:

  1. mixer level改成了和LAV默认一致。
  2. 关闭了Expand stereo to center 和expend stereo to surround。这两个选项其实是把2.0映射到5.1才有必要的,但是Pot的实现很怪,是先把2.0用这个映射到5.1,再用下面的mix level mix回2.0。如果下面全是100的情况下自然是完全一样,但是我们都改成非100了,还保持这两个勾中会导致音量变低,所以去掉。

这么改完听5.1音轨,发现LAV的声音还是会小一点(mix倒是听上去完全一样了),研究了下发现是LAV里那个”prevent clipping”选项导致的(自动降低了音量防止削波也就是爆音),我音量因为一般都不拉满所以其实无所谓,可以自行调整。

嘛,这个改不改其实区别不大了,因为一般有5.1音轨的视频大多会有官方混音好的2.0,2.0的设备就应该听那个才对。

备胎播放器:mpv->SMPlayer

在Pot频繁崩溃我却不知所措(笑)的期间,我使用mpv当做备胎播放器,尤其是用来播放ts文件。

mpv是个非常优秀的跨平台开源一体化播放器,渲染质量很高功能也很全。尤其是不依赖太多外部程序(比如LAV、MadVR)这点非常好。而且mpv那种seek时丝般顺滑、毫无delay的感觉和极速的启动速度实在太美。可以一键开启手动反交错(默认是D)这点我也很喜欢。

但是作为一个命令行为主的工具,其用户体验并不是特别好。本人并不排斥CLI工具或者手动修改config文件,但是如果需要经常或者大量调整这些东西,还是非常难受的(尤其是大多时候还得去翻doc,而不是有intuitive的选项可以直接找到想要的设置)。另外,自带的那个简陋的UI也有诸多不便。

于是我去找了下mpv的套壳播放器。很快,我就找到这款叫SMPlayer的软件。虽然UI比MPC-HC还要丑几个档次,但是至少完美保留了mpv的优点,定制快捷键很方便(我基本全改成和Pot一样了w),有基础的选择音轨、章节功能,作为主要拿来看ts的备胎,我也不能要求太高了。

为什么Pot不可替代

个人对Pot的依赖,有部分是来自于迁移成本太高(我建立了大量播放列表),但是主要还是UX体验太好。

就拿一点来说,事实上也是我每次用其他播放器都感觉极其不便的一点:章节选择。Pot可以:

  • 在进度条显示章节marker
  • 且悬浮会有章节名称的Tooltip;
  • 一键(H)开启章节列表选单,然后在列表中自由选择想要的章节;
  • 可以用快捷键(默认是Shift+PageDn)来快速跳转下一章节。

上面的这些功能,不少播放器都有某种程度的支持(比如mpv的进度条有章节marker,大部分播放器的menu里都有章节选择),但是能完美做到上面所有的?并没有。

尤其是一键开启这里——我之前多次提过,快捷键是否“快捷”和是否有快捷键一样重要。比如你想在SMPlayer里选章节?倒是可以,先点browse,再点chapter,然后选,这至少需要3-5秒,中间还要不断移动鼠标光标到很小的目标上。这个方便程度和直接按H是天上地下的。同理,在Pot里按A选音轨、L选字幕、都是极其经常需要用到的,单键快捷键比起组合键或者菜单的优势非常明显。

而且万一视频没有章节,想自己添加?小case:按下P即可添加bookmark。而且这个bookmark在以后使用上,和章节完全没有区别:你依然可以按H查看、按Shift+PgDn来跳转、在进度条上看到marker。另外,通过设置选项之后,bookmark完全可以做成外挂的,这样即使视频文件移动了也能保持所有的bookmark。(参见前文的相关内容)。

注意,bookmark这个功能不是Pot独有的,我能想到不少播放器都有这种功能。但是能做到如此方便、让人去愿意去用,才是其独到之处。

同理,我们来比较下“跳转功能”。在Pot里,按下G会出现跳转框:

QQ图片20190713205207

同样地,在SMPlayer可以用ctrl+J出现跳转窗口:

QQ图片20190713205308

看出两者的区别了吗?姑且不论Pot多了个按帧跳转的功能,但就按时间跳转,Pot就多了:

  1. 精确到毫秒
  2. 直接默认选中全部时间,所以配合ctrl+V等于多了个快速的选中当前时间的功能。

当然公平起见,我们也举个比较接近的例子,MPC-BE的(ctrl+G):

004

基本和Pot很接近了,但是还缺少一个自动hightlight时间的功能,所以不能直接ctrl+V选择当前时间,得先ctrl+A一下。

再来说说缩放:调整视频canvas大小是个很常见的操作,在Pot里你可以:

  • 按123选视频原始大小的50%、100%、150%大小;
  • 按atrl+1/2/3/4按当前桌面百分比大小来缩放;
  • 全屏时依然可以按上述快捷键,来直接窗口化并缩放到对应大小,而不用先退出全屏;
  • 拖拽改变大小时,窗口frame保持比例,不会出现黑边;
  • 在同一个窗口打开新视频时保持窗口大小(可设置)。

等等等等。上面后四条都是非常好用的功能。

播放列表方面我别的播放器的用的不多所以也没有对比不太好吹,至少可以做到只选取视频的部分加入播放列表:

QQ图片20190713211402

Pot不是一个完美的播放器,但是就是这种UX上的attention to detail,让人爱不释手。

结语的一些碎碎念

我发现x264好像根本不支持RGB空间。我刚测试才发现,之前自己用ffmpeg做的“RGB24测试视频”实际是YUV444的…

PotPlayer的崩溃问题我感觉和他的I/O buffer有关。因为我发现在我的5400rpm硬盘上开启bitrate特别大的文件(比如ts)时或者拖拽进度条时最容易崩溃。

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

本来想直接在前文里追记,但是正好有点别的东西一并写了。

Progressive的DVD

上文中说到“发现近年的DVD大多都是progressive的了”,其实相当不准确。感谢boday的指点,其实准确地说:近年的DVD依然大多是交错的,但是确实存在一种,(例如TrySail的好几张碟都这样)实质是Progressive的DVD,元数据长这样:

Width : 720 pixels
Height : 480 pixels
Display aspect ratio : 16:9
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Scan order : 2:3 Pulldown

这种应该叫做“软Telecine”,可以看到帧率是23.976p而不是30,其原理就是完全按照Progressive来存储,但是加了个2:3 Pulldown的metatag,所以DVD player播放的时候会即时进行telecine来pull到30i。当然,对于电脑播放的情况,解码器会直接按照24p播放,也不需要进行IVTC。

看不出交错的隔行视频

前文提到有些HDTV明明是隔行却看不出任何交错现象。这个问题后来想想简直太弱智了:因为人家就是用逐行拍摄、然后把每一帧拆成两场罢了,由于根本就是同时曝光的两场,所以weave回去自然不会有交错条纹……

MKV的音频Delay“问题”

后来问了作者了,作者到也很直接:“我没什么好说的,有很多原因可能导致这个,比如sequence不是从视频关键帧开始等等”。总之我理解就是他是说这个delay区别并不是什么bug,而是有技术原因在背后罢了。

上面算是补记,下面是一点点新东西。

PotPlayer使用外挂滤镜的截图问题

Pot使用外挂解码器(Lav)之后,截图功能就变得稳定性极差。估计多出自Pot截图的时间点和渲染的步骤不同步/不一致造成。最基本的错帧问题大家都知道了,就不提了,提几个别的。

其中最滑稽的问题是,如果开启了Pot的转换滤镜,会出现播放中截图暂停后截图结果不一样的现象。其不一样之处主要是缩放质量,缩小播放尺寸+用实画面截图(ctrl+alt+C)就可以发觉。

001
Lav+Pot转换滤镜实画面截图对比:先暂停 vs 播放时直接截图

顺便一提,如果不开启Pot的转换滤镜,倒是没有暂停和不暂停的区别了,但是截图出来的依然和你实际MadVR渲染出的高质量缩放是不一样的,在缩放倍数较大的时候很明显。当然,这个倒也是意料之中了。

002
实画面截图 vs 手动prtScn(200% NN放大)

说回开启了Pot转换滤镜会出现播放中截图和暂停后截图的结果不一样的现象,其实有另外一个更奇葩的:播放时截图Pot的yuv->rgb的转换矩阵和暂停截图不一致。这个现象经常在没有很鲜艳的颜色时不是很明显,所以容易被坑。

具体说来,在“暂停后截图”时,Pot会和正常编码器/渲染器一样(?),自行根据视频metatag或者尺寸选择正确的转换。然而,在“播放中截图”时,Pot会套用这个设置:

003

这里的坑爹之处在于,和前文提到过的让Pot处理YUV->RGB的BUG一样,这里设成Auto也会永远用BT.601,即使视频是HD、且有显式Tag的。由于HD视频更为常见,所以我手动改成了BT.709,但是自然这样会导致SD视频又有问题。所以,如果真的要用Pot截图,还是老老实实暂停了再截吧。

MadVR缩放算法

另外没事儿干对比了下MadVR的缩放算法。简单来说就是chroma upscaling用NGU比Lanczos在某些大色块高锐度(比如我一直用的测试视频)还是勉强有肉眼可见的区别,虽然实际放片还是区别很小。我暂时改用NGU+low quality了,能把GPU的load压在20%左右,还算能接受。由于上述各种笔油鸡,下面截图用的PrtScn。

004

Downscaling/upscaling那边,我比较了几个没看出大区别,NGU太耗资源不考虑,我相对喜欢锐度高一点的,所以继续用Lanczos+anti-ring filter。

(顺便吐槽自己干的一个蠢事:用50%大小播片,然后好奇为啥NGU完全不耗资源……)