使用xuggle_5.4 实现视频加水印
实现思路
1.读取视频流
2.对视频的图片做转换【注:视频分图片和音频,两个是不同的处理器】
3.把音频流重新导回
4.输出处理后的视频
引入依赖包
java
<dependency>
<groupId>xuggle</groupId>
<artifactId>xuggle-xuggler</artifactId>
<version>5.4</version>
<scope>system</scope>
<!-- https://mvnrepository.com/artifact/xuggle/xuggle-xuggler/5.4 在这下载-->
<systemPath>${basedir}/lib/xuggle-xuggler-5.4.jar</systemPath>
</dependency>
实现代码
java
public static void main(String[] args) {
String inputPath="D:\\Download\\b.mp4";
String outputPath="D:\\Download\\b231231.mp4";
StopWatch sw1=new StopWatch();
sw1.start();
markToVideo(inputPath,outputPath,"加了个水印");
sw1.stop();
System.out.println("mark 未压缩的视频 耗时" + sw1.getTotalTimeSeconds() + "秒");
}
private static final Font FONT = new Font("simkai", Font.BOLD, 60);
private static final AlphaComposite COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
/**
* X轴水印之间的间隔
*/
private static final int X_MOVE = 300;
/**
* Y轴水印之间的间隔
*/
private static final int Y_MOVE = 140;
// 定义一个名为markToVideo的公共静态方法,该方法接受三个字符串参数:输入路径、输出路径和内容
public static void markToVideo(String inputPath, String outputPath, String content) {
// 创建一个媒体读取器对象,从输入路径读取视频文件
IMediaReader reader = ToolFactory.makeReader(inputPath);
try {
// 设置要生成的缓冲图像类型为3BYTE_BGR,即蓝色、绿色、红色三个通道的BGR格式
reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
// 不添加动态流
reader.setAddDynamicStreams(false);
// 查询元数据
reader.setQueryMetaData(true);
// 创建一个媒体写入器对象,将处理后的视频写入到输出路径
IMediaWriter writer = ToolFactory.makeWriter(outputPath, reader);
// 为读取器添加一个监听器,监听视频图片事件
reader.addListener(new MediaToolAdapter() {
@Override
public void onVideoPicture(IVideoPictureEvent event) {
// 获取视频图片事件中的图片对象
IVideoPicture picture = event.getPicture();
// 获取Java数据中的缓冲图像
BufferedImage bufferedImage = event.getJavaData();
// 创建一个图形2D对象,用于在缓冲图像上绘制文本
Graphics2D graphics = bufferedImage.createGraphics();
// 打印缓冲图像的宽度和高度
System.out.println(bufferedImage.getWidth() + " and " + bufferedImage.getHeight());
// 在缓冲图像上创建文本(此处的createText方法未在代码中定义)
createText(content, bufferedImage, bufferedImage.getWidth(), bufferedImage.getHeight(), graphics);
// 创建一个转换器对象,将缓冲图像从Java的图像格式转换为YUV420P格式
IConverter converter = ConverterFactory.createConverter(bufferedImage, IPixelFormat.Type.YUV420P);
// 使用转换器将缓冲图像转换为YUV420P格式的视频图片对象
IVideoPicture iVideoPicture = converter.toPicture(bufferedImage, picture.getTimeStamp());
// 向写入器添加一个音频流,这里并未实际使用音频流,因此参数都是0和默认值
writer.addAudioStream(0, 0, ICodec.ID.CODEC_ID_H264, bufferedImage.getWidth(), bufferedImage.getHeight());
// 将处理后的视频图片对象编码并写入到输出视频文件
writer.encodeVideo(0, iVideoPicture);
}
});
// 等待读取器读取完所有数据包(此处为阻塞操作,直到所有数据包处理完毕)
while (reader.readPacket() == null);
} catch (Exception e) {
// 捕获并打印异常信息
e.printStackTrace();
} finally {
// 关闭读取器对象
reader.close();
}
}
private static void createText(String content, BufferedImage bufImg, int imgWidth, int imgHeight, Graphics2D graphics) {
//标记的颜色
Color markColor = new Color(180, 180, 180);
// 设置水印颜色
graphics.setColor(markColor);
// 设置水印透明度 可自定义
graphics.setComposite(COMPOSITE);
// 设置倾斜角度
graphics.rotate(Math.toRadians(-35), (double) bufImg.getWidth() / 2,
(double) bufImg.getHeight() / 2);
// 设置水印字体
graphics.setFont(FONT);
// 消除java.awt.Font字体的锯齿
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int xCoordinate = -imgWidth / 2;
int yCoordinate;
// 字体长度
int markWidth = FONT.getSize() * getTextLength(content);
// 字体高度
int markHeight = FONT.getSize();
// 循环添加水印
double d = 1.5;
while (xCoordinate < imgWidth * d) {
yCoordinate = -imgHeight / 2;
while (yCoordinate < imgHeight * d) {
graphics.drawString(content, xCoordinate, yCoordinate);
yCoordinate += markHeight + Y_MOVE;
}
xCoordinate += markWidth + X_MOVE;
}
// 释放画图工具
graphics.dispose();
}
/**
* 计算水印文本长度
* 1、中文长度即文本长度 2、英文长度为文本长度二分之一
*
* @param text 文字
* @return int
*/
public static int getTextLength(String text) {
// 水印文字长度
int length = text.length();
for (int i = 0; i < text.length(); i++) {
String s = String.valueOf(text.charAt(i));
if (s.getBytes().length > 1) {
length++;
}
}
length = length % 2 == 0 ? length / 2 : length / 2 + 1;
return length;
}