渲染视频帧的最佳方法是什么?

时间:2011-04-14 16:35:32

标签: android video android-ndk

从捆绑到我的应用程序(FFmpeg等)的解码器中渲染视频帧的最佳选择是什么?

我自然倾向于选择 Android Video Player Using NDK, OpenGL ES, and FFmpeg 中提到的OpenGL。

但是在 OpenGL in Android for video display 中,评论指出OpenGL不是渲染视频的最佳方法。

然后呢? jnigraphics本地图书馆?还有一个非GL SurfaceView?

请注意,我想使用本机API来渲染帧,例如OpenGL或jnigraphics。但是用于设置SurfaceView等的Java代码是可以的。

PS:MediaPlayer在这里无关紧要,我正在谈论自己解码和显示帧。我不能依赖默认的Android编解码器。

3 个答案:

答案 0 :(得分:12)

我将根据自己的经验尝试详细阐述和巩固答案。

为什么选择openGL

当人们想到用openGL渲染视频时,大多数正在尝试利用GPU进行色彩空间转换和alpha混合。

例如,将YV12视频帧转换为RGB。颜色空间转换,如YV12 - > RGB要求您单独计算每个像素的值。设想一个1280 x 720像素的帧,最终会有多少次操作。

我刚刚描述的是SIMD的用途 - 对多个数据并行执行相同的操作。 GPU非常适合色彩空间转换。

为什么!openGL

缺点是将纹理数据导入GPU的过程。考虑到对于每个帧,您必须纹理数据加载到内存中(CPU操作),然后您必须此纹理数据复制到GPU(CPU操作)。 使用openGL进行加载/复制比使用openGL更慢。

如果您正在播放低分辨率视频,那么我认为您可能无法看到速度差异,因为您的CPU不会出现瓶颈。但是,如果你尝试使用HD,你很可能会遇到这个瓶颈,并注意到性能的显着提升。

传统上解决这个瓶颈的方法是使用Pixel Buffer Objects(分配GPU内存来存储纹理载荷)。不幸的是,GLES2没有Pixel Buffer Objects。

其他选项

由于上述原因,许多人选择使用软件解码与可用的CPU扩展相结合,如NEON进行色彩空间转换。用于NEON的YUV 2 RGB的实现存在here。绘制帧的方法,SDL与openGL对于RGB无关紧要,因为在这两种情况下你都要复制相同数量的像素。

您可以通过从adb shell运行cat /proc/cpuinfo并在功能输出中查找NEON来确定目标设备是否支持NEON增强功能。

答案 1 :(得分:3)

之前我已经走过FFmpeg / OpenGLES路径了,这不是很有趣。

您可以尝试从FFmpeg项目移植ffplay.c,这是在使用SDL的Android端口之前完成的。这样你就不会从头开始构建解码器,而且你不必处理AudioTrack的特性,这是Android独有的音频API。

在任何情况下,最好尽可能少地进行NDK开发并依赖移植,因为在我看来,ndk-gdb调试经验现在非常糟糕。

话虽如此,我认为OpenGLES的表现是您最不担心的。我发现性能很好,虽然我承认我只在少数设备上测试过。解码本身相当密集,在播放视频时我无法进行非常积极的缓冲(来自SD卡)。

答案 2 :(得分:1)

实际上我已经部署了一个自定义视频播放器系统,几乎所有的工作都是在NDK方面完成的。我们正在获得全帧视频720P及以上,包括我们的定制DRM系统。 OpenGL不是你的答案,因为在Android上不支持Pixbuffers,所以你每帧都会对你的纹理进行基本爆破,这会搞砸OpenGLESs缓存系统。坦率地说,你需要通过Froyo及以上版本的Native支持的位图来推送视频帧。之前Froyo你的软管。我还写了很多NEON内在函数用于颜色转换,重新缩放等,以提高吞吐量。我可以在HD Video上通过这个模型推出50-60帧。