这个公众号会路线图式的遍历分享音视频技术:音视频基础 → 音视频工具 → 音视频工程示例 → 音视频工业实战。关注一下成本不高,错过干货损失不小 ↓↓↓
随着相机采集越来越多的与滤镜、美颜、特效等前处理流程结合,关注采集预览的性能变得十分重要。采集预览阶段表示打开相机,但是还没开始进行直播推流或者视频录制的阶段,但这时候一般也开始进行滤镜、美颜、特效前处理了。在这个阶段我们可以关注以下性能指标:
此外,我们还需要关注:采集画面质量、采集内存等指标的优化。
手机设备上的应用要打开相机是需要向用户申请权限的,所以优化权限申请的交互及文案提升权限通过率是优化相机打开成功率的一个方案。
这里有几个建议:
如果确实遇到相机打开报错,可以重试相机打开流程。
另外,需要统计相机打开错误的细分错误码,这样就能更好的定位相机打开失败的原因进行针对性的优化。
优化相机打开速度,可以从业务层进行处理,优先将 CPU 资源让给相机,相机打开后回调给业务相机首帧已出的事件,这样业务收到该事件后再进行其它初始化,体验会得到很大提升。
通常相机会与特效等 SDK 混合使用,可以子线程异步加载特效组件,首帧可以无特效立即展示出来,等检测特效加载好后再加入效果即可。
第一帧展示前可以使用上一次关闭高斯模糊图来占位,这样体验比纯黑色效果好很多,可参考微信朋友圈相机。
把采集和视频特效放在同一个线程,随着特效功能越来越强,计算越来越重,会影响到最终的输出帧率。要优化可以改为多线程的方式,这里有下面几点需要注意:
1)使可并发的任务跑在不同的线程上:
2)使用缓冲区组合生产消费者模型,各个模块可以并行,而且性能兼容性更好:
这样一来,在采集后如果要继续做其他任务(比如编码、发送网络等)也能比较方便的接入。
采集和前处理(AI 模型、图像处理、特效等)模块交互时,可以做下面几项优化:
GPU 和 CPU 要尽量少做数据拷贝,性能比较差。可以使用系统能力来实现 GPU 和 CPU 的内存共享来做相关的优化。
比如在 iOS 上,使用设置了 kCVPixelBufferIOSurfacePropertiesKey
属性的 CVPixelBufferRef 是可以支持 GPU 和 CPU 共享内存的。从相机采集出来的、从 VideoToolbox 解码出来的 CVPixelBufferRef 都具有这个属性,所以通常来讲使用系统的 API 时,你并不太需要操心这个问题。
如果你要自己创建一个图像来进行渲染,还希望能读出其数据做其他处理,并且希望支持 GPU 和 CPU 共享内存,可以参考下面这篇文章:Rendering to a texture with iOS 5 texture cache api[1]
通常低端机效果较多情况下选择 1080P + 30FPS 会比较卡,影响用户体验,如何选择合适的分辨率和帧率则尤为重要。
画面采集质量,比如清晰度、亮度等指标对于最终视频观看的体验尤为重要,可通过以下几点尝试提高画质:
可智能选择人脸自动对焦或者手动对焦,防止曝光不合理影响画质。下面的对焦策略,可以参考:
很多手机在使用中可能会出现镜头被弄脏的情况,这时候采集处理的画面质量自然就比较模糊了,针对这种情况可通过算法检测预览画面是否模糊,并提示用户清洁一下摄像头来解决清晰度的问题。
对于采集后的图像还可以通过算法进行画质增强。
音视频知识图谱 2022.09中就介绍了部分图像降噪和增强相关的算法分类,这里就不深入探讨了。
优化相机内存占用大小,有利于减少内存 OOM
问题导致的崩溃。在不同的平台,可以选择恰当的采集数据输出格式来优化内存使用:
1)iOS 采集数据输出格式
输出格式可配置为 BGRA
& YUV
,尽量设置为 YUV
数据格式,可以减少 width * height * 2.5
数据大小。
720 * 1280
分辨率,单张图片 BGRA
占用 720 * 1280 * 4 = 3.5M
,YUV
占用 720 * 1280 * 1.5 = 1.3M
。CVPixelBufferPool
队列,使用队列的好处是当外层锁住 CVPixelBufferA,底层则直接使用 CVPixelBufferB,有利于提高多线程性能,如果全部都锁住了,那相机将不会再吐数据。实测队列大小为 13
,所以 YUV
数据格式相对于 BGRA
节约共 (3.5 M - 1.3M) * 13 = 28.6M
。BGRA
,所以需要通过 OpenGLES 将 YUV
数据转换为 BGRA 纹理即可,开销非常小。另一个好处是很多算法输入也都是 YUV
数据格式。2)Android 采集数据输出格式
安卓因为支持 Camera1 & Camera2 两种模式,通常根据线上大数据决定当前设备启用哪种模式。
YUV
或者 SurfaceTexture
,如果需要算法识别则输出 YUV
,不需要则直接输出 SurfaceTexture
来提高性能。YUV
数据格式,通常需要每一帧进行旋转,做图像的裁剪、缩放、旋转、尺寸变化时要注意优化性能。可以使用 libyuv 来做常规的图像处理,一些 libyuv 版本甚至做过汇编级别的优化来提升图像处理的性能。[1]
Rendering to a texture with iOS 5 texture cache api: https://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/