首页 文章

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

提问于
浏览
12

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

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

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

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

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

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

3 回答

  • 12

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

    Why openGL

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

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

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

    Why !openGL

    缺点是将纹理数据导入GPU的过程 . 考虑到每个帧你必须将纹理数据放入内存(CPU操作)然后你必须将这个纹理数据输入GPU(CPU操作) . 正是这种加载/复制使得使用openGL比使用open更慢 .

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

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

    Other Options

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

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

  • 3

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

    您可以尝试从FFmpeg项目移植ffplay.c,这是在使用SDL的Android端口之前完成的 . 这样你就不必处理 AudioTrack 的特性,这是Android独有的音频API .

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

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

  • 1

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

相关问题