Java ffmpeg 实现视频加文字/图片水印功能
引入依赖
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>4.3.1-1.5.4</version>
</dependency>
代码示例
文字水印实现
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import java.awt.*;
import java.awt.image.BufferedImage;
/**
* 视频添加文字水印
*
* @author alin
*/
public class VideoWatermark {
public static void main(String[] args) throws Exception {
// 视频文件
String inputFile = "D:\\test\\video.mp4";
// 输出文件
String outputFile = "D:\\test\\output.mp4";
// 初始化FFmpegFrameGrabber以读取输入视频文件
try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile)) {
grabber.start();
// 初始化FFmpegFrameRecorder以写入输出视频文件
try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels())) {
recorder.setFormat("mp4");
recorder.setSampleRate(grabber.getSampleRate());
recorder.setFrameRate(grabber.getFrameRate());
recorder.setTimestamp(grabber.getTimestamp());
recorder.setVideoBitrate(grabber.getVideoBitrate());
recorder.setVideoCodec(grabber.getVideoCodec());
recorder.start();
// 处理每一帧
Frame frame;
Java2DFrameConverter converter = new Java2DFrameConverter();
while ((frame = grabber.grab()) != null) {
if (frame.image != null) {
// 将Frame转换为BufferedImage
BufferedImage bufferedImage = converter.getBufferedImage(frame);
// 在BufferedImage上绘制文字水印
Graphics2D g = bufferedImage.createGraphics();
// 启用抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 启用文本抗锯齿
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 使用支持中文的字体
g.setFont(new Font("Microsoft YaHei", Font.BOLD, 30));
g.setColor(Color.gray);
String watermarkText = "测试水印文字";
// 计算水印文字的位置 右下角
//FontMetrics fontMetrics = g.getFontMetrics();
//int textWidth = fontMetrics.stringWidth(watermarkText);
//int textHeight = fontMetrics.getHeight();
//int x = bufferedImage.getWidth() - textWidth - 10; // 右边距10像素
//int y = bufferedImage.getHeight() - textHeight + fontMetrics.getAscent() - 10; // 下边距10像素
// 计算水印文字的位置 左上角
int x = 10; // 左边距10像素
int y = 30; // 上边距30像素
g.drawString(watermarkText, x, y);
g.dispose();
// 将BufferedImage转换回Frame
frame = converter.convert(bufferedImage);
}
// 记录帧
recorder.record(frame);
}
// 关闭grabber和recorder
recorder.stop();
recorder.release();
grabber.stop();
}
}
}
}
图片水印实现
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* 视频添加图片水印
*
* @author alin
*/
public class VideoWatermark {
public static void main(String[] args) throws Exception {
// 视频文件
String inputFile = "D:\\test\\video.mp4";
// 输出文件
String outputFile = "D:\\test\\output.mp4";
// 水印照片
String watermarkImageUrl = "D:\\test\\test.png";
try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile)) {
grabber.start();
try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels())) {
recorder.setFormat("mp4");
recorder.setSampleRate(grabber.getSampleRate());
recorder.setFrameRate(grabber.getFrameRate());
recorder.setTimestamp(grabber.getTimestamp());
recorder.setVideoBitrate(grabber.getVideoBitrate());
recorder.setVideoCodec(grabber.getVideoCodec());
recorder.start();
BufferedImage watermarkImage = loadWatermarkImage(watermarkImageUrl);
Frame frame;
while ((frame = grabber.grab()) != null) {
if (frame.image != null) {
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(frame);
// 在BufferedImage上绘制图片水印
Graphics2D g = bufferedImage.createGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
int x = 10; // 左边距10像素
int y = 30; // 上边距30像素
g.drawImage(watermarkImage, x, y, null);
g.dispose();
frame = converter.convert(bufferedImage);
}
recorder.record(frame);
}
recorder.stop();
recorder.release();
grabber.stop();
}
}
}
/**
* 加载水印图片
*
* @param imagePath 水印图片路径
* @return 水印图片
* @throws IOException
*/
private static BufferedImage loadWatermarkImage(String imagePath) throws IOException {
//return ImageIO.read(new URL(imagePath));
return ImageIO.read(new File(imagePath));
}
}