Flutter中如何给视频添加水印?优先不使用第三方包
Flutter 视频添加水印实现方案
一、无第三方包实现思路
Flutter本身没有直接操作视频的API,需通过MethodChannel调用平台原生代码实现,核心是在原生层对视频帧添加水印后重新编码输出。
Android 端实现要点
利用Android的MediaCodec解码原视频,在每一帧渲染时通过Canvas绘制水印(文本/图片),再编码为新视频,最后用MediaMuxer封装成完整文件。核心代码片段:
override fun onOutputFrame(frame: ByteBuffer, info: MediaCodec.BufferInfo) { val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) // 绘制原视频帧到画布 canvas.drawBitmap(frameToBitmap(frame, width, height), 0f, 0f, null) // 添加文本水印 val paint = Paint().apply { color = Color.WHITE textSize = 48f isAntiAlias = true } canvas.drawText("自定义水印", 50f, height - 50f, paint) // 将带水印的Bitmap送入编码器 encodeBitmap(bitmap) }
iOS 端实现要点
基于AVFoundation框架,用AVAsset读取原视频,创建AVMutableComposition,将水印封装为CALayer添加到视频合成图层,最后通过AVAssetExportSession导出。核心代码片段:
func addWatermark(to inputURL: URL, outputURL: URL, watermarkText: String) async throws { let asset = AVAsset(url: inputURL) let composition = AVMutableComposition() guard let videoTrack = asset.tracks(withMediaType: .video).first else { throw VideoError.invalidSource } let compVideoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)! try await compVideoTrack.insertTimeRange(CMTimeRangeMake(start: .zero, duration: asset.duration), of: videoTrack, at: .zero) // 创建文本水印图层 let watermarkLayer = CATextLayer() watermarkLayer.string = watermarkText watermarkLayer.foregroundColor = UIColor.white.cgColor watermarkLayer.fontSize = 40 watermarkLayer.frame = CGRect(x: 20, y: asset.duration.value - 60, width: 200, height: 40) // 配置视频合成 let videoComposition = AVMutableVideoComposition(asset: asset) { request in let frameLayer = request.renderContext.copyCurrentFrame() let rootLayer = CALayer() rootLayer.addSublayer(frameLayer) rootLayer.addSublayer(watermarkLayer) request.finish(with: rootLayer, context: nil) } // 导出处理后的视频 let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetMediumQuality)! exporter.outputURL = outputURL exporter.outputFileType = .mp4 exporter.videoComposition = videoComposition await exporter.export() }
Flutter 端调用
通过MethodChannel与原生通信,传递参数并获取处理结果:
class VideoWatermark { static const MethodChannel _channel = MethodChannel('video_watermark'); static Future<String?> addTextWatermark({ required String inputPath, required String outputPath, required String text, }) async { return await _channel.invokeMethod('addTextWatermark', { 'input': inputPath, 'output': outputPath, 'text': text, }); } }
二、第三方包实现方案(推荐)
若原生开发成本高,可使用flutter_ffmpeg基于FFmpeg命令行实现,步骤简单且兼容性强。
步骤1:添加依赖
dependencies: flutter_ffmpeg: ^0.5.1
步骤2:执行水印命令
- 添加文本水印:
import 'package:flutter_ffmpeg/flutter_ffmpeg.dart'; final FlutterFFmpeg _ffmpeg = FlutterFFmpeg(); // 命令说明:保留原音频,在视频左下角添加白色文本水印 await _ffmpeg.execute( '-i $inputPath -vf "drawtext=text=\'我的水印\':x=20:y=H-60:fontsize=40:fontcolor=white" -codec:a copy $outputPath -y' );
- 添加图片水印:
// 命令说明:在视频右下角添加半透明图片水印 await _ffmpeg.execute( '-i $inputPath -i $watermarkImgPath -filter_complex "overlay=W-120:H-120:alpha=0.6" -codec:a copy $outputPath -y' );
注意事项
- 权限:Android需申请
READ_MEDIA_VIDEO(Android13+)、WRITE_EXTERNAL_STORAGE(Android13以下);iOS需开启相册读写权限。 - 性能:视频处理耗资源,建议在后台线程执行,避免阻塞UI。
- 位置调整:通过滤镜参数(如
x=W-100表示右对齐)或原生图层坐标控制水印位置。
内容的提问来源于stack exchange,提问作者황희윤
相关产品推荐
相关产品推荐

