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

oli*_*erg 12 video android android-ndk

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

我自然倾向于选择使用NDK,OpenGL ES和FFmpeg的Android视频播放器中提到的OpenGL.

但在用于视频显示的Android中的OpenGL中,评论指出OpenGL不是渲染视频的最佳方法.

然后怎样呢?jnigraphics本地图书馆?还有非GL SurfaceView?

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

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

Err*_*454 12

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

为什么选择openGL

当人们想到使用openGL渲染视频时,大多数人都试图利用GPU进行色彩空间转换和alpha混合.

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

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

为什么!openGL

缺点是将纹理数据导入GPU的过程.考虑对于每个帧,您必须将纹理数据加载到内存中(CPU操作),然后您必须将此纹理数据复制到GPU(CPU操作).正是这种加载/复制可以使用openGL比替代品慢.

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

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

其他选择

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

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


Mat*_*lis 3

我以前也走过 FFmpeg/OpenGLES 这条路,但并不是很有趣。

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

无论如何,尽可能少地进行 NDK 开发并依赖移植是一个好主意,因为在我看来,现在 ndk-gdb 调试体验非常糟糕。

话虽这么说,我认为 OpenGLES 性能是您最不需要担心的。我发现性能很好,尽管我承认我只在少数设备上进行了测试。解码本身相当密集,并且在播放视频时我无法(从 SD 卡)进行非常积极的缓冲。