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) + "毫秒");
    }
}

参考

相关推荐
前端老石人11 小时前
前端网站换肤功能的 3 种实现方案
开发语言·前端·css·html
Legendary_00811 小时前
LDR6500U PD取电芯片:赋能设备Type-C升级,解锁高效安全取电新体验
c语言·开发语言·安全
jwt79392793711 小时前
Spring之DataSource配置
java·后端·spring
Rust研习社11 小时前
深入理解 Rust 裸指针:内存操作的双刃剑
开发语言·后端·rust
Huangjin007_11 小时前
【C++ STL篇(四)】一文拿捏vector常用接口!
开发语言·c++·学习
NQBJT11 小时前
[特殊字符] VS Code + Markdown 从入门到精通:写论文、技术文档的超实用指南
开发语言·vscode·c#·markdown
草莓熊Lotso11 小时前
Linux 线程同步与互斥(一):彻底搞懂线程互斥原理、互斥量底层实现与 RAII 封装
linux·运维·服务器·开发语言·数据库·c++
逻辑驱动的ken12 小时前
Java高频面试场景题07
java·开发语言·面试·职场和发展·求职招聘·春招
slarymusic12 小时前
解决报错net.sf.jsqlparser.statement.select.SelectBody
java
我不是懒洋洋12 小时前
【数据结构】栈和链表基本方法的实现
c语言·开发语言·数据结构·c++·链表·青少年编程·ecmascript