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

发布时间:2023年12月21日

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

实现思路

1.读取视频流
2.对视频的图片做转换【注:视频分图片和音频,两个是不同的处理器】
3.把音频流重新导回
4.输出处理后的视频

引入依赖包

<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>

实现代码

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;
    }
文章来源:https://blog.csdn.net/zxcz123123421/article/details/135099117
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。