使用java实现ffmpeg的各种操作

news2024/9/25 11:11:38

以实现如下功能

  • 1、支持音频文件转mp3;
  • 2、支持视频文件转mp4;
  • 3、支持视频提取音频;
  • 4、支持视频中提取缩略图;
  • 5、支持按时长拆分音频文件;

1、工具类

由于部分原因,没有将FfmpegUtil中的静态的命令行与Type枚举类结合使用。


import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/***
 *
 * @author xuancg
 * 要求系统内置ffmpeg工具环境
 * @date 2024/9/23
 */
@Slf4j
public class FfmpegUtil {

    private static final String CONVERT_MP3 = "ffmpeg -i %s -y %s";

    private static final String CONVERT_MP4 = "ffmpeg -i %s -c:v libx264 -c:a copy -y %s";

    private static final String EXTRACT_MP3 = "ffmpeg -i %s -q:a 0 -map a -y %s";

    private static final String EXTRACT_ICON = "ffmpeg -i %s -ss 0.5 -vframes 1 -r 1 -ac 2 -ab 128k   -y -f mjpeg %s";

    private static final String SPLIT_AUDIO_BY_SIZE = "ffmpeg -i %s  -f segment -segment_time  %d  -c copy -y  %s";


    private static final Set<String> MP3_TYPE = new HashSet<>(Arrays.asList("mp3", "wav", "aac", "flac"));

    private static final Set<String> MP4_TYPE = new HashSet<>(Arrays.asList("mp4", "avi", "flv", "mpeg", "wmv"));


    /***
     * 音视频文件格式化,如果存在目标文件会强制覆盖
     * 1、支持音频文件转mp3;
     * 2、支持视频文件转mp4;
     * 3、支持视频提取音频;
     * 4、支持视频中提取缩略图;
     * 5、支持按时长拆分音频文件;
     */
    public static boolean convertMedia(MediaConvertBo convertBo) {
        File src = convertBo.getSrc();
        File dest = convertBo.getDest();
        if (null == src || !src.isFile()) {
            log.error("原始文件不存在");
            return false;
        }
        if (null != dest && dest.isFile()) {
            log.info("目标文件已存在");
        }
        long start = System.currentTimeMillis();
        Process process = null;
        BufferedReader reader = null;
        try {
            String cmd = createCmd(convertBo);
            if(null == cmd){
                return false;
            }
            log.info("ffmpeg执行命令=" + cmd);
            // 执行命令
            process = Runtime.getRuntime().exec(cmd);
            // 获取命令输出结果
            reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                log.debug(line);
            }
            // 明确自己的命令需要执行多长时间,否则可以一直等待
            int timeout = convertBo.getTimeout();
            if (timeout <= 0) {
                process.waitFor();
            } else {
                process.waitFor(timeout, TimeUnit.SECONDS);
            }
            return dest.isFile() && dest.length() > 10;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            log.error("剪裁视频超时source=" + src.getAbsolutePath());
        } finally {
            if (null != process) {
                process.destroy();
            }
            if (null != reader) {
                try {
                    reader.close();
                } catch (IOException e) {
                    log.error("关闭流失败" + e.getMessage());
                }
            }
            log.info("耗时ms=" + (System.currentTimeMillis() - start));
        }
        return false;

    }


    public static boolean isMp4File(File file){
        String name = file.getName();
        String suffix = name.substring(name.lastIndexOf(".") + 1);
        return MP4_TYPE.contains(suffix);
    }

    public static boolean isMp3File(File file){
        String name = file.getName();
        String suffix = name.substring(name.lastIndexOf(".") + 1);
        return MP3_TYPE.contains(suffix);
    }


    private static final String createCmd(MediaConvertBo bo) {
        File src = bo.getSrc();
        String srcPath = src.getAbsolutePath().replace("\\", "/");
        String destPath = bo.getDest().getAbsolutePath().replace("\\", "/");;
        if (bo.isConvertMp3()) {
            if(!isMp3File(src)){
                log.error("错误的mp3格式");
                return null;
            }
            return String.format(CONVERT_MP3, srcPath, destPath);
        } else if (bo.isConvertMp4()) {
            if(!isMp4File(src)){
                log.error("错误的mp4格式");
                return null;
            }
            return String.format(CONVERT_MP4, srcPath, destPath);
        } else if(bo.getType() == MediaConvertBo.Type.EXTRACT_MP3){
            if(!isMp4File(src)){
                log.error("错误的mp4格式");
                return null;
            }
            return String.format(EXTRACT_MP3, srcPath, destPath);
        } else if(bo.getType() == MediaConvertBo.Type.EXTRACT_ICON) {
            if(!isMp4File(src)){
                log.error("错误的mp4格式");
                return null;
            }
            return String.format(EXTRACT_ICON, srcPath , destPath);

        } else if(bo.getType() == MediaConvertBo.Type.SPLIT_AUDIO_BY_SIZE){
            bo.getDest().mkdirs();
            String name = src.getName();
            String suffix = name.substring(name.lastIndexOf(".") + 1);
            // 保持输入输出一致性
            return String.format(SPLIT_AUDIO_BY_SIZE, srcPath, bo.getSplitSize(), destPath + "/output_%03d." + suffix);
        }

        log.error("错误的type");
        return null;
    }

}

2、入参对象


import lombok.Data;

import java.io.File;

/***
 *
 * @author xuancg
 * @date 2024/9/23
 */
@Data
public class MediaConvertBo {


    private File src;
    private File dest;

    /**0表示持续等待,单位秒*/
    private int timeout = 0;

    /** 拆分时长,单位秒*/
    private int splitSize = 60;

    /**处理类型,必传*/
    private Type type;


    public boolean isConvertMp3(){
        return null != type && type == Type.CONVERT_MP3;
    }

    public boolean isConvertMp4(){
        return null != type && type == Type.CONVERT_MP4;
    }

    public enum Type {
        /**将视频转码成mp4*/
        CONVERT_MP4,
        /**将音频转码成mp3*/
        CONVERT_MP3,
        /**从视频中提取音频*/
        EXTRACT_MP3,
        /**从视频中提取缩略图*/
        EXTRACT_ICON,
        /**按时长拆分音频文件*/
        SPLIT_AUDIO_BY_SIZE,
        ;
    }


}

3、junit测试


import org.junit.Test;

import java.io.File;

/***
 *
 * @author xuancg
 * @date 2024/9/23
 */
public class ConvertTest {

    /**
     * 1分10秒的wav2M大小=转成mp3耗时858ms,200kb大小
     */
    @Test
    public void convertmp3(){
        File src = new File("C:\\Users\\Desktop\\音视频素材\\example.wav");
        File dest = new File("C:\\Users\\Desktop\\音视频素材\\example.mp3");

        MediaConvertBo bo = new MediaConvertBo();
        bo.setType(MediaConvertBo.Type.CONVERT_MP3);
        bo.setSrc(src);
        bo.setDest(dest);

        System.out.println(FfmpegUtil.convertMedia(bo));
    }


    /**
     * 4分13秒视频50M大小=提取音频耗时7秒,4M大小
     */
    @Test
    public void extractMp3(){
        File src = new File("C:\\User\\Desktop\\音视频素材\\202002041032546186.mp4");
        File dest = new File("C:\\User\\Desktop\\音视频素材\\202002041032546186.mp3");

        MediaConvertBo bo = new MediaConvertBo();
        bo.setType(MediaConvertBo.Type.EXTRACT_MP3);
        bo.setSrc(src);
        bo.setDest(dest);
        System.out.println(FfmpegUtil.convertMedia(bo));
    }

    /**
     * 耗时500ms,保持原始视频尺寸
     */
    @Test
    public void extractIcon(){
        File src = new File("C:\\Users\\Desktop\\音视频素材\\202002041032546186.mp4");
        File dest = new File("C:\\Users\\Desktop\\音视频素材\\202002041032546186.jpg");

        MediaConvertBo bo = new MediaConvertBo();
        bo.setType(MediaConvertBo.Type.EXTRACT_ICON);
        bo.setSrc(src);
        bo.setDest(dest);
        System.out.println(FfmpegUtil.convertMedia(bo));
    }


    /**
     * 1分钟2秒
     */
    @Test
    public void splitAudio(){
        File src = new File("C:\\Users\\Desktop\\音视频素材\\example.wav");
        File dest = new File("C:\\Users\\Desktop\\音视频素材\\example");

        MediaConvertBo bo = new MediaConvertBo();
        bo.setType(MediaConvertBo.Type.SPLIT_AUDIO_BY_SIZE);
        bo.setSrc(src);
        bo.setDest(dest);
        bo.setSplitSize(60);
        System.out.println(FfmpegUtil.convertMedia(bo));
    }

}

5、maven依赖

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version> <!-- 版本号可替换为最新版本 -->
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>1.5.8</version>
</dependency>

<!-- 此版本中主要兼容linux和windows系统,如需兼容其他系统平台,请引入对应依赖即可 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>opencv</artifactId>
    <version>4.6.0-1.5.8</version>
    <classifier>linux-x86_64</classifier>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>opencv</artifactId>
    <version>4.6.0-1.5.8</version>
    <classifier>windows-x86_64</classifier>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>openblas</artifactId>
    <version>0.3.21-1.5.8</version>
    <classifier>linux-x86_64</classifier>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>openblas</artifactId>
    <version>0.3.21-1.5.8</version>
    <classifier>windows-x86_64</classifier>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.1.2-1.5.8</version>
    <classifier>linux-x86_64</classifier>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.1.2-1.5.8</version>
    <classifier>windows-x86_64</classifier>
</dependency>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2163389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频汇聚/视频存储/安防视频监控EasyCVR平台RTMP推流显示离线是什么原因?

视频汇聚/视频存储/安防视频监控EasyCVR视频汇聚平台兼容性强、支持灵活拓展&#xff0c;平台可提供视频远程监控、录像、存储与回放、视频转码、视频快照、告警、云台控制、语音对讲、平台级联等视频能力。 EasyCVR安防监控视频综合管理平台采用先进的网络传输技术&#xff0…

Goland的使用

一、安装Goland 一、Goland简介 Goland是由JetBrains公司旨在为go开发者提供的一个符合人体工程学的新的商业IDE。这个IDE整合了IntelliJ平台的有关go语言的编码辅助功能和工具集成特点 二、下载相应的安装包 1、官网下载地址 GoLand by JetBrains: More than just a Go IDE 三…

网络编程,端口号,网络字节序,udp

前面一篇我们讲了网络的基础&#xff0c;网络协议栈是什么样的&#xff0c;数据如何流动传输的&#xff1b;接下来这篇&#xff0c;我们将进行实践操作&#xff0c;真正的让数据跨网络进行传输&#xff1b; 1.网络编程储备知识 1.1 初步认识网络编程 首先我们需要知道我们的…

Facebook对现代社交互动的影响

自2004年成立以来&#xff0c;Facebook已经成为全球最大的社交媒体平台之一&#xff0c;改变了人们的交流方式和社交互动模式。作为一个数字平台&#xff0c;Facebook不仅为用户提供了分享生活点滴的空间&#xff0c;也深刻影响了现代社交互动的各个方面。本文将探讨Facebook如…

Ollama在Windows安装,使用,简单调用API

一、安装ollama 1、安装 在Windows本地安装ollama&#xff0c;官方网页&#xff1a;https://ollama.com/download/windows 下载完安装包&#xff0c;安装就好&#xff0c;默认应该是C盘。应该是没办法改&#xff0c;如果有小伙伴能改&#xff0c;也请告知一下。 2、验证安装…

华为OD机试 - 数据单元的变量替换 - 分治、递归(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

基于yolov8+deepsort+gradio实现目标追踪演示

【效果展示】 【测试环境】 ultralytics8.2.95 gradio4.26.0 torch1.9.0cu111 理论上支持最新ultralytics版本 【实现部分代码】 with gr.Blocks() as demo:with gr.Tab("追踪"):# 使用Markdown显示文本信息&#xff0c;介绍界面的功能gr.Markdown(""…

linux固定串口别名

最近项目功能要求&#xff0c;需要将插入设备的串口设备占用的端口号固定住&#xff0c;这里记录一下设置过程方便以后查阅。 linux固定串口别名 配置过程相关补充 配置过程 列出当前插入USB端口的设备&#xff1a; lsusb查看当前设备的端口号&#xff1a; ls dev/查看当前设…

无人机飞手培训及巡检、吊运等飞行服务一体化技术详解

在无人机行业日益兴起的背景下&#xff0c;培养专业、合格的无人机飞手成为首要任务。飞手培训基础涵盖理论学习与安全意识建立两大方面。理论学习包括无人机基础知识&#xff08;如无人机类型、结构、原理&#xff09;、航空法规&#xff08;如民用无人驾驶航空器实名制登记管…

旧衣回收小程序搭建,开发功能优势

随着人们生活水平、消费水平的提高&#xff0c;在日常生活中产生了大量的限制物品&#xff0c;为了减少浪费&#xff0c;越来越多的人开始重视环保回收。旧衣物作为一种新型的回收方式&#xff0c;也逐渐得到了大众的关注&#xff0c;旧衣物回收市场发展规模也在持续上升&#…

Certbot自动申请并续期https证书

Certbot自动申请并续期https证书 一、 安装 Certbot&#xff1a;使用命令安装 Certbot&#xff1a; dnf install certbot python3-certbot-nginx获取 SSL 证书&#xff1a;运行 Certbot 命令来获取并安装 SSL 证书。 示例命令&#xff0c;替换其中的域名和路径信息&#xff1a…

PHP API 框架:构建高效API的利器【电商API接口】

在当今快速发展的互联网时代&#xff0c;API&#xff08;应用程序编程接口&#xff09;已成为连接不同应用程序和服务的关键。PHP&#xff0c;作为一种流行的服务器端脚本语言&#xff0c;提供了多种强大的框架来简化API的开发。本文将介绍PHP API框架的重要性&#xff0c;以及…

java并发编程笔记 之 线程和进程

文章目录 前言线程线程优先级和时间片创建多线程及运行线程的状态 进程查看进程的命令进程的通信方式 线程和进程的区别从关系上疑问集锦 前言 并发 1、并发是指在同一时间段内&#xff0c;计算机系统能够处理多个任务的能力。 2、在并发编程中&#xff0c;我们可以理解为多个…

chapter17-多线程基础——(自定义泛型)——day20

580-程序进程线程 581-并发并行 并发和并行也可以同时进行 582-继承Thread创建线程 583-多线程机制 主线程和子线程交替执行 单核&#xff1a;两个线程并发 多核&#xff1a;两个线程并行 主线程结束&#xff0c;不是说进程就结束&#xff0c;进程要等所有线程结束 584-为什…

模型Alignment之RLHF与DPO

1. RLHF (Reinforcement Learning from Human Feedback) RLHF 是一种通过人类反馈来强化学习的训练方法&#xff0c;它能够让语言模型更好地理解和执行人类指令。 RLHF 的三个阶段 RLHF 的训练过程一般分为三个阶段&#xff1a; 监督微调&#xff08;Supervised Fine-Tuning,…

认知杂谈82《跳出信息茧房,持续精进》

内容摘要&#xff1a; 互联网时代&#xff0c;信息丰富&#xff0c;但便捷性削弱了我们的好奇心。互联网是双刃剑&#xff0c;快速获取知识的同时&#xff0c;也让我们陷入“信息茧房”&#xff0c;限制视野。 好奇心减少&#xff0c;部分原因是互联网的“懒惰效应”&#xff0…

国家标准和团体标准有什么区别?

国家标准和团体标准的区别主要体现在以下几个方面&#xff1a; 1. 制定标准的主体不同&#xff1a;国家标准是由国家机构通过并公开发布的标准&#xff1b;团体标准是由学会、协会、商会、联合会、产业技术联盟等社会团体协调相关市场主体共同制…

【项目实战】如何在项目中基于 Spring Boot Starter 开发简单的 SDK

什么是SDK 通常在分布式项目中&#xff0c;类和方法是不能跨模块使用的。为了方便开发者的调用&#xff0c;我们需要开发一个简单易用的SDK&#xff0c;使开发者只需关注调用哪些接口、传递哪些参数&#xff0c;就像调用自己编写的代码一样简单。实际上&#xff0c;RPC(远程过…

element下拉框联动 或 多选 回显数据后页面操作不生效问题解决

第一种:多选回显不生效 解决方式: 代码: <el-form-item label"系统" prop"Key"> <el-select v-model"addForm.Key" multiple placeholder"请选择" change"$forceUpdate()"> <el-option v-for"item …

Typescript高级用法

TypeScript 是一种类型安全的 JavaScript 超集&#xff0c;除了基本类型和对象类型之外&#xff0c;TypeScript 还提供了一些高级类型系统&#xff0c;使得我们可以更好地处理复杂的数据结构和业务逻辑。本文将深入探讨 TypeScript 的高级类型系统&#xff0c;以更好地理解和使…