从捆绑到我的应用程序(FFmpeg等)的解码器中获取视频帧的最佳选择是什么?
我自然倾向于选择OpenGL,如上所述 Android视频播放器使用NDK,OpenGL ES和FFmpeg。
但在 Android中的OpenGL用于视频显示,评论指出OpenGL不是渲染视频的最佳方法。
然后怎样呢? jnigraphics本地图书馆?还有非GL SurfaceView?
请注意,我想使用本机API来渲染帧,例如OpenGL或jnigraphics。但是用于设置SurfaceView等的Java代码是可以的。
PS:MediaPlayer在这里无关紧要,我正在谈论自己解码和显示帧。我不能依赖默认的Android编解码器。
我将根据自己的经验尝试详细阐述和巩固答案。
为何选择openGL
当人们想到用openGL渲染视频时, 最 正试图利用GPU进行色彩空间转换和alpha混合。
例如,将YV12视频帧转换为RGB。像YV12 - > RGB这样的颜色空间转换要求您单独计算每个像素的值。设想一个1280 x 720像素的帧,最终会有多少操作。
我刚刚描述的是SIMD的用途 - 对多个数据并行执行相同的操作。 GPU非常适合色彩空间转换。
为什么!openGL
缺点是将纹理数据导入GPU的过程。考虑到你需要的每一帧 加载 纹理数据进入内存(CPU操作),然后你必须 复制 这种纹理数据进入GPU(CPU操作)。就是这个加载/复制 能够 使用openGL比使用替代品更慢。
如果您正在播放低分辨率视频,那么我认为您可能无法看到速度差异,因为您的CPU不会出现瓶颈。但是,如果你尝试使用HD,你很可能会遇到这个瓶颈,并注意到性能的显着提升。
传统上解决这个瓶颈的方法是使用 像素缓冲对象 (分配GPU内存来存储纹理载荷)。不幸的是,GLES2没有Pixel Buffer Objects。
其他选择
由于上述原因,许多人选择使用软件解码与可用的CPU扩展相结合,如NEON进行色彩空间转换。存在用于NEON的YUV 2 RGB的实现 这里。绘制帧的方法,SDL与openGL对于RGB无关紧要,因为在两种情况下都要复制相同数量的像素。
您可以通过运行确定目标设备是否支持NEON增强功能 cat /proc/cpuinfo
来自adb shell并在功能输出中查找NEON。
我之前已经走过FFmpeg / OpenGLES路径了,这并不是很有趣。
您可以尝试从FFmpeg项目移植ffplay.c,这是在使用SDL的Android端口之前完成的。这样你就不会从头开始构建你的解码器,你也不必处理它的特性 AudioTrack
,这是Android独有的音频API。
在任何情况下,最好尽可能少地进行NDK开发并依赖移植,因为在我看来,ndk-gdb调试体验现在非常糟糕。
话虽如此,我认为OpenGLES的性能是您最不担心的。我发现性能很好,虽然我承认我只在少数设备上测试过。解码本身相当密集,我在播放视频时无法进行非常积极的缓冲(来自SD卡)。
实际上我已经部署了一个自定义视频播放器系统,几乎所有的工作都是在NDK方面完成的。我们正在获得全帧视频720P及以上,包括我们的定制DRM系统。 OpenGL不是你的答案,因为在Android上不支持Pixbuffers,因此你每个帧都会对你的纹理进行基本爆破,这会搞砸OpenGLESs缓存系统。坦率地说,你需要通过Froyo及以上版本的Native支持的位图来推送视频帧。之前Froyo你的软管。我还写了很多NEON内在函数用于颜色转换,重新缩放等,以提高吞吐量。我可以在高清视频上通过这个模型推出50-60帧。