ffmpeg静态图转视频

注意:本文部分内容之前发表在此文。但是经过补充后单独成章比较好,就移动到这边来了。

将一张图片转成视频的基本命令很简单:

ffmpeg -loop 1 -i {img} -t {dur} -vf format=yuv420p output.mp4

默认的fps是25,可以用-r指定成别的。这里重点注意-vf format=yuv420p部分,这个保证视频会被正确转换为最常见的YUV420格式,否则会使用YUV444格式。这个等效于-pix_fmt yuv420p

同理,如果需要其他格式(YUV444、YUV422之类),只需要替换成其他的pixel format即可。如果想要full range,可以使用yuvj420p

但是仅仅这样做,有两个问题。

选择的正确RGB->YUV转换矩阵

第一个问题是RGB->YUV的转换矩阵。ffmpeg默认是使用BT.601矩阵来进行这个转换的,如果你的输出视频是SD分辨率,这并没有问题。但是如果是HD视频,HD默认的标准是BT.709,所以这样就不对了。最明显的就是纯红色255, 0, 0会变成255, 25, 0。

解决办法,首先自然可以给输出结果显式加上BT.601的metadata:

-colorspace smpte170m

(虽然NTSC和PAL有各种微妙的区别(参见此文),但是这里用PAL的bt470bg也可以,因为这单说矩阵,这俩实际上是一样的。)

但是,不推荐这种做法。有的滤镜/渲染器根本无视元数据。HD视频还是老老实实用BT.709就好。所以最好的办法是进行正确的BT.709转换。

ffmpeg有N个video filter可以实现这个,最常见的是scale

ffmpeg -loop 1 -i {img} -vf scale=out_color_matrix=bt709,format=yuv420p -color_primaries 1 -color_trc 1 -colorspace 1 -t {dur} output.mp4

其中-vf scale=out_color_matrix=bt709部分是把图片转换成BT.709(Rec. 709的另外一个名称)。因为我们还有个format的vf,直接把两者用逗号串起来(filter chain)。

后面的-color_primaries 1 -color_trc 1 -colorspace 1的是在元数据里标注。如果用x264编码(默认如此),也可以直接用-x264opts colormatrix=bt709。当然,如上所述,如果是HD视频可以略去不写(不推荐)。

除了-vf scale,还可以用:

  • -vf colormatrix=bt601:bt709,format=yuv420p:从命令来看,感觉实质是先转601再转709。
  • -vf colorspace=iall=bt601-6-625:all=bt709:format=yuv420p :同上。另外注意,这里的formatcolorspace这个vf的一部分(冒号分割而非逗号),而不是再调用format。 呃,这个有点问题,实际上你要只转换matrix不动Primaries和Transfer function,否则红色会色偏。太麻烦不推荐使用了。如果感兴趣的话,正确的命令是:
  • -vf colorspace=iprimaries=bt709:primaries=bt709:ispace=smpte170m:space=bt709:itrc=bt709:trc=bt709:format=yuv420p
  • -vf zscale=matrix=709:r=limited,format=yuv420p:这是一个比较新的filter,来自zlib21-08-08更新:在本文写成时,如果用yuv420p,会自动imply limited range(同理是yuvj420pfull range)。但是最新版本的ffmpeg下的zlib已经不是这样(疑似是因为这个改动)。所以,请显式加上limit range的参数r=limited来保证产出的视频是支持最广的limited range视频。

几个讨论可以参见这帖这帖

swscale的颜色误差bug

我之前一直是使用上述的-vf scale来转的,但是总是发现颜色有点偏——白色(255, 255, 255)会变成略微发黄的颜色(252, 255, 252),我以为这仅仅是精度不足的缘故也没太在意。直到有一天无意发现,如果我先将输入的BMP图片另存为PNG格式,就不会发生偏色。这完全不make sense!于是我报到了ffmpeg

经过快2个月无人问津后,我忍不住去ffmpeg的emaillist发了个帖,果然引来了玉——除了一些workaround之外(下述),最重要的是有人指向了真正的bug:#979

简单来说,swscale这个库(libswscale)——包括scale滤镜——有一个奇怪的bug:从bgr24转换为YUV会有色差,但是rgb24就不会(两者应可以无损转换)。上面BMP和PNG结果不同也是因为PNG用的是rgb24的pixel format,而BMP是bgr24。

既然知道了问题所在,我们只需要先转换一次即可,把上面的vf前再串一个format

-vf format=rgb24,scale=out_color_matrix=bt709,format=yuv420p

就可以啦!那么上面提到的其他几种转换滤镜,有没有同样的问题呢?

  • colormatrix:同样的bug,这个filter应该也是基于libswscale。
  • colorspace:如果你使用上述的方式,使用colorspace内置的format参数来转换成yuv420p而不是串一个format vf,可以避免这个bug。
  • zscale:无此bug。

另外,这个bug还可以通过添加scale的flag,accurate_rnd(精确rounding)来修复(这里还加上了另外一个增加精度的flag,full_chroma_int,不过这里accurate_rnd其实就够):

-vf scale=out_color_matrix=bt709:flags=full_chroma_int+accurate_rnd,format=yuv420p

当然,这并不是说这个bug仅仅是精度的问题:否则无法解释为什么rgb24就无问题。

另外,colormatrix之类的vf虽然没有flags参数,但是你可以增加-sws_flags accurate_rnd,也可以修复问题。

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

本文是前文,外挂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)时或者拖拽进度条时最容易崩溃。

浏览器对full range视频的支持

为什么会去折腾full range video这个小众的东西?这次还真不是我闲的蛋疼,事实是我发现很多Twitch直播已经开始用full range了(例子有现在火热进行中的Supermajor(PGL)和之前的Epicenter),然后用Firefox看就发现颜色不对,对比度爆表。

之前有“控诉”过Firefox对视频的支持程度落后Chrome一个世纪,当时提出了几个Chorme支持、Firefox不支持的东西:

  • RGB视频
  • 4:4:4或者4:4:2视频
  • Full range视频
  • 对nV显卡的支持不好

当然,这几条还是对的,但是我今天发现Chrome对full range的支持也不是完美,所以还是客观起见,详细说明一下。

说到这个话题,不得不先重复一遍我之前在各种场合提过多次的所谓“对nV显卡的支持不好”具体啥意思。其实,就是在Win 7 + nVidia显卡的默认设置下,Firefox播放视频的色域(color range)会错误。这里的“错误”,严谨地说是limited range(就是99%的视频)不会正确拉伸到full range。

这个问题的产生原因是Win7不支持D3D11 DXVA,而Firefox没有对D3D9 DXVA进行优化。其实,之前Chrome也有这个bug,但是在我提出之后Chrome几个月后就修复了。这个问题的解决方案,除了换A/I GPU或者升级到Win 10这种废话,就是

  1. 软解视频,即把media.hardware-video-decoding.enabled设为false
  2. 修改nVidia控制面板的一个设置,从“通过视频播放器设置”改成手动设为full range:

QQ图片20180609164804

我之前一直是用2,倒是不会影响本地播放器的播放(本地播放器我本来就没开DXVA)。

现在说回full range视频的解码。先说Chrome那边:软解的情况下(设置chrome://flags/#disable-accelerated-video-decode 为Disabled),完美无缺。硬解就不太行了,会把视频强行进行一次伸张,导致颜色被clip。我发的bug ticket在此,这里有个视频可以测试:

当然,你也可以去上述的控制面板手动改成“limited”,来让他不伸张,所以正好得到正确的颜色,但是很显然这样又会毁掉所有的limited range的视频的颜色,所以还是老老实实软解吧。

Firefox除了硬解和Chrome有一样的问题以外,软解也不行——我发的ticket在此

基本内容就是这些了,顺便讲下上面那个视频是怎么造出来的。首先自然是ps里把那个图画出来,然后用FFMPEG做。上次已经提到了记得要加-vf scale=out_color_matrix=bt709来保证输出的YUV是BT.709的,那么full range怎么处理?我网上搜了下意外地发现相关信息相当少,一开始搜到一个什么-color_range 2(这个参数ffmpeg的documentation根本没提到啊喂),后来发现效果其实就是强行在元数据里塞个full range,结果视频的像素数值还都是16-235范围内的,出来就是个灰暗的视频囧。

最后在这贴搜到原来要用-pix_fmt yuvj420p才能输出0-255的视频。-color_range 2都不用加,出来的视频自动metatag都是full range了。我用的完整命令行如下:

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 yuvj420p out_420_709_full.mp4

外挂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作者的原帖见此

本文中使用的测试视频由作者使用静态图片使用ffmpeg生成。其中的一些细节请参见此文

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]

另外,在测试过程中我发现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的视频实践中基本没有。

压制ゆうゆ演唱会视频小记

文章里的事情大概是几个月前的了其实,不过为了叙述方便还是按照时序讲。

之前从YouTube下载了这套非常罕见的ゆうゆ(岩井由紀子)的唯一演唱会(至少是唯一有视频记录的)《ボクらは元気なゆうゆ印》的全集。虽然画质不怎么地,但是能看到已经是万幸了。

将整套视频共7个part用youtube-dl下载完毕后,有几个问题导致欣赏起来不是很方便:

  1. 分段
  2. 视频比例不对,外加有没切割干净的黑边。考虑到该演唱会只发布在VHS上,应该是录屏的结果(外加ntsc各种奇怪的劳什子)。

于是自然就想到把这7段自行压制一下,整合成一个视频。

最先想到的自然是MKV无损拼接;但是随便试了下就放弃了:我发现这几个视频居然连分辨率都不一样——有的是360p,有的是480p——一开始是怀疑yotube-dl下载的问题,但是double check了之后发现Y2B上也是如此。也因此,导致在YouTube给出的编码格式都不一样:有的音频是Opus,有的是Vorbis。

切边

第二个想到的是megui。megui里切黑边很方便,有可视化,可以切的非常干净。最后生成对应的AVS脚本。至于比例问题,考虑到原始视频自然是4:3的,所以无脑把切剩的拉到640×480,目测比例没大问题:

crop.png
左:切割前 右:切割后

使用的参数是:

crop(2, 28, -14, -32)
LanczosResize(640,480) # Lanczos (Sharp)

但是切完之后,发现后续步骤没法进行了:megui本身并没有一个特别好用的视频合并工具。而且和大多数视频一样,这些视频有个问题:音频和视频的长度并不一样。就拿第一段为例,视频的长度为00:07:54.507000000,音频的则是00:07:55.021000000,足足错了快1秒!这在播放单独每个段落的时候自然没问题(超出的音频直接就掐掉了),但是如果贸然将每段单独转换并一一合并的话,会出现(第二段起)音频不断滞后或者提前的音画不同步问题。我在megui里找了半天,似乎没有办法简单地克服这个问题。我总不能自己找个音频编辑软件把每个音频都手动切割一下吧?另外,考虑到megui处理视频的时候,是把音频和视频分开处理的,这也不甚方便:每次压完之后都得手动合并一下音频视频流(我知道可以用脚本自动化,但是实在是费不起那个功夫)。

于是我在网上漫无目的地搜索,搜到了avidemux这个从名字到UI都略蠢的软件:

003.png

当初选这个软件是因为这个软件直接就有合并文件的功能(把N个一起拖进来),但是试了下就发现,依然有上面所述的音画不同步的问题——而且不同分辨率也是合成不了。

但是你别说,这玩意虽然bug奇多,但是功能还挺全。其最方便的是各种filter,和XnView之于图片一样,可以添加一堆依次适配。这对于我那几个360p的分段有奇效,因为我可以直接添加三个filter:第一个先拉大到640×480,第二个用之前提过的crop,第三个再拉到640×480。这样做(而不是直接在360p上crop再拉伸)的好处是可以保证能和480p那几个完全对齐。虽然我猜这些filter的原理也都是avs了,但是至少这界面人性化很多。所以,我决定就用这个软件替代megui来进行前面的crop+resize的工作。

对于输出的视频和音频编码,我视频选了ultra fast+-crf 12的超高质量(外加节省时间),音频选了copy,来最大可能地减少二次压缩的损失,因为后面反正还要合并。还是要吐槽下,这个软件确实很笨,没法导入导出设置,那些filter每次都要重选。还好只有7个,否则我怕不是要疯掉。

合并

于是经过烦人的点点点,我终于有了7个MKV文件,每个都是640×480分辨率,有视频流和音频流,无黑边比例对,就差合并了。这里要动终极武器ffmpeg了。ffmpeg有一篇很不错的合并视频的教程,不过前几章都是教你如何无损(不重编码)合并同编码视频文件的,可以跳过。我们这里要用的是“Concat filter”那个。这里是官方的范例:

ffmpeg -i input1.mp4 -i input2.webm \
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]" \
-map "[v]" -map "[a]" <encoding options> output.mkv

可以看到这玩意语法也相当啰嗦,不过还是那句话只有七个,所以我们就手写吧…结果如下:

ffmpeg -i 001_edit.mkv -i 002_edit.mkv -i 003_edit.mkv -i 004_edit.mkv -i 005_edit.mkv -i 006_edit.mkv -i 007_edit.mkv -filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] [2:v:0] [2:a:0] [3:v:0] [3:a:0] [4:v:0] [4:a:0] [5:v:0] [5:a:0] [6:v:0] [6:a:0] concat=n=7:v=1:a=1 [v] [a]" -map "[v]" -map "[a]" -c:v libx264 -preset slower -crf 18 -profile:v high -level 5.0 -c:a libvorbis -qscale:a 6 result_final.mp4

这里,AVC我用了slower的preset,high@5.0的profile外加-crf 18,音频用了Vorbis可变编码率-qscale:a 6

压制耗时不长(毕竟只是一个标清的视频),大概1.6x的速度。检查结果,完美无瑕(当然,每段衔接处会顿卡,这个无法避免),前面说的音频滞后/不同步的问题完全没有,果然ffmpeg还是专业啊。

章节

对于演唱会类的视频,没有章节怎么能忍。之前我在整理CoCo的演唱会视频时已经研究过如何制作章节,虽然MKVToolNix似乎有逐个添加章节的功能,但是还是手动写XML来得方便。

制作起来倒也很简单了,就是繁琐些:自己看视频找节点,然后用g(PotPlayer快捷键)查看复制时间戳,然后填写到XML里就是。章节名称网上找了好几个都不全,我用的是这个(手动添加了个“yuuyu即兴创作”(Special: ゆうゆアドリブソング)的段落)。

结果:


<?xml version="1.0"?>
<Chapters>
<EditionEntry>
<ChapterAtom>
<ChapterTimeStart>00:0:00.000000000</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>Opening</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:00:31.266</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>アッというMAにMEっ!</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:03:46.312</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>25セントの満月</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:07:55.995</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>アラジンの魔法ビン</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:11:28.369</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>メトロポリス・ハネムーン</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:15:07.825</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>へへへのへ</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:19:04.265</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>はてなが咲いた</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:23:25.139</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>Special: ゆうゆアドリブソング</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:26:25.334</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>ついて行けない</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:15:07.825</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>へへへのへ</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:19:04.265</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>はてなが咲いた</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:29:37.354</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>爪を噛んでた</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:33:51.745</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>-3℃</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:37:32.261</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>Panic'n Roll</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:44:23.560</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>天使のボディーガード</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
<ChapterAtom>
<ChapterTimeStart>00:48:06.486</ChapterTimeStart>
<ChapterDisplay>
<ChapterString>マグネット・マジック (Encore)</ChapterString>
<ChapterLanguage>jpn</ChapterLanguage>
</ChapterDisplay>
</ChapterAtom>
</EditionEntry>
</Chapters>

view raw

chapter.xml

hosted with ❤ by GitHub

有了这个,用MKVToolNix合并进MKV里就是了。chapter的选项在Output里:

005

结果不用说,很完美。

关于视频本身

当我第一次看这个演唱会的时候,还是略显感伤的。作为小猫俱乐部里我的最爱,ゆうゆ的巅峰自然还是小猫俱乐部活跃的时期。当时在ゆうゆ小猫里是固定前排,要单曲有单曲,要组合更有人气爆棚的うしろゆびさされ組。和大多数偶像一样,在小猫俱乐部解散后,单飞的ゆうゆ人气一路下跌,最后在89年后直接停止了歌手活动专心做telent,但也就是在三四线游荡,最后撑到97年结婚彻底退出娱乐圈。不过比起许多80年代偶像现在徐娘半老还在辛苦地走穴赚钱,安心做家庭主妇大概也是一种幸福(ゆうゆ最后一次出现在公众眼界应该是02年的富士台FNS歌謡祭的小猫再聚首)。

这场ゆうゆ单飞后的首次(可能也是唯一)演唱会,虽然仅仅是小猫解散后不到一年的88年1月24日,却已经和组合时期的画风完全不同了,当然这大多是单飞以及年龄增长导致的路线选择问题,倒也没什么奇怪的。不过我个人对这个搞怪的路线不是很感冒,可能更怀念那个唱『夏休みは終わらない』那个元气小不点吧。不过这场收录了我最喜欢的一首,4单的c/w『爪を噛んでた』的现场版,光是这个就值回票价了。我单独压了一份发了Y2B:

分割方法:

ffmpeg -i 006_edit.mkv -ss 00:00:00 -t 00:04:13.940 -c:v libx264 -preset fast -crf 18 -c:a flac cut.mkv

缩略图自己P的,用了meiryo字体+投影。

另外值得一提的是本场演唱会的举办地点是中野サンプラザ,即著名的偶像圣地。后来比较有名的应该是早安系长期固定在此演出,不过我第一次知道还是从CoCo的演唱会里。

后记

成文之时随便搜了下,果然(为什么我要说果然)在我搞完这一切之后的几个月内就有人在Y2B直接放了一段的完整版……好吧唯一可以自我安慰的是他那个有水印不是么(笑)。