使用xuggle_5.4 实现视频加水印

使用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;
    }
相关推荐
benbenAItalk4 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
sunshine22 girl4 小时前
Java学习二 基本语法2, 算术运算符
java·学习
niucloud-admin4 小时前
JAVA V6 多商户商城 开发文档——插件目录结构
java·开发语言
2601_962885724 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
滕州市燕猫虎计算机科技工作室个体工商户4 小时前
Java锁
java·开发语言
shehuiyuelaiyuehao6 小时前
1计算机是如何工作的
java·计算机网络
letisgo57 小时前
JAVA 高级进阶07篇《@Transactional失效的8个场景:代理机制到传播行为》
java·面试·transactional·spring事务·aop动态代理
水域安全老周7 小时前
水趣钓鱼救生衣专利拆解:两级锁紧如何解决落水人衣分离
java·前端·网络
AI创界者7 小时前
前沿多模态大模型 MiniMax-H3无审查 本地部署与深度实测指南
人工智能·aigc·音视频
三8447 小时前
Java 模板注入(FreeMarker) · 02 · 模板引擎与 FreeMarker 语法
java·开发语言·web安全·freemarker