作者:quink
来源:Fun With FFmpeg
链接:https://mp.weixin.qq.com/s/xzKF0k7V3mh1bnB-Vduzng
一、透明视频的应用场景和现有方案
复杂的特效动画往往使用透明视频来实现。在AI火爆之后,透明视频又有了一个业务场景:数字人。透明视频有多种实现方式:
- mp4格式支持PNG图片编码,所以最简单的方案是在mp4里放PNG图片;
- webm/mkv格式VP9编码,数字人用的比较多。和PNG相比,VP9编码大大提升了压缩效率;
- H.264、H.265视频编码,图像上下或左右分成两半,一半是普通YUV内容,一半的Y plane用来保存alpha信息,解码后处理时把YUV转成RGBA。和VP9相比,编解码器可选的更多,支持更好。缺点是后处理麻烦,要小心对半处理碰上硬件解码crop切边问题,处理不好可能中心找偏了。
二、Alpha HEVC透明视频标准原理
其实H.265标准本身支持透明视频编码,描述在Annex F:Common specifications for multi-layer extensions. H.265 nalu header设计时考虑了扩展性:
nal_unit_header( ) {
forbidden_zero_bit f(1)
nal_unit_type u(6)
nuh_layer_id u(6)
nuh_temporal_id_plus1 u(3)
}
nuh_temporal_id_plus1标记了时域分层信息,时域分层SVC编码在流媒体直播业务中大量使用。而nuh_layer_id用的就很少了,大家可能忽略了它的价值。MV-HEVC和Alpha HEVC都依赖nuh_layer_id。
和MV-HEVC相比,Alpha HEVC的实现很简单:
- 用nuh_layer_id = x编码base层(x一般是0),也就是普通的YUV内容,
- 用nuh_layer_id = y编码alpha层(y一般是1),alpha层也是按照YUV三个plane去编码的,Y plane是alpha信息,UV plane忽略
- alpha层和base层具有相同的编码参考结构,相同的POC,alpha层的视频帧和base层同时解码输出,输出时可以简单操作,由两个YUV组合成一个YUVA
- base层和alpha层有各自的SPS/PPS,所以至少有两个SPS和PPS,如图所示
![FFmpeg H.265透明视频解码](https://www.nxrte.com/wp-content/themes/justnews/themer/assets/images/lazy.png)
MV-HEVC有跨层的参考,Alpha HEVC没有跨层参考,实际上可以单读解码base层和alpha层,如下图所示:
![FFmpeg H.265透明视频解码](https://www.nxrte.com/wp-content/themes/justnews/themer/assets/images/lazy.png)
可以看到图中相邻两帧POC相同,前一个是base层,后一个是alpha层。
Alpha HEVC的基本原理讲完了,它还有两个辅助工具:
- VPS扩展部分,描述了是否包含alpha扩展,各层之间的关系。这里不得不吐槽,VPS extension是典型的overengineering,为了节省几个bit,做出了类似C语言的指针的指针的指针的指针的指针的指针的设计,能够支持N多层的编码。实际上,知道是透明视频,忽略VPS extension照样解码。Apple发布的Alpha HEVC的样片,就搞错了VPS extension。
- SEI里标记alpha视频信息。和VPS extension相比,SEI alpha_channel_info还算简单。
三、FFmpeg支持Alpha HEVC透明视频解码
虽然H.265标准支持透明视频,真正让Alpha HEVC落地的是Apple。Apple在WWDC19时推出了它们的方案,也就是在videotoolbox硬件编解码上实现了Alpha HEVC。
FFmpeg支持用videotoolbox编码Alpha HEVC:
./ffmpeg -i bunny.mp4 -i basketball.mp4 \
-filter_complex '[1:v][0:v]alphamerge,format=bgra[vout]’ \
-c:v hevc_videotoolbox \
-pix_fmt bgra \
-alpha_quality 0.5 \
-map '[vout]' -tag:v hvc1 alpha.mp4
但因为集成方式问题,FFmpeg不支持videotoolbox解码Alpha HEVC视频,也不支持纯软件解码Alpha HEVC。
自从Anton给FFmpeg加了MV-HEVC解码支持之后,我就在考虑Alpha HEVC的解码。
Alpha HEVC解码最麻烦的处理是解析VPS extension,我硬着头皮糊了一个,能够
- 正常解析Apple videotoolbox编码的Alpha HEVC
- 也支持x265编码的Alpha HEVC,虽然x265的VPS extension不太标准
- 不支持Apple 2019年放出来的样片,前面说了,Apple弄错了VPS extension
- Nvidia nvenc说是支持Alpha HEVC,但是编码输出的VPS/SPS/PPS是乱套的,大概也不支持
剩下的解码部分基本可以复用MV-HEVC的工作。但有个很大的差异,MV-HEVC是输出两个frame的,左眼和右眼。对于Alpha HEVC来说,单独输出base层的YUV和alpha层的YUV,对用户不友好,FFmpeg自己的工具也不好处理这种两个frame,所以应当输出YUVA。我做了一个取巧的设计,让alpha层AVFrame的data[0]指向base层AVFrame的data[3],解码到alpha层AVFrame的Y,也就解码输出到base层的YUVA的A plane。
FFmpeg命令行解码Alpha HEVC,单独查看alpha plane:
./ffmpeg -i ~/Movies/alpha.mp4 -an \
-vf extractplanes=planes=a \
-c:v rawvideo -f nut - |ffplay -
如下图所示:
![FFmpeg H.265透明视频解码](https://www.nxrte.com/wp-content/themes/justnews/themer/assets/images/lazy.png)
单独提取Y plane,如下图所示:
![FFmpeg H.265透明视频解码](https://www.nxrte.com/wp-content/themes/justnews/themer/assets/images/lazy.png)
四、展望
H.265相比VP9(至少在国内)生态上成熟很多。Alpha HEVC有Apple硬件编解码的支持,有x265软件编码的支持,现在又有了FFmpeg软件解码的支持,后续加上硬件解码不成问题。万事俱备,只差一个产品经理了:怎么把Alpha HEVC用起来。
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。