【发布时间】:2011-08-29 16:17:48
【问题描述】:
这个问题并不意味着我对 ffmpeg 代码是否可以在 Andoid 上使用感兴趣。我知道它可以。我只是在问是否有人在这些东西上取得了真正的性能进步。
在对这些东西进行了几周的实验后,我提出了这个问题,我已经受够了。
我不想写信给人们甚至不说他们解码什么样的视频(分辨率,编解码器)并且只谈论一些神秘的 FPS 的分支。我只是不明白他们想做什么。此外,我不会仅为我的手机或具有一些扩展 OpenGL 功能的 Android 2.2++ 手机开发应用程序。我有一个很受欢迎的手机 HTC Desire,所以如果应用程序无法在它上面运行,那么下一步是什么?
好吧,我有什么?
-
来自最新 HEAD 分支的 FFMpeg 源代码。其实我用NDK5也造不出来,所以我决定用偷来的。
-
Bambuser 的构建脚本 (bash) 带有适当的 ffmpeg 源代码 ([web]: http://bambuser.com/r/opensource/ffmpeg-4f7d2fe-android-2011-03-07.tar.gz)。 使用 NDK5 进行一些修正后,它构建良好。
-
Rockplayer 的凝胶化 ffmpeg 源代码,具有巨大的 Android.mk 构建脚本容量([web]:http://www.rockplayer.com/download/rockplayer_ffmpeg_git_20100418.zip)。
经过一些修正,它由 NDK3 和 NDK5 构建。 Rockplayer 可能是 Android 上最酷的媒体播放器,我认为使用它的构建我会有一些好处。
我有适合项目的视频(不大也不小):600x360 H.264。
我们从第 2 条和第 3 条中获得的两个库都为我们提供了从视频中获取帧的可能性(逐帧、搜索等)。我没有尝试获取音轨,因为该项目不需要音轨。我不会在这里发布我的源代码,因为我认为这是传统的而且很容易找到。
那么,视频的结果如何?
- HTC Desire,Android 2.2
- 600x360,H.264
- 解码和渲染在不同的线程中
- Bambuser(用于 armv5te 的 NDK5 构建,RGBA8888):平均 33 毫秒/帧。
- Rockplayer(NDK3 为霓虹灯构建,RGB565):平均 27 毫秒/帧。
乍一看还不错,只是觉得这些只是解码帧的结果。
如果有人在解码时间上有更好的结果,请告诉我。
视频最难的是渲染。如果我们有 600x360 的位图,我们应该在绘画之前以某种方式缩放一张,因为不同的手机有不同的屏幕尺寸,我们不能指望我们的视频会和屏幕一样大。
我们必须通过哪些选项来重新调整框架以使其适合屏幕? 我能够检查(相同的电话和视频源)这些案例:
- sws_scale() Bambuser 构建中的 C 函数:70 毫秒/帧。不可接受。
- Android 中愚蠢的位图重新缩放 (Bitmap.createScaledBitmap):65 毫秒/帧。不可接受。
- OpenGL 渲染在纹理四边形的正交投影中。在这种情况下,我不需要缩放框架。我只需要准备包含帧像素的纹理 1024x512(在我的情况下是 RGBA8888),然后将其加载到 GPU(gl.glTexImage2D)中。结果:~220 毫秒/帧渲染。不可接受。没想到 glTexImage2D 就在 Snapdragon CPU 上吃亏了。
就是这样。我知道有一些方法可以使用片段着色器通过 GPU 转换 YUV 像素,但我们将使用相同的 glTexImage2D 和 200 毫秒来加载纹理。
但这不是结束。 ...我唯一的朋友结束... :) 这不是一个绝望的情况。
尝试使用 RockPlayer,您肯定会想知道他们是如何快速进行该死的帧缩放的。我想他们在 ARM 架构方面有很好的经验。他们很可能使用 avcodec_decode_video2 而不是 img_convert(就像我在 RP 版本中所做的那样),但随后他们使用了一些技巧(取决于 ARM 版本)进行缩放。
也许他们也有一些“神奇”的 buld 配置用于 ffmpeg 减少解码时间,但他们发布的 Android.mk 不是他们使用的 Android.mk。我不知道。
所以,现在看来,您不仅可以为 ffmpeg 构建一些简单的 JNI 桥,还可以为 Android 平台提供真正的媒体播放器。只有当您拥有不需要缩放的合适视频时,您才能执行此操作。
有什么想法吗?
【问题讨论】:
-
我认为你应该再试一次 OpenGL。大多数设备没有专用的视频内存,因此传递图像应该非常快。检查纹理格式设置以避免位图数据转换很重要。 glTexSubImage 也是重复加载纹理数据的常用函数。