app端视频水印需分播放叠加与录制嵌入两种场景:前者用css层叠+pointer-events:none实现轻量覆盖,后者须用原生插件或服务端ffmpeg;动态水印必须原生实现。

App端视频水印不能靠前端Canvas实时绘制,必须区分「播放时叠加」和「录制/导出时嵌入」两种场景——前者用CSS层叠+pointer-events: none,后者必须走原生插件或服务端FFmpeg。
video组件上层覆盖文字/图片水印(仅App端播放时)
这是最轻量、最快上线的方案,适用于对版权要求不高的内部应用。核心是利用position: relative + absolute定位,且必须加pointer-events: none,否则会拦截点击、拖动进度条等操作。
-
video容器需设position: relative,水印view或image设position: absolute - 水印元素样式中必须包含
pointer-events: none,否则iOS/Android App都会卡顿或无法控制播放 - 全屏适配要监听
@fullscreenchange事件动态调整水印位置,比如全屏时右下角改到左上角 - 不要在水印里放
button或input,它们会触发focus并导致键盘弹出,破坏体验
Android/iOS原生插件实现录制时嵌入水印(真·防篡改)
如果你的需求是「拍出来的视频文件自带水印」,比如巡检、取证类App,那必须用原生插件。uni-app的camera组件不暴露帧数据,无法做动态时间戳、GPS坐标等水印。
- Android端需用
Camera.PreviewCallback或ImageReader获取YUV帧,用MediaCodec编码时逐帧叠加Bitmap水印 - iOS端对应使用
AVCaptureVideoDataOutput拿到CMSampleBufferRef,用CIContext合成水印再送入AVAssetWriter - 关键陷阱:帧缓存必须用循环buffer池(如3~5个
byte[]),否则onPreviewFrame回调会被丢帧甚至花屏 - 水印文字建议预渲染为Bitmap,避免每帧调用
drawText造成线程阻塞
服务端FFmpeg预处理(适合已存在视频)
对已有视频文件加水印,别在App里硬扛。直接传到服务端用FFmpeg跑,返回带水印的新地址。App只负责播放。
- 文字水印命令:
ffmpeg -i input.mp4 -vf "drawtext=text='ID:123':x=10:y=h-th-10:fontsize=16:fontcolor=white" output.mp4 - 图片水印命令:
ffmpeg -i input.mp4 -i watermark.png -filter_complex "overlay=10:10" output.mp4 - 注意:MP4必须含
moov头信息,否则H5 video无法seek,加-movflags +faststart参数修复 - 移动端上传大视频前务必压缩,否则超时失败率极高;推荐先用
mediainfo校验分辨率/码率再转码
真正难的是动态水印——比如每帧显示实时毫秒级时间戳。这已经超出Web技术栈能力,必须原生插件+硬件加速渲染。很多团队踩坑后才发现:Canvas绘图速度根本跟不上30fps,而原生插件里一个Canvas.lockCanvas()调用就可能让预览卡顿。别迷信“纯前端方案”。











