看视频时有两个很自然的愿望:老片源分辨率低,希望它清晰一点;24 帧的电影在 120Hz 屏幕上,希望它顺滑一点。这两个愿望各有名字:

  • 超分(Super-Resolution):把低分辨率画面放大,并尽量补出原本不存在的细节;
  • 补帧(插帧):在相邻两帧之间算出“中间那一帧“,24fps 变 48fps,运动画面明显更顺。

手机上有现成的开源技术能做这两件事吗?能做到“实时“(一边播一边算,不卡不掉帧)吗?我花了一天时间,在一台骁龙 8 Gen 3 手机上把三条技术路线全部真机跑了一遍,拿到了一手性能数据。先说结论:

  • 超分容易,补帧难。超分用 GPU“滤镜“就能满帧率跑,用 NPU(手机里的 AI 专用芯片)更是连 1080p 都实时;而 AI 补帧非常吃算力,纯 GPU 方案只在 320p 这样的小分辨率下能实时。
  • 三条路线最后可以拼成一条完整的实时管线:低分辨率补帧 + 高分辨率超分 + 120Hz 输出,每一步都有实测数字支撑。

下面是完整过程,按“从简单到硬核“的顺序讲。

测试平台

项目详情
手机vivo V2403A(零售正式版,没有 root
芯片骁龙 8 Gen 3(SM8650)
GPUAdreno 750——管“画面计算“,着色器和 Vulkan 计算都跑在这
NPUHexagon V75——管“AI 推理“,手机相机的美颜夜景就用它
屏幕1260×2800 @120Hz,天生适合呈现插帧后的高帧率画面
系统Android 16

顺带发现一个有趣的细节:GPU 驱动里暴露了两个叫 GL_QCOM_motion_estimation(运动估计)和 GL_QCOM_frame_extrapolation(帧外推)的扩展——这是芯片厂商在硬件层面预留的补帧相关能力,这次没来得及深入,先记下来。

三条路线总览

路线干什么原理(一句话版)上手难度
A. Anime4K 着色器超分给 GPU 挂一串“智能滤镜“,放大同时修边缘★ 装个播放器就行
B. RIFE(ncnn Vulkan)补帧AI 模型看着前后两帧,算出中间帧★★ 要自己编译
C. QNN / NPU超分(也能补帧)把 AI 模型塞进手机的 AI 专用芯片★★★ 要转换模型

这三条不是互斥的选择题,而是可以组装的零件——文章最后会讲怎么拼。

路线 A:Anime4K 着色器超分 —— ✅ 最简单,效果立竿见影

Anime4K(GitHub ★21k,MIT 许可)是一组专门为动漫画面设计的 GPU 着色器。着色器可以理解成“跑在显卡上的滤镜“:每帧画面经过它时顺手做放大和边缘修复,单帧开销不到 3 毫秒,对帧率毫无影响。

最省事的用法是装一个 mpv-android 播放器(MIT 许可的开源播放器),它原生支持加载用户着色器。把 Anime4K 的着色器链挂进去(高光钳制 → 去噪 → 细节恢复 → 2 倍放大),播放动漫片源立刻能看到区别。

这条路上唯一的坑有点出乎意料:mpv-android 的正式版里,通过设置界面编辑保存的 mpv.conf 配置,播放器核心实际上不读——我用“同一静态画面开关着色器各截一帧“的方法验证过,两次截图 0 像素差异,等于白配。换成官方 debug 版安装包后,可以用 run-as 命令借用 App 自己的身份把配置文件直接写进它的私有目录:

adb shell "cat /sdcard/mpv.conf | run-as is.xyz.mpv sh -c 'cat > files/mpv.conf'"

这次立即生效。用同样的静态帧对比法验证:28% 的像素发生了变化(MSE=712,PSNR=19.60dB——这个指标在这里用来证明“画面确实被重新处理了“,而非同一帧)。肉眼对比:没挂着色器的画面,色块边缘是锯齿状的阶梯、小块发糊;挂了 Anime4K 后边缘平滑连续、细节更锐利。

小结:超分这一项,着色器方案零成本、满帧率,可以全程开着。两个局限:它只为动漫内容设计,真人实拍视频用了只是“锐化放大“,不会真的补细节;另外 mpv 播放器自带的“插值“选项只是显示层面的帧混合,不是 AI 补帧——顺滑的事得靠路线 B。

路线 B:RIFE 神经网络补帧 —— ✅ 能跑,但要先知道边界

补帧选的是 RIFE(GitHub ★11k,MIT 许可),目前公认的实时插帧算法里最好用的一个:输入前后两帧,AI 算出中间帧。手机上跑 AI 模型的主流框架是 ncnn + Vulkan(腾讯开源的移动端推理框架,走 GPU 计算)。

现成的 App 都不靠谱

先试了社区里现成的方案,两个都失败:

  • 某个 RIFE 安卓 App 装上就闪退。查日志发现它打包的 native 库里少注册了一个叫 rife.Warp 的图层,模型一加载就崩——是 App 本身的 bug,不是手机不行。
  • 它内置的模型下载在手机上卡在 0%(模型托管在 GitHub,手机直连下不动;在电脑上下好再推进手机即可绕过)。

自己编译一个

既然现成的不争气,就直接拿官方实现 nihui/rife-ncnn-vulkan 的源码,用 Android NDK 交叉编译一个手机版:

cmake -G Ninja \
  -DCMAKE_TOOLCHAIN_FILE=<NDK路径>/build/cmake/android.toolchain.cmake \
  -DANDROID_ABI=arm64-v8a \
  -DANDROID_PLATFORM=android-24   # 24 以上才有 Vulkan

编出来一个 54MB 的独立可执行文件(自带全部依赖,也包含上面那个 App 缺的 Warp 层)。把它和 RIFE 模型文件(约 10MB)推进手机的 /data/local/tmp直接在命令行里跑——不需要做成 App,也不需要界面:

./rife-ncnn-vulkan -m rife-v4.6 -0 前一帧.png -1 后一帧.png -o 中间帧.png

先验证算得对不对:合成出来的中间帧和两个源帧都不相同(对两者的 PSNR 都在 19~21dB),说明它既没偷懒复制前一帧也没复制后一帧,是真心算出来的新画面。✅

关键数据:GPU 补帧的实时边界

补帧要“实时“,每帧的处理时间必须小于播放间隔。24fps 补到 48fps,每帧预算是 20.8 毫秒。实测(Adreno 750,Vulkan,fp16 半精度):

源分辨率算一帧耗时相当于每秒处理能实时补帧吗
320×180~8.5ms117fps✅ 非常轻松
854×480~80ms12.5fps❌ 差 4 倍
1280×720~164ms6.1fps❌ 差 8 倍
1920×1080~364ms2.7fps❌ 差 18 倍
3840×2160 (4K)~1.79s0.56fps❌ 差 86 倍

规律很干净:耗时基本和像素数量成正比(每微秒处理约 5.5 个像素)。结论也由此清晰——这颗 GPU 上 RIFE 的实时边界大约在 320p,480p 起步就超预算了。想在更高分辨率补帧,得换更轻的模型,或者请出下一条路线的 NPU。

路线 C:把 AI 模型塞进 NPU —— ✅ 打通,比 CPU 快 4 倍

手机里除了 CPU 和 GPU,还有一块专门跑 AI 的芯片(高通叫 Hexagon NPU/HTP)。它的特点是又快又省电,手机自带的相机夜景、人像算法就跑在上面。要把自己的模型放上去,需要用高通的 QAIRT SDK 做模型转换——这一步工具链比较繁琐,但一旦打通,收益巨大。

整个流程走通后回头看,其实是五步:

  1. 用 ONNX 搭一个小超分模型:三层卷积 + 像素重排,输入 64×64 输出 128×128(全部选用 NPU 喜欢的算子);
  2. 用 SDK 的 qnn-onnx-converter 转换:顺便做 8-bit 量化——把模型里的数字从浮点压成整数,体积和耗时都大减;
  3. 把转换产物编成手机能加载的模型库 .so(按官方 Android.mk 流程手工组装,NDK 交叉编译);
  4. 把运行库和模型推进手机 /data/local/tmp
  5. 用 SDK 自带的 qnn-net-run 跑推理——输出 Finished Executing Graphs, rc=0,成功 ✅。

过程中的三个坑值得记下来:

  1. Python 版本:SDK 转换器的某个组件只认 Python 3.10,3.12 下直接报错——版本卡住,换版本就好。
  2. 缺文件:手工链接模型库时会缺两个官方工具源文件和权重符号对齐,照着官方编译脚本补齐即可。
  3. 一个惊喜:按文档,加载进 NPU 的模块需要厂商签名,但这台零售手机对未签名模块放行,第三方模型直接跑进了 NPU——也说明这条路的门槛纯粹在软件工具链,不需要 root、不需要破解。

NPU 有多快

指标数值
64×64→128×128 超分,单次推理1.28 毫秒
硬件层面的证据报告显示 Number of HVX threads used: 4——NPU 的向量核 4 线程全开,是真·NPU 执行而非模拟
同一个模型跑在 CPU 上6.5 毫秒 → NPU 快约 4 倍(还更省电)

再把输入分辨率逐档加大,测出超分的完整效率表:

输入 → 输出NPU 执行耗时等效帧率够实时吗
854×480 → 1708×9603.9ms190fps✅ 绰绰有余
1280×720 → 2560×14409.3ms71fps✅ 轻松
1920×1080 → 3840×216024.8ms31fps✅ 刚好覆盖 24/30fps 源
3840×2160 → 7680×432089.7ms11fps❌ 4K 超分不现实

耗时约每像素 10 纳秒,同样是线性规律。要说明的是这是个 4 层的演示模型;换成真正的画质级模型(参数大约多 5~10 倍),耗时乘 3~6 倍——720p 依然实时,1080p 接近实时,依然可用。

把两张表放在一起看

对着这块 1260×2800 的屏幕算总账,得到三个有点反直觉的结论:

  1. 4K 片源根本不需要超分。4K(830 万像素)已经比屏幕(约 350 万像素)大了,直接缩小显示就好。4K 源想补帧也不现实(0.56fps),正确吃法是先缩到 1080p 再补帧、再放大
  2. 瓶颈永远是补帧,不是超分。超分这边,着色器方案恒实时、NPU 方案连 1080p 都实时;而补帧在 GPU 上必须压到 320p 的小画面上才来得及算。
  3. GPU 和 NPU 可以分工。补帧和超分分别放在不同的芯片单元上跑,互不抢资源,还能并行。

于是最终的推荐管线长这样(每输出一帧约花 12~20 毫秒,在 48fps 的 20.8ms 预算之内):

flowchart LR
    D["解码<br/>(播放器硬解)"] --> RIFE["RIFE 补帧<br/>在 320p 小画面上 ~8.5ms<br/>(GPU)"]
    RIFE --> SR["超分放大<br/>NPU 4~9ms<br/>或 Anime4K 着色器"]
    SR --> OUT["放大铺满屏幕<br/>1260x2800 @120Hz"]

思路就是“让重的活在小画面上干“:补帧最吃算力,就先把画面缩到 320p 再补;超分便宜,就在接近屏幕大小的画面上做。真做成播放器时还需要两个保险:双缓冲避免解码和计算互相等待;以及降级策略——万一算不过来,就自动改成隔帧补、或干脆只留超分。另外 GPU/NPU 持续满载会发热耗电,补帧功能最好做成手动开关。

三条路线总结

路线实测结果实时性适合内容成本
A. Anime4K 着色器✅ 生效(28% 像素差异)✅ 满帧率动漫最佳最低,装播放器即用
B. RIFE 补帧✅ 合成帧正确≤320p ✅ / 720p ❌所有内容中(要自己编译)
C. QNN NPU✅ 全链路跑通,4 倍于 CPU超分 1080p 实时所有内容中(要转换模型)

给想动手的读者的建议顺序

  1. 先装 mpv-android 挂 Anime4K,当天就能看到动漫超分的效果,成本几乎为零;
  2. 想玩补帧,用 NDK 编一个 rife-ncnn-vulkan,先在 320p 小画面上感受“24 变 48“;
  3. 想追求 720p 以上的全实时,再去研究 QNN 模型转换——这是三条路里文档最少、但天花板最高的一条。

开源社区已经把零件都备齐了(而且基本都是 MIT/BSD 许可,可自由使用;唯一要避开的是 AGPL 许可的 video2x,只能参考不能集成)。一台不 root 的普通手机,也能搭出一条每一环都有实测数据支撑的实时超分补帧管线——剩下的就是动手了。