在游戏引擎中播放视频
美术同学给我们的游戏做了段片头视频,正要加到产品中去时,才发现我们的引擎居然没有提供视频播放的功能。我想这个东西开源库一大堆,那做起来还不是小菜一碟。可没想到还是折腾了一整天才搞定。
第一件事是考察 License 。结果用的人做多的 ffmpeg 是 GPL 的,不适合我这种商业应用。虽然有一部分功能可以以 LGPL 的方式使用,但是遵守起来也是麻烦一大堆。想了一下还是做罢。我可不想学暴风影音和 QQ Player 那样上耻辱榜。
最终考察结果,居然没太多的选择。还是 google 的 vp8 最好。License 最为宽松,所以就去下载了一份 libvpx 的最新版试用。
README 有点老旧,里面说在 Windows 下编译必须 cygwin ,我很听话的在 cygwin 下 build 了一份出来。反正就是个 libvpx.a ,打算复制到 Mingw 里去用。可在 Mingw 里链接却出了问题,缺少 pthread 库。mingw32 是不带这个库的,虽然在网上找了一份 pthread-win32 ,但是看了几眼,被那一大坨 dll 吓怕了,犹豫了一下还是没继续尝试。
重新回头研究了一下 libvpx 的 source ,发现它并不一定要使用 pthread 的 api ,貌似在 windows 下还可以使用 win32 原生 api ,看起来是为 vs 编译准备的。我估摸着 mingw 也能搞定,接着装了份 msys 试了一下,果然 ok。
现在写个玩具播放器还需要一个以 vp8 格式压缩的数据文件。看了一下, libvpx 里带了 ivfenc 。输入是 yuv 格式,输出是 ivf 格式。而 libvpx 主页上没看到 api 文档,只好去读它自带的 simple decode 的代码。看了一眼发现很好理解,用起来还是很简单的。只是这个测试用的 ivf 文件怎么生成略有头痛。
yuv 格式似乎是一种不压缩的 YUV 色彩空间的位图序列。ffmpeg 可以生成。又下了一份 ffmpeg 编译出来,把美术交过来的视频编码成了 .yuv 文件。然后在用 ivfenc 转换成了 .ivf 。
本来想播放一下转换的成果看看先。google 了一下,没有什么现成的软件可以播放之。无奈之下,只好闷头先写播放程序。写出来后怎么都不对,非常郁闷。
开始怀疑是不是 .ivf 压缩错了。好在我曾经有过 jpeg 的编解码经验,对这块有点感觉。猜测到可能是 yuv 文件不对。想了一下,原来 .yuv 文件应该只是一个纯粹的数据流,里面没有任何格式信息。比如视频的帧率,视频的尺寸等等。所以网上很难找到所谓 .yuv 的播放器。而且 ivfenc 在压缩时也必须在命令行指定视频的大小。因为 .yuv 的输入流里根本就没这个信息。一开始还想当然的以为 ivfenc 会根据命令行指定尺寸对数据源做缩放,后来手工计算了一下视频应该有的帧数和实际压缩后帧数严重不符,才发现问题。
同理,.ivf 也仅仅是一图象压缩流。并非完整的视频文件。所以也没有所谓 ivf 的 codec 了。完整的视频文件格式还需要额外的描述信息以及音频流数据等。
明白了这些就知道该怎么做了。用 ffmpeg 输入 .yuv 数据时,可以加上 -f yuv4mpegpipe 生成指定的 yuv 信息,并且指定 -pix_fmts
为 yuv420p ,这个是 ivfenc 认的 yuv 格式。(yuv 有多种组合方式,在 jpeg 的压缩中也是如此)。之后,使用 ivfenc 时指定正确的宽高,就能生成有效的 ivf 文件了。
播放视频的时候通常需要把像素数据从 YUV 转到 RGB 。这个程序我十年前用 MMX 优化过,今天再翻出来用用即可。C 的优化版本也还凑合。今天还 google 到一篇 paper 专门谈这个优化的。有兴趣的同学可以参考一下。
不过在 3d engine 里还有更好的方法:就是利用 GPU 。只需要为 YUV 各创建一张单通道帖图,然后在 ps 里做转换即可。之所以不用一张三通道帖图干这事,是因为默认的 ivf 展开的数据,YUV 是 4:1:1 储存的。
当然单纯播放视频的话,也可以用 YUV 格式的覆盖表面来做。在 DirectX 里容易实现,我还不清楚 OpenGL 里该怎么干。
今天一开始有同学建议我嵌一个媒体播放器或是 Flash player 的控件在 Engine 中。我很不愿意考虑这种方案。不解释了。其实用开源库的方法,实际消耗的人力也没有预想的大。
Comments
Posted by: Anonymous | (26) June 30, 2016 12:19 PM
Posted by: 福利工口姬 | (25) April 16, 2014 03:55 PM
Posted by: 学子正装网 | (24) November 18, 2010 11:18 PM
Posted by: 不孕不育的原因 | (23) October 25, 2010 10:44 AM
Posted by: mzm9 | (22) September 18, 2010 10:49 AM
Posted by: Tony Huang | (21) September 17, 2010 06:24 PM
Posted by: so | (20) September 11, 2010 06:57 PM
Posted by: mike | (19) September 9, 2010 05:11 PM
Posted by: trueice | (18) September 8, 2010 03:59 PM
Posted by: trueice | (17) September 8, 2010 03:56 PM
Posted by: 佛挡杀佛是地方 | (16) September 5, 2010 07:31 PM
Posted by: mm | (15) September 1, 2010 07:31 PM
Posted by: godness | (14) September 1, 2010 12:49 PM
Posted by: godness | (13) September 1, 2010 12:48 PM
Posted by: lichking | (12) August 31, 2010 10:32 PM
Posted by: gld | (11) August 31, 2010 09:17 PM
Posted by: GPL | (10) August 31, 2010 09:15 PM
Posted by: 螺旋板换热器 | (9) August 31, 2010 04:16 PM
Posted by: black | (8) August 31, 2010 02:41 PM
Posted by: Dreampuf | (7) August 31, 2010 02:38 PM
Posted by: plainroc | (6) August 31, 2010 01:00 PM
Posted by: 笨笨猪 | (5) August 31, 2010 12:49 PM
Posted by: dwing | (4) August 31, 2010 10:52 AM
Posted by: Kevin Lynx | (3) August 31, 2010 10:42 AM
Posted by: hacker47 | (2) August 31, 2010 09:02 AM
Posted by: rexzhou | (1) August 31, 2010 08:55 AM