使用 NDK、OpenGL ES 和 FFmpeg 的 Android 视频播放器

Android Video Player Using NDK, OpenGL ES, and FFmpeg

好的,这就是我目前所拥有的。我已经在 android 上构建了 FFmpeg,并且能够很好地使用它。从 java 端传递选择的文件名后,我已经能够将视频加载到 FFmpeg 中。为了节省性能,我在 NDK 中编写视频播放器,而不是通过 JNI 将帧从 FFmpeg 传递到 java。我想将视频中的帧发送到 OpenGL 表面。我无法弄清楚如何获取每一帧视频并将其渲染到 OpenGL 表面上。几个星期以来,我一直在试图解决这个问题,但没有运气。希望有人能指出我正确的方向。

谢谢!

相关讨论

  • 嗨 Kieran,我正在尝试使用 FFmpeg 和 android ndk 转换格式并播放音频或视频。我在网上找不到任何资源或指导。经过长时间的搜索,我找到了这个链接 github.com/havlenapetr/FFMpeg。但我无法编译和运行这个例子。请帮助我或给我参考链接 - 我如何在 android 中使用 FFmpeg 文件播放音频/视频....谢谢
  • Praveenb,我很难让 FFmpeg 最终在 Android 上编译和使用。我不得不玩弄一下配置脚本。我也没有使用最新版本的 FFmpeg。我下载了一个稍旧的版本,它仍然使用 sws_scale 函数来让它工作。我可以尽我所能帮助你让它工作,让我知道你现在在哪里,你遇到了什么类型的错误。构建静态库应该不难。
  • 嗨,我正在努力为 Android 构建 FFmpeg。您能告诉我您是如何设法为 Android 构建静态库的吗?是否有任何 git-repository 或类似的东西可以开始?那个配置脚本怎么样 - 有什么要设置的?

想到的一种方法是将帧的像素绘制到纹理中,然后使用 OpenGL 渲染该纹理。

不久前我写了一篇关于如何解决此问题的博文,主要针对基于像素的老式视频游戏,但它也适用于您的情况。帖子是 C 中的 Android Native Coding,我用一个例子建立了一个 github 存储库。使用这种技术,我已经能够获得 60 FPS,即使在第一代硬件上也是如此。

针对此方法编辑 glTexImage2D 与 glTexSubImage2D。

调用 glTexImage2D 将为您的纹理分配视频内存并将您传递给它的像素复制到该内存中(如果您不传递 NULL)。调用 glTexSubImage2D 将更新您在已分配纹理中指定的像素。

如果您更新所有纹理,那么调用其中一个或另一个几乎没有区别,实际上 glTexImage2D 通常更快。但是如果你只更新纹理的一部分,glTexSubImage2D 会在速度上胜出。

您必须使用 2 的幂次方纹理尺寸,因此在高分辨率设备上覆盖屏幕需要 1024x512 纹理,在中等分辨率下需要 512x512 纹理。纹理大于屏幕区域(高分辨率为 800x400-ish),这意味着您只需要更新它的一部分,因此 glTexSubImage2D 是要走的路。

相关讨论

  • 感谢您的答复!你知道这很有趣,我不久前浏览了你的博客,我用它作为我的应用程序的基础哈哈。直到现在我才再次找到它,所以谢谢你让我知道!现在我终于在屏幕上出现了一些东西,但像素似乎完全搞砸了。我不确定我是否正确创建了我的矩形纹理,或者在 FFmpeg 中转换为正确的 RGB 像素格式是否存在问题。我希望有更多的 OpenGL ES 文档,因为在 OpenGL 中使用四边形很容易做到这一点。有小费吗?
  • 您可以使用带有纹理的四边形。只需使用 glOrthof 并设置您的顶点和纹理坐标,就像在常规 OpenGL 中一样。混乱的像素是一个模糊的描述:它们是完全无法辨认的吗?太绿还是太红?也许他们被剪到左边?我的建议:使用与 GLES 重叠的 OpenGL 子集让代码在 PC 上运行,然后将完全相同的代码编译到 Android。它是我通常做的。
  • 好的,谢谢你的信息。抱歉,我所说的混乱像素的意思是,它们是无法辨认的。在 FFmpeg 中,您必须使用函数 sws_scale 将像素格式转换为 RGG,但至于 OpenGL 方面,我仍在学习如何使用它,我不太确定我是否转换为正确的像素格式,或者我是否设置了我的矩形顶点和纹理坐标正确。另外,由于我正在遍历每一帧,因此应该使用 glTexSubImage2d() 或继续使用 glTexImage2d() 用新帧中的新纹理数据替换当前纹理?
  • @Kieran:我添加了关于 tex 与 texsub 的注释。
  • 感谢richq,所有这些信息真的很有帮助。我一定会发回我最终做的事情,以防其他人需要一些帮助。
  • 我终于使用 FFmpeg 和 OpenGL ES 让视频帧显示在屏幕上......如果有人对我如何让它工作感兴趣,请告诉我,我会尽力提供帮助。它最终成为使用来自 FFmpeg 的正确像素格式转换并将其映射到 OpenGL 中正确的像素格式以及使用正确的纹理坐标的问题。但有一件事是,与 .mp4 解码相比,手机上的 .3gp 解码速度非常慢。在我原来的机器人上,我最多只能获得 ~11fps。虽然 droid x 产生了约 22fps 的结果……但仍在努力改进它。
  • @Kieran 很高兴看到你走得更远。我在我的博客文章中有一条评论说纹理缓冲区方法本身在某些手机(例如 Nexus One)上可能会很慢,可能也需要检查一下。
  • @Android007:我尝试使用本机 android 位图 api,它产生了相同的 fps,但我没有遇到任何黑帧问题......你确定你的循环通过数据包运行是绝对正确的吗?可能是您以某种方式尝试显示不应该使用的数据包部分?屏幕上显示的帧看起来是否正确,显示的帧之间的视频似乎有任何跳跃?请发回您想出的任何结果!
  • 我对崩溃的猜测很可能是您没有在本机端释放内存。请务必仔细查看循环中分配的所有内容,然后使用 FFmpegs av_free 函数释放该内存......堆栈跟踪是否提供有关崩溃来自哪一侧的任何见解?
  • @Kieran Id 对这个主题非常感兴趣,尤其是关于像素转换和 OpenGL 输出。您是否打算在某处发布一些源代码?我非常感谢,因为我无法理解所有细节——我只是习惯了一些 Android 编程,还没有接触过 ffmpeg 或 OpenGL。
  • @slhck 当然我可以发布一些示例。只要让我知道您需要什么帮助,我会尽力而为。一旦你弄清楚了这一切真的很简单,一开始很难让它全部工作。
  • @Kieran 那太棒了。我下周左右开始实施,也许我们可以私下谈一谈?
  • @Kieran 你真是太好了。我还是得看看我们是否真的需要那个功能,否则会浪费资源:)
  • 大家好!我问了一个关于 OpenGL 还是原生位图 API(或其他东西)是否最适合视频的问题。到目前为止,我有两个相当矛盾的答案。这就是为什么打开 100 点赏金,在 12 小时内关闭。你能看看吗?这是:stackoverflow.com/questions/5666513/
  • @Kieran 这正是我要问的问题!如我所见,您设法使其完全正常工作?你能提供一些例子吗?我给你发了邮件!希望它仍然是相同的地址:)
  • 嗨 DiscGolfer,您能否提供一些示例源代码,用于在 OPENGLES 上使用 FFMPEG 渲染视频帧 ....
  • 听起来很奇怪 glTexImage 比 glTexSubImage 快

以上是使用 NDK、OpenGL ES 和 FFmpeg 的 Android 视频播放器的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>