如何使用 NDK 有效地放大视频帧
Posted
技术标签:
【中文标题】如何使用 NDK 有效地放大视频帧【英文标题】:How to efficiently scale up video frame using NDK 【发布时间】:2014-08-05 11:50:38 【问题描述】:我正在做一个关于处理视频帧的 android 项目,我需要在显示之前处理每一帧。该过程包括将帧从1920x1080放大到2560x1440分辨率,色彩空间转换以及一些必要的基于RGB的图像处理,所有这些工作都应该在33ms~40ms内完成。
我已经用 arm neon 优化了 yuv->rgb 和其他处理,它们运行良好。但我必须先将帧从 1080p 放大到 2k 分辨率,这是现在的性能瓶颈。
我的问题是如何在 20 毫秒内有效地将图像从 1080p 放大到 2k 分辨率,我对缩放算法没有太多经验,所以任何建议都是有帮助的。 可以用arm neon来优化现有算法吗?
硬件环境:
CPU:三星 Exynos 5420 内存:3GB 显示:2560X1600 像素更新:
我将描述我的解码过程,我使用MediaCodec将普通视频(H.264)解码为YUV(NV12),默认解码器是硬件,非常快。然后我用arm neon将NV12转为RGBW,然后将RGBW帧发送到surfaceflinger显示。我只是使用普通的 SurfaceView,而不是 GLSurfaceView。
瓶颈在于如何将 YUV 从 1080p 快速扩展到 2K。
【问题讨论】:
为什么需要扩大规模? @AlexCohn 是要求,我需要处理surfaceflinger无法识别的特殊RGB类型(Pentile RGBW),所以我需要先放大帧,处理每个像素2560x1600,然后张贴帧显示。如果我让surfaceflinger 放大,它会丢失一些信息。你对这个问题有什么想法吗? 我相信硬件颜色转换器/缩放器会比 CPU 更快地完成这项工作。 也许你可以使用OpenGL? 您熟悉 OpenGL 和着色器编程吗?对于并行 GPU 硬件来说,这听起来确实是个不错的问题。如果你想走这条路,请告诉我,因为这听起来很有趣。 【参考方案1】:我发现示例运行良好,所以请允许我带领这个示例程序使用 OpenGL 着色器从 YUV -> RGB 进行转换:http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c
我对您的程序的设想是:
-
硬件视频解码 H.264 流 -> YUV 数组
将该 YUV 数组作为 纹理 上传到 OpenGL;实际上,您将上传 3 种不同的纹理——Y、U 和 V
运行片段着色器,将这些 Y、U 和 V 纹理转换为 RGB(W) 图像;这将在显存中产生一个新的纹理
针对上一步生成的纹理运行新的片段着色器以缩放图像
这里可能涉及一些学习曲线,但鉴于您的问题描述,我认为它是可行的。一步一步来:准备好 OpenGL 框架,尝试只上传 Y 纹理并编写一个简单的片段着色器,它只根据 Y 样本发出一个灰度像素,然后继续正确转换图像,然后得到一个真的很幼稚的上采样器工作,然后将更复杂的上采样器投入使用。
【讨论】:
【参考方案2】:我也推荐opengl es,主要是因为我目前正在做的项目,也播放视频。对我来说,显示器是 1920 x 1080,所以我使用的纹理是 2048 x 1024。我在四核 arm7 上获得大约 35 fps。
使用 GLSurfaceView 和您自己的自定义渲染器。如果您使用的是 ffmpeg,那么一旦您解码了视频帧,请使用 sws_scale 缩放您的帧,然后将其上传到 opengl 纹理中。纹理/显示越大,获得的 fps 越低,因为每帧将大图像上传到 GPU 需要花费大量时间。
根据您对视频输入的解码需求,您必须进行研究。对我来说,我必须为 android 编译 ffmpeg 并从那里开始。
【讨论】:
其实我在ffmepg中测试了sws_scale方法,对我来说有点慢。测试结果是1080p到2K每帧40ms左右,所以我觉得如果有硬件解决方案是最好的。 是的,我将离开 sws_scale 以进行项目的下一次更新。我基本上会将解码后的帧转换为 rgba 并使用 UV 裁剪纹理以进行显示。 GL 可以在显示时在硬件中进行缩放。 720x576 帧将只使用 1024x1024 纹理,并且每帧只需要上传一次。除了 GL 为您提供的选项之外,您可能对过滤几乎无能为力,但这应该足够了。我目前唯一的问题是需要对每一帧进行去隔行扫描,所以我正在研究 glsl 来为我做这件事。【参考方案3】:我很抱歉把这个放在答案中。我没有足够的积分发表评论。 我想补充一点,您可能会遇到 OGL 纹理限制。我尝试使用 OGL 来解决相反的问题;从相机实时缩小。问题是最大 OGL 纹理是 2048x2048。不确定这是否适用于所有设备。此限制适用于 N72013 和 LG2 等较新的套件。最后,我不得不在没有 OGL 的情况下写入 NDK,方法是手动优化它。 不过祝你好运。
【讨论】:
以上是关于如何使用 NDK 有效地放大视频帧的主要内容,如果未能解决你的问题,请参考以下文章
如何在 pandas 数据帧中有效地使用 one-hot 编码规范化列?