【问题标题】:What is the best method to render video frames?渲染视频帧的最佳方法是什么?
【发布时间】:2011-08-05 17:00:24
【问题描述】:

渲染从捆绑到我的应用程序(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 编解码器。

【问题讨论】:

  • 有这方面的消息吗?我需要在 OpenGL 四边形中播放视频 - 即将视频逐帧转换为 OpenGL 纹理。我必须采用 FFmpeg 方式还是有更简单的解决方案?
  • @j00hi:这是题外话,问题不是“如何用 OpenGL 播放视频”。请搜索/提出另一个问题。
  • 距离上次活动已经快10年了。有没有办法重新打开这个问题?

标签: android video android-ndk


【解决方案1】:

我之前走过FFmpeg/OpenGLES的路子,玩的不是很开心。

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

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

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

【讨论】:

  • 感谢您的回答。我实际上对 AudioTrack 和 NDK 很满意。我有一个流行的应用程序,它广泛使用这些,有很多本机代码和音频优化。构建和使用 FFmpeg 库也可以,我不怕。我的问题真的是关于视频帧显示。考虑到所有纹理,OpenGL 是实现最佳 FPS 的方法吗? RGB565 默认的 OpenGL 格式呢?这种像素格式的视频看起来不错吗?
  • 向您致敬,先生! AudioTrack 与 NDK 结合起来让我非常适合。我使用了 RGB565,我没有注意到视频质量的差异。和以前一样,在我的使用中,解码本身往往会降低帧率,帧率从未低于 ~24 fps。
  • 好的,是的,我实际上已经在 OpenGL RGB565 中将非常大的 JPEG 图像渲染为纹理,看起来还不错,但我的印象是使用 RGB888 会更好(参见 my other question) ,因此是考虑 jnigraphics 的原因。我还不确定,但我对 OpenGL 很熟悉,所以我想我会走那条路,除非有人提出更好的主意。
  • 哦,顺便说一句,我已经改写了这个问题,将重点放在帧渲染方面。解码器方面是边缘的。很抱歉造成混乱。
【解决方案2】:

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

【讨论】:

  • 感谢 Greg 提供这些信息。通过“本机支持的位图”,我假设您正在谈论 NDK 公开的 jnigraphics 库。在本机代码中更改像素后,您是否需要在 Java 中刷新/重绘位图/视图?您是否在许多设备上对此进行了测试?跨设备的帧率是否一致?
  • Greg,对于想要从手机流式传输实时视频的人,您能推荐一本书、开源项目或教程吗?很抱歉在评论中提出新问题,但我想引起您的注意。谢谢。
  • @Greg:你能补充一些细节吗?我为这个问题开了一个赏金,因为只有两个答案,而且它们与 OpenGL 相矛盾。你能再具体一点吗?例如,您是否尝试过使用 glTexSubImage2D() 而不是 glTexImage2D() 来防止您提到的 OpenGL 缓存问题?
  • @Greg:你说你可以使用这种技术播放 720p 视频?您使用的是软件视频解码器吗?我已经为 iPhone 采用了这种方法,并且 sw 解决方案 (ffmpeg) 在 320p 视频分辨率下(在 iPhone 2 上可能是 480p)停止可靠地工作。在 iPhone 上,我切换到 AV Foundation。我希望为 android 做同样的事情,但他们似乎没有一个好的视频编辑框架(还)
【解决方案3】:

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

为什么选择 openGL

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

例如将 YV12 视频帧转换为 RGB。 YV12 -> RGB 等色彩空间转换要求您单独计算每个像素的值。想象一下,对于 1280 x 720 像素的帧,这最终需要多少操作。

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

为什么是 !openGL

缺点是将纹理数据输入 GPU 的过程。考虑到对于每一帧,您必须将纹理数据加载到内存中(CPU 操作),然后您必须将该纹理数据复制到 GPU 中(CPU 操作)。正是这种加载/复制可以使使用 openGL 的速度比其他方法慢。

如果您播放的是低分辨率视频,那么我想您可能看不到速度差异,因为您的 CPU 不会出现瓶颈。但是,如果您尝试使用高清,您很可能会遇到这个瓶颈并注意到性能受到显着影响。

解决这个瓶颈的传统方法是使用Pixel Buffer Objects(分配 GPU 内存来存储纹理加载)。不幸的是 GLES2 没有像素缓冲区对象。

其他选项

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 2020-02-06
    • 2021-10-28
    • 1970-01-01
    • 2014-05-21
    • 1970-01-01
    • 2021-07-13
    相关资源
    最近更新 更多