Java处理视频文件,生成打标视频

java 复制代码
import org.apache.commons.lang3.StringUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author Mr.superbeyone
 * @project 
 * @className FfmpegUtil2
 * @description
 * @date 2023-10-20 15:15
 **/

public class FfmpegUtil2 {


    private static Logger logger = LoggerFactory.getLogger(FfmpegUtil2.class);


    /**
     * 生成标注后的视频文件
     *
     * @param srcVideoPath 源视频文件路径
     * @param frameRate    跳帧请求RPC的步数
     * @param extName      生成的文件扩展名 如: mp4  flv
     * @return 标注后的视频文件路径
     */
    public static String generateTagVideo(String srcVideoPath, int frameRate, String extName) {
        return generateTagVideo(srcVideoPath, null, frameRate, extName);
    }

    public static String generateTagVideo(String srcVideoPath, String targetVideoPath, int frameRate, String extName) {
        long start = System.currentTimeMillis();
        //视频文件路径
        File srcVideoFile = new File(srcVideoPath);
        if (!srcVideoFile.exists() || !srcVideoFile.isFile()) {
            logger.info("generateTagVideo srcVideoPath is not video file {}", srcVideoPath);
            return "";
        }
        if (StringUtils.isBlank(targetVideoPath)) {
            targetVideoPath = srcVideoFile.getParentFile() + File.separator + StringUtils.substringBeforeLast(srcVideoFile.getName(), ".") + "_tag." + extName;
        }
        String targetVideo = doGenerateTagVideo(srcVideoPath, targetVideoPath, frameRate, extName);
        logger.info("generateTagVideo 耗时 {}", (System.currentTimeMillis() - start));
        logger.info("generateTagVideo srcVideo {} targetVideo {}", srcVideoPath, targetVideo);
        return targetVideo;
    }

    public static String doGenerateTagVideo(String srcVideoPath, String targetVideoPath, int frameRate, String extName) {
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;
        try {
            grabber = FFmpegFrameGrabber.createDefault(new File(srcVideoPath));
            grabber.setFormat(StringUtils.substringAfterLast(srcVideoPath, ".").toLowerCase());
            grabber.start();

            int imageHeight = grabber.getImageHeight();
            int imageWidth = grabber.getImageWidth();
            recorder = FFmpegFrameRecorder.createDefault(new File(targetVideoPath), imageWidth, imageHeight);

            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
            recorder.setFormat(extName);

            recorder.setVideoBitrate(10000);//数值越大,存储空间越大
            recorder.setVideoOption("preset", "ultrafast");//究极快
            recorder.start();

            Java2DFrameConverter converter = new Java2DFrameConverter();

            int index = 0, x = 0, y = 0, width = 0, height = 0;
            Frame frame;
            while ((frame = grabber.grabImage()) != null) {
                if (null == frame.image) {
                    continue;
                }
                index++;
                
                BufferedImage image = converter.getBufferedImage(frame);
                if (frameRate > 0 && index % frameRate == 0) {
                    Map<String, Integer> location = rpcFindLocation(image);
                    x = location.get("x");
                    y = location.get("y");
                    width = location.get("w");
                    height = location.get("h");
                }
                
                Graphics graphics = image.getGraphics();
                graphics.setColor(Color.RED);
                graphics.drawRect(x, y, width, height);
                Frame drawFrame = converter.convert(image);
                recorder.record(drawFrame);
            }
            recorder.close();
            grabber.close();
        } catch (Exception e) {
            logger.error("doGenerateTagVideo exception ", e);
        } finally {
            if (grabber != null) {
                try {
                    grabber.close();
                } catch (Exception ex) {
                    logger.error("close grabber error", ex);
                }
            }
            if (recorder != null) {
                try {
                    recorder.close();
                } catch (Exception ex) {
                    logger.error("close recorder error", ex);
                }
            }
        }

        return targetVideoPath;
    }

    /**
     * 对图片文件RPC调用
     *
     * @param image 图片文件
     * @return x, y, w, h
     */
    private static Map<String, Integer> rpcFindLocation(BufferedImage image) {
        Map<String, Integer> location = new HashMap<>(8);
        Random random = new Random();
        location.put("x", 800 + random.nextInt(100));
        location.put("y", 750 + random.nextInt(50));
        location.put("w", 50 + random.nextInt(10));
        location.put("h", 50 + random.nextInt(10));
        return location;
    }


    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        String srcPath = "D:\\WorkSpace\\video\\src\\b.mp4";
        String destPath = "D:\\WorkSpace\\video\\src\\test\\" + System.currentTimeMillis() + ".flv";
        generateTagVideo(srcPath, destPath, 10, "flv");
        System.out.println(destPath + "耗时\t" + (System.currentTimeMillis() - start) + "毫秒");
    }
}

参考

相关推荐
非优秀程序员4 小时前
第04章 邮箱大战,163 与 QQ 的暗战|《互联网产品恩仇录》
java·vue.js·架构
知已难寻5 小时前
Docker 入门:容器技术与 Docker 基础
java·运维·服务器·docker·云原生·容器
沐晓时光5 小时前
C语言入门,内存函数知识讲解
c语言·开发语言
文丑颜不良啊7 小时前
LeetCode2481~2500题目解析
java·leetcode
Flynn Liang8 小时前
同一需求三套写法:用 Spring AI、LangChain4j、AgentScope Java 各实现一个带工具调用的 RAG 助手(实战对比)
java·人工智能·大模型·架构设计·spring ai·langchain4j·agentscope
聪明的笨猪猪8 小时前
实际工程问题:AI 生成 Spring Cache(@Cacheable / @CachePut / @CacheEvict)缓存注解踩坑
java·经验分享·面试·ai编程
愿有所息9 小时前
记一次 ARM64 + JDK8 上 fastjson2 的诡异数据错乱
java
秋饼9 小时前
MCP 2026-07-28 无状态协议大改版:Spring AI 2.1 多轮往返请求与网关路由落地
java·ai·技术分享·后端开发
SL_staff10 小时前
JVS-BI 实战:业务人员如何用零代码 ELT + 可视化配置构建实时经营分析闭环
java·spring·全栈
SL_staff11 小时前
企业AI落地难?JVS-AI渐进式实践:安全可控、小切口验证、标准化沉淀与规模化复制
java·开源·aigc