【问题标题】:Is 'Android+FFMpeg' friendship really available?'Android+FFMpeg' 友谊真的可用吗?
【发布时间】:2011-08-29 16:17:48
【问题描述】:

这个问题并不意味着我对 ffmpeg 代码是否可以在 Andoid 上使用感兴趣。我知道它可以。我只是在问是否有人在这些东西上取得了真正的性能进步。

在对这些东西进行了几周的实验后,我提出了这个问题,我已经受够了。

我不想写信给人们甚至不说他们解码什么样的视频(分辨率,编解码器)并且只谈论一些神秘的 FPS 的分支。我只是不明白他们想做什么。此外,我不会仅为我的手机或具有一些扩展 OpenGL 功能的 Android 2.2++ 手机开发应用程序。我有一个很受欢迎的手机 HTC Desire,所以如果应用程序无法在它上面运行,那么下一步是什么?

好吧,我有什么?

  1. 来自最新 HEAD 分支的 FFMpeg 源代码。其实我用NDK5也造不出来,所以我决定用偷来的。

  2. Bambuser 的构建脚本 (bash) 带有适当的 ffmpeg 源代码 ([web]: http://bambuser.com/r/opensource/ffmpeg-4f7d2fe-android-2011-03-07.tar.gz)。 使用 NDK5 进行一些修正后,它构建良好。

  3. 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
  • 解码和渲染在不同的线程中
  1. Bambuser(用于 armv5te 的 NDK5 构建,RGBA8888):平均 33 毫秒/帧。
  2. Rockplayer(NDK3 为霓虹灯构建,RGB565):平均 27 毫秒/帧。

乍一看还不错,只是觉得这些只是解码帧的结果。

如果有人在解码时间上有更好的结果,请告诉我。

视频最难的是渲染。如果我们有 600x360 的位图,我们应该在绘画之前以某种方式缩放一张,因为不同的手机有不同的屏幕尺寸,我们不能指望我们的视频会和屏幕一样大。

我们必须通过哪些选项来重新调整框架以使其适合屏幕? 我能够检查(相同的电话和视频源)这些案例:

  1. sws_scale() Bambuser 构建中的 C 函数:70 毫秒/帧。不可接受。
  2. Android 中愚蠢的位图重新缩放 (Bitmap.createScaledBitmap):65 毫秒/帧。不可接受。
  3. 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 也是重复加载纹理数据的常用函数。

标签: android video ffmpeg


【解决方案1】:

我确实在 android 上编译了 ffmpeg。从这一点来看 - 播放视频纯粹依赖于实现,因此没有必要测量延迟可以在需要的地方进行高度优化而不使用标准 swscale。是的 - 您可以构建一些简单的 JNI 桥并在 NDK 中使用它来执行 ffmpeg 调用,但这已经是播放器代码了。

【讨论】:

    【解决方案2】:

    根据我的经验,YUV 到 RGB 的转换一直是一个瓶颈。因此,using an OpenGL shader 被证明是一个显着的提升。

    【讨论】:

    • Alex Cohn,我现在使用 OpenGL 渲染方法,但性能仍然很差。在这种情况下,我仍然需要使用 sws_scale 来准备纹理。
    • 为什么需要 sws_scale?
    • Alex,我需要 sws_scale 来准备一个 wigth 和 height 是 2 次方的倍数的纹理。尝试按照您的建议使用着色器,但出现错误说我的 Adreno 不支持着色器.这很奇怪,但我还没有解决方案。
    • 人们 do complain 关于 Adreno 着色器。但并不是说着色器在那里无法使用,而且我自己也没有这样的设备来验证这些问题。无论如何,即使您的纹理必须设置为 2 的幂,您也不需要填充整个 1024x512 纹理;如果只设置 600x360 矩形,也可以显示这个矩形。请注意,OpenGL 或 Surface 会将输出缩放到没有sws_scale 的屏幕尺寸。
    【解决方案3】:

    我在我的项目中使用http://writingminds.github.io/ffmpeg-android-java/。有一些复杂命令的解决方法,但对于简单的命令,包装器对我来说效果很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-01
      • 2023-03-14
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-28
      相关资源
      最近更新 更多