如何为自定义视频录制应用录制的视频添加指定位置的两个水印
多端实现视频录制双水印的通用方案
核心实现逻辑
不管采用哪类技术栈开发,整体实现思路统一:
- 提前准备好正方形、三角形的透明水印素材
- 实时录制阶段拿到每帧视频的原始纹理/像素数据,或者录制完成后对成品视频逐帧处理
- 在指定坐标分别绘制两个水印,处理后的帧送入编码器生成最终视频
1. Android 原生实现
高性能方案(OpenGL ES,适配高帧率高分辨率录制)
- 配置
MediaRecorder或者CameraX的视频输出时,接入自定义Surface处理逻辑 - 创建离屏OpenGL上下文绑定FBO,每帧渲染流程:
- 先渲染原始摄像头采集的帧
- 绘制左上角正方形水印:坐标取(边距, 视频高度 - 水印高度 - 边距),注意OpenGL坐标系Y轴向上
- 绘制右下角三角形水印:坐标取(视频宽度 - 水印宽度 - 边距, 边距),可提前把三角形水印转成Bitmap上传为2D纹理直接绘制,也可以直接传入三角形顶点坐标渲染
- 处理后的帧输出到编码器即可
轻量方案(Canvas,适配低复杂度录制场景)
如果不想写OpenGL逻辑,可以用ImageReader拿到每帧的Image转成Bitmap后用Canvas直接绘制,核心伪代码:
val canvas = surface.lockCanvas(null) // 绘制原始视频帧 canvas.drawBitmap(videoFrameBitmap, 0f, 0f, null) // 绘制左上角正方形水印,边距可自定义调整 canvas.drawBitmap(squareWatermark, 16f, 16f, null) // 绘制右下角三角形水印 val triangleLeft = canvas.width - triangleWatermark.width - 16f val triangleTop = canvas.height - triangleWatermark.height - 16f canvas.drawBitmap(triangleWatermark, triangleLeft, triangleTop, null) surface.unlockCanvasAndPost(canvas)
注:Canvas方案性能低于OpenGL,适合1080P及以下、30帧以内的录制场景
2. iOS 原生实现
- 用
AVAssetWriter做视频录制时,添加AVAssetWriterInputPixelBufferAdaptor接收处理后的帧 - 每帧
CMSampleBuffer到来时,创建CIImage上下文执行合成:- 加载正方形、三角形水印的
CIImage实例 - 用
CGAffineTransform把正方形水印移到左上角位置 - 用
CGAffineTransform把三角形水印移到右下角位置 - 用
CIContext把合成后的CIImage渲染到CVPixelBuffer,送入AVAssetWriter编码即可
- 加载正方形、三角形水印的
- 对性能要求高的场景可以用Metal实现实时渲染,逻辑和Android的OpenGL方案一致。
3. 全平台通用FFmpeg方案
如果接受录制完成后再加水印,直接用FFmpeg命令处理即可,兼容性最高,不需要写复杂的渲染逻辑:
ffmpeg -i 输入视频路径 \ -i 正方形水印路径.png \ -i 三角形水印路径.png \ -filter_complex "[0:v][1:v]overlay=x=16:y=16[tmp];[tmp][2:v]overlay=x=W-w-16:y=H-h-16[v]" \ -map "[v]" -map 0:a -c:v libx264 -c:a copy 输出视频路径.mp4
其中x=16:y=16表示正方形水印距离左、上边缘16px,x=W-w-16:y=H-h-16表示三角形水印距离右、下边缘16px,数值可以按需调整。
如果需要实时录制阶段加水印,也可以接入FFmpeg的libavfilter模块实时处理每一帧,逻辑和上面的命令一致。
4. 跨平台框架实现
- Flutter:用
flutter_webrtc或者camera_android_camerax插件拿到原始帧,调用image库的drawImage方法绘制两个水印后再编码 - React Native:用
react-native-vision-camera的帧处理器插件,拿到帧数据后调用原生端的绘制逻辑处理,或者用ffmpeg-kit-react-native做后期处理
内容的提问来源于stack exchange,提问作者Rishail Siddiqui
相关产品推荐
相关产品推荐

