JAVACV实现视频流转视频文件和视频截取

MAVEN 依赖

xml 复制代码
  <!-- mac 平台报错 https://gitee.com/52jian/EasyMedia/issues/I5ZMMR-->
        <!-- 媒体只用到以下两个,javacv、ffmpeg -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.5.7</version>
        </dependency>
        <!--全平台的ffmpeg-->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg-platform</artifactId>
            <version>5.0-1.5.7</version>
        </dependency>
        <!-- hutool工具包 -->
		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<version>5.3.3</version>
		</dependency>

JavaCvUtil

java 复制代码
package com.zj.util;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.springframework.util.StopWatch;

import java.io.IOException;

/**
 * @author 小布
 * @version 1.0.0
 * @className JavaCvUtil.java
 * @createTime 2023年08月19日 11:10:00
 */
@Slf4j
public class JavaCvUtil {
    /**
     * convertFileByApi
     *借助JavaCV和ffmpeg的api
     * @param sourcePath       sourcePath 可以是流地址或者文件地址
     * @param fileFullPathName fileFullPathName
     * @param duration         duration 录制时长 只针对视频流录制
     * @return java.lang.String
     * @author xiaobu
     * @date 2023/8/21 9:40
     */
    public static String convertStream2FileByApi(String sourcePath, String fileFullPathName, int duration) {
        long beginTime = System.currentTimeMillis();
        FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(sourcePath);
        Frame capturedFrame = null;
        FFmpegFrameRecorder recorder = null;
        try {
            frameGrabber.start();
            frameGrabber.getLengthInTime();
            //获取video得类型 如MP4等
            String videoType = fileFullPathName.substring(fileFullPathName.lastIndexOf(".") + 1);
            recorder = new FFmpegFrameRecorder(fileFullPathName, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setFormat(videoType);
            recorder.setFrameRate(frameGrabber.getFrameRate());
            recorder.setVideoBitrate(frameGrabber.getVideoBitrate());
            recorder.setAudioBitrate(192000);
            recorder.setAudioOptions(frameGrabber.getAudioOptions());
            recorder.setAudioQuality(0);
            recorder.setSampleRate(44100);
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
            recorder.start();
            while (true) {
                try {
                    capturedFrame = frameGrabber.grabFrame();
                    if (capturedFrame == null) {
                        System.out.println("!!! Failed cvQueryFrame");
                        break;
                    }
                    recorder.record(capturedFrame);
                    long nowTime = System.currentTimeMillis();
                    long costTime = nowTime - beginTime;
                    //duration S自动断开
                    if (costTime >= duration * 1000L) {
                        log.info("【convertFileByApi】::costTime ==> 【{}】", costTime);
                        break;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            recorder.stop();
            recorder.release();
            frameGrabber.stop();
            frameGrabber.release();
            recorder.close();
            frameGrabber.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回转码后视频文件名称
        return fileFullPathName;
        //返回转码后视频全路径
        //return fileFullPathName;
    }


    /**
     * convertFile2FileByApi
     *
     * @author 小布
     * @date 2023/8/21 13:33
     * @param sourcePath sourcePath
     * @param fileFullPathName fileFullPathName
     * @param duration duration 录制时长(z)
     * @return java.lang.String
     */
    public static String convertFile2FileByApi(String sourcePath, String fileFullPathName, int duration) {
        long beginTime = System.currentTimeMillis();
        FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(sourcePath);
        Frame capturedFrame = null;
        FFmpegFrameRecorder recorder = null;
        try {
            frameGrabber.start();
            frameGrabber.setTimestamp(20 * 1000000);
            // 视频的时长 微秒
            long lengthInTime = frameGrabber.getLengthInTime();
            String format = String.format("视频长度:%s(S)",  lengthInTime / 1000 / 1000);
            System.out.println(format);
            //获取video得类型 如MP4等
            String videoType = fileFullPathName.substring(fileFullPathName.lastIndexOf(".") + 1);
            recorder = new FFmpegFrameRecorder(fileFullPathName, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setFormat(videoType);
            recorder.setFrameRate(frameGrabber.getFrameRate());
            recorder.setVideoBitrate(frameGrabber.getVideoBitrate());
            recorder.setAudioBitrate(192000);
            recorder.setAudioOptions(frameGrabber.getAudioOptions());
            // Highest quality
            recorder.setAudioQuality(0);
            recorder.setSampleRate(44100);
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
            recorder.start();
            int count = 0;
            while (true) {
                try {
                    capturedFrame = frameGrabber.grabFrame();
                    if (capturedFrame == null) {
                        log.error("【convertFile2FileByApi】::【!!! Failed cvQueryFrame】");
                        break;
                    }
                    count++;
                    if (count > 1000) {
                        break;
                    }
                    recorder.record(capturedFrame);
                    long nowTime = System.currentTimeMillis();
                    long costTime = nowTime - beginTime;
                    //duration S自动断开
                    if (costTime >= duration * 1000L) {
                        log.info("【convertFileByApi】::costTime ==> 【{}】", costTime);
                        break;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            recorder.stop();
            recorder.release();
            frameGrabber.stop();
            frameGrabber.release();
            recorder.close();
            frameGrabber.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回转码后视频文件名称
        return fileFullPathName;
        //返回转码后视频全路径
        //return fileFullPathName;
    }

    /**
     * 基于JavaCV跨平台调用ffmpeg命令
     * duration 录制时长为多少秒的视频
     */
    public static String convertByCommand(String sourcePath, String destPath, String duration) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("开始执行基于JavaCV跨平台调用ffmpeg命令录制视频");
        try {
            String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
            ProcessBuilder pb = new ProcessBuilder(ffmpeg, "-i", sourcePath, "-vcodec", "h264", destPath);
            if (StrUtil.isNotBlank(duration)) {
                pb = new ProcessBuilder(ffmpeg, "-i", sourcePath, "-vcodec", "h264", "-t", duration, destPath);
            }
            pb.inheritIO().start().waitFor();
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
        stopWatch.stop();
        log.info("【convertByFfmpegCommand】::stopWatch.getTotalTimeSeconds() ==> 【{}】", stopWatch.getTotalTimeSeconds());
        return destPath;

    }

}

JAVACV 版本说明
JAVACV 基于JavaCV跨平台执行ffmpeg命令
JavaCV入门

相关推荐
数字融合1 小时前
透明化视场时空配准视频孪生多视域空间融合技术
人工智能·音视频·virtualenv
Yeauty3 小时前
2026 年在 Rust 里处理音视频,该走哪条路?
rust·ffmpeg·音视频·视频
weixin_495248404 小时前
短剧视频翻译配音指南:投流素材和完整剧集译制有何不同?
音视频
气泡音人声分离18 小时前
音频 Key 和 BPM 识别原理:歌曲调性和速度是如何分析出来的?
音视频·升降调·音频变速
海带紫菜菠萝汤21 小时前
WebCodecs API 实战:浏览器原生视频编解码的原理与性能测试
前端·javascript·音视频·视频编解码
kriston20261 天前
2026音频指纹识别方案准确率对比:主流厂商差距与选型指南
音视频
薛定谔的猫-菜鸟程序员1 天前
基于 Electron 的本地短视频解析与下载工具:架构设计与工程实践
java·electron·音视频
程序员大辉1 天前
seedance2.0做的视频太贵?开源免费最佳替代方案:bernini生视频,ltx2.3来配音
音视频·视频大模型·ltx2.3·bernini
AI星桥小王子1 天前
镜头、角色、剧情自由把控,可控式 AI 视频工作台横向测评
人工智能·音视频
EasyDSS1 天前
巡逻调度、应急呼叫、多路同屏——企业级融媒体平台EasyDSS一站式搞定园区安保所有音视频需求
音视频·媒体