SurfaceView和MediaCodec生成的Surface之间互相拷贝的可用方法有哪些
两个Surface实例之间内容拷贝的实现方法
以下方法不区分源Surface与目标Surface的类型,可根据你的业务场景、适配要求选择:
方法1:ImageReader中转实现
- 实现逻辑:创建匹配源Surface输出尺寸、格式的
ImageReader实例,将源内容输出到ImageReader.getSurface()生成的中转Surface,调用ImageReader.acquireNextImage()获取帧数据后,把Image的像素缓冲区写入目标Surface即可 - 注意事项:处理完成后必须调用
Image.close()释放资源,否则会导致帧队列阻塞无法获取新帧;如果需要二次处理帧内容(裁剪、加水印、色彩调整),可以在这一步直接操作缓冲区 - 适用场景:需要对帧内容做自定义处理的场景,灵活度最高
方法2:SurfaceTexture + OpenGL 渲染实现
- 实现逻辑:创建
SurfaceTexture实例绑定到OpenGL纹理ID,用该实例生成中转Surface作为源内容的输出目标,收到SurfaceTexture.OnFrameAvailableListener的帧可用回调时,在GL线程中直接把纹理内容绘制到目标Surface上 - 注意事项:需要自行维护独立的GL渲染线程,渲染时要正确应用
SurfaceTexture.getTransformMatrix()返回的变换矩阵,避免画面旋转、拉伸或者方向错误 - 适用场景:对性能要求高的场景,拷贝过程几乎无CPU参与,耗时极低,适合高帧率、高分辨率的视频流拷贝场景
方法3:SurfaceControl 直接重定向(Android 10+ 可用)
- 实现逻辑:Android 10(API 29)新增的
SurfaceControlAPI支持直接对Surface的缓冲区做重定向映射,无需手动搬运帧数据,配置完成后源Surface的内容会自动同步到目标Surface - 注意事项:仅支持API 29及以上系统版本,低版本设备无法兼容
- 适用场景:仅需要适配高版本系统的应用,实现代码最简,性能开销最低
方法4:Canvas 中转绘制(适用范围极窄)
- 实现逻辑:如果源Surface支持锁定Canvas操作,调用
Surface.lockCanvas()获取源内容画布,再锁定目标Surface的Canvas,直接把源画布内容绘制到目标画布上,最后调用unlockCanvasAndPost()提交更改即可 - 注意事项:绝大多数硬件渲染的Surface(包括MediaCodec生成的Surface、开启硬件加速的SurfaceView输出Surface)都不支持锁定Canvas操作,该方法仅适用于软渲染的静态Surface内容拷贝,性能较差
- 适用场景:简单低性能要求的静态内容拷贝,不需要依赖第三方库或者高版本系统API
内容的提问来源于stack exchange,提问作者Ayyappa
相关产品推荐
相关产品推荐

