ffmpeg部署和springboot使用

2023-05-16

视频存储部署

一、环境安装

1.1 yasm安装

在编译ffmpeg时,执行./configure,报出了如下错误:
“nasm/yasm not found or too old. Use –disable-x86asm for a crippled build.”
需安装yasm解决:

1)可下载安装

1.在http://www.tortall.net/projects/yasm/releases/上下载适合自己的版本
2.解压并进入yasm的目录
3.执行./configure
4.执行make
5.执行sudo make install
安装成功后再在ffmpeg下执行configure即可通过

2)命令行安装

apt-get install yasm/ yum install yasm

1.2 ffmpeg安装

1)可下载安装

1、在官网下载对应版本的ffmpeg
2、解压安装
tar -zxvf ffmpeg-4.4.2.tar.gz 
cd ffmpeg-4.4.2
./configure --prefix=/usr/local/ffmpeg
make && make install
3、配置变量
vi /etc/profile
在最后PATH添加环境变量:
export PATH=$PATH:/usr/local/ffmpeg/bin
保存退出
查看是否生效
source /ect/profile 设置生效
4、查看版本
ffmpeg -version 查看版本

出现“gcc is unable to create an executable file C compiler test failed.”
安装 yum install gccy

好了之后执行cd /usr/local/ffmpeg进入安装目录,查看一下发现有bin,include,lib,share这4个目录,其中bin是ffmpeg主程序二进制目录,include是C/C++头文件目录,lib是编译好的库文件目录,share是文档目录,然后进入bin目录,执行 ./ffmpeg -version 查看当前版本的详细信息,默认情况下一般会报libavdevice.so.57: cannot open shared object file: No such file or directory,原因是lib目录未加载到链接到系统库中,添加库:

添加这些库:vim /etc/ld.so.conf
然后添加一行内容: /usr/local/ffmpeg/lib
之后保存并退出,
然后执行 :sudo ldconfig 重新加载资源
使配置生效,现在再次执行 ./ffmpeg -version 显示就正常了

二、FfmpegUtils工具

2.1 FfmpegUtils代码

import com.zdxf.videostore.utils.video.VideoDesc;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: zj
 * @Date: 2022/3/31 0031 15:40
 * @Description:
 */
@Slf4j
public class FfmpegUtils {

    /**
     * 设置图片大小
     */
    private final static String IMG_SIZE = "1920x1080";
    /**
     * ffmpeg执行目录
     */
    private final String ffmpegPath;

    /**
     * 正则表达式,获取视频的时长、比特率
     */
    private static final Pattern VIDEO_PATTERN = Pattern.compile("Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s");

    public FfmpegUtils(String ffmpegPath) {
        this.ffmpegPath = ffmpegPath;
    }

    /**
     *  合并视频
     * @param txtPath txtPath
     * @param newFilePath 新文件路径
     */
    public  void videoMerge(String txtPath,String newFilePath) {
        // 最好 ffmpeg -f concat -i filelist.txt -c copy output.mkv
        List<String> commands = new ArrayList<>();
        commands.add(ffmpegPath);
        commands.add("-f");
        commands.add("concat");
        commands.add("-safe");
        commands.add("0");
        commands.add("-i");
        commands.add(txtPath);
        commands.add("-c");
        commands.add("copy");
        commands.add("-strict");
        commands.add("-2");
        commands.add(newFilePath);
        log.info("合成视频开始,{},命令:{}", newFilePath, String.join(" ", commands));
        execAndWriteInfo(commands, "videoMerge");
        log.info("合成视频结束,{}", newFilePath);
    }

    /**
     *  执行命令并打印执行信息
     * @param commands 命令
     * @param methodName 方法名
     * @return 命令执行信息
     */
    private static String execAndWriteInfo(List<String> commands, String methodName)  {
        ProcessBuilder builder = new ProcessBuilder().command(commands);
        StringBuilder sb = new StringBuilder();
        try {
            Process process = builder.start();
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            return sb.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("{},err:{}, info:{}",methodName, ex.getMessage(), sb);
        }
        log.info("{},info:{}",methodName, sb);
        return "";
    }

    /**
     *  视频获取截图
     * @param videoPath 视频地址
     * @param imagePath 图片保存地址
     * @param timePoint 截取时间点 秒
     */
    public  void videoToImage(String videoPath, String imagePath, int timePoint) {
        List<String> commands = new ArrayList<>();
        commands.add(ffmpegPath);
        commands.add("-ss");
        // 这个参数是设置截取视频多少秒时的画面
        commands.add(timePoint + "");
        commands.add("-i");
        commands.add(videoPath);
        commands.add("-y");
        commands.add("-f");
        commands.add("image2");
        commands.add("-t");
        commands.add("0.001");
        commands.add("-s");
        //这个参数是设置截取图片的大小
        commands.add(IMG_SIZE);
        commands.add(imagePath);
        log.info("开始截图:{},命令:{}", videoPath, String.join(" ", commands));
        execAndWriteInfo(commands, "videoToImage");
        log.info("完成截图:{}", videoPath);
    }


    /**
     * 获取视频时长
     * @param videoPath 视频路径
     * @return 时长
     */
    public  VideoDesc getVideoDesc(String videoPath) {
        List<String> commands = new java.util.ArrayList<>();
        commands.add(ffmpegPath);
        commands.add("-i");
        commands.add(videoPath);
        log.info("获取视频时长开始:{},命令:{}", videoPath, String.join(" ", commands));
        try {
            String info = execAndWriteInfo(commands, "getVideoDesc");
            //从视频信息中解析时长
            Matcher m = VIDEO_PATTERN.matcher(info);
            if (m.find()) {
                return new VideoDesc(0, 0, m.group(3), videoPath.split("\\.")[1], m.group(1).split("\\.")[0], videoPath);
            }
            log.error("获取视频时长完成e:{}", info);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("获取视频时长完成:{}", videoPath);
        return null;
    }

    /**
     *  转换格式
     * @param videoPath 视频路径
     * @param outPath 输出路径
     */
    public  boolean videoChangeFormat(String videoPath, String outPath) {
        // ffmpeg -f h264 -i 1.dav -c copy test.mp4
        // `ffmpeg -i "车载录像20150320.dav" -vcodec copy -acodec copy "车载录像20150320.mp4"`
        List<String> commands = new ArrayList<>();
        commands.add(ffmpegPath);
//        commands.add("-f");
//        commands.add("-h264");
        commands.add("-i");
        commands.add(videoPath);
        commands.add("-vcodec");
        commands.add("copy");
        commands.add("-acodec");
        commands.add("copy");
        commands.add(outPath);
        log.info("转换格式开始:{},命令:{}", videoPath, String.join(" ", commands));
        execAndWriteInfo(commands, "videoChangeFormat");
        log.info("转换格式完成:{}", videoPath);
        return false;
    }


    /**
     * 视频抽取音频文件
     * @param videoPath 视频路径
     * @param type  文件类型
     * @param audioPath 文件保存路径
     * @return 是否成功
     */
    public  boolean videoToAudio(String videoPath, String type, String audioPath){
        List<String> commands = new ArrayList<>();
        commands.add(ffmpegPath);
        commands.add("-i");
        commands.add(videoPath);
        commands.add("-f");
        commands.add(type);
        commands.add("-vn");
        commands.add("-y");
        commands.add("-acodec");
        if("wav".equals(type)){
            commands.add("pcm_s16le");
        }else if("mp3".equals(type)){
            commands.add("mp3");
        }
        commands.add("-ar");
        commands.add("16000");
        commands.add("-ac");
        commands.add("1");
        commands.add(audioPath);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commands);
            Process p = builder.start();

            // 1. start
            // 保存ffmpeg的输出结果流
            BufferedReader buf;
            String line;
            buf = new BufferedReader(new InputStreamReader(p.getInputStream()));
            StringBuffer sb = new StringBuffer();
            while ((line = buf.readLine()) != null) {
                System.out.println(line);
                sb.append(line);
            }
            // 这里线程阻塞,将等待外部转换进程运行成功运行结束后,才往下执行
            p.waitFor();
            // 1. end
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * wav 转 mp3
     * wav转mp3命令:ffmpeg -i test.wav -f mp3 -acodec libmp3lame -y wav2mp3.mp3
     * @param wavPath wav路径
     * @param mp3Path MP3路径
     * @return 是否成功
     */
    public  boolean ffmpegOfWavToMp3(String wavPath, String mp3Path){
        List<String> commands = new java.util.ArrayList<>();
        commands.add(ffmpegPath);
        commands.add("-i");
        commands.add(wavPath);
        commands.add("-f");
        commands.add("mp3");
        commands.add("-acodec");
        commands.add("libmp3lame");
        commands.add("-y");
        commands.add(mp3Path);
        try {
            // 1. start
            // 保存ffmpeg的输出结果流
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commands);
            Process p = builder.start();
            BufferedReader buf = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = buf.readLine()) != null) {
                sb.append(line);
            }
            // 这里线程阻塞,将等待外部转换进程运行成功运行结束后,才往下执行
            p.waitFor();
            // 1. end
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }



    public static void main(String[] args) throws InterruptedException {
        String path = "ffmpeg";
        String outputPath = "E:\\video\\0000000001210\\0000000001210.mp4";
        String filePath1 = "E:\\video\\0000000001005\\0000000001005_task990-648.flv";
        String outPath1 = "E:\\video\\0000000001005\\0000000001005_task990-648.mp4";
        String imagePath = "E:\\video\\0000000001005\\0000000001005.jpg";
        String txtFilePath = "E:\\video\\0000000001005\\0000000001005.txt";
        // FfmpegUtils.videoMerge(txtFilePath, outputPath);

        //FfmpegUtils.videoToImage(outputPath, imagePath, 0);
        FfmpegUtils ffmpegUtils = new FfmpegUtils("ffmpeg");
        // ffmpegUtils.videoChangeFormat(filePath1, outPath1);
        //TimeUnit.MILLISECONDS.sleep(240);
        System.out.println(ffmpegUtils.getVideoDesc(outputPath));
    }
}

2.2 springboot配置使用

@Slf4j
@Service
public class VideoStoreServiceImpl  implements VideoStoreService {
	private final FfmpegUtils ffmpegUtils;
	public VideoStoreServiceImpl(@Value("${ffmpeg.path}")  String ffmpegPath) {
        this.ffmpegUtils = new FfmpegUtils(ffmpegPath);
        ffmpegUtils.videoMerge(txtFilePath, outputPath);
	  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ffmpeg部署和springboot使用 的相关文章

随机推荐

  • RabbitMQ

    什么是 RabbitMQ xff1f RabbitMQ 是使用 Erlang 语言来编写的 xff0c 并且是基于 AMQP 协议 最大的特点就是 消费并不需要确保提供方存在 xff0c 实现了服务之间的高度解耦 AMQP xff1a Ad
  • word批量设置图片大小和对齐,使用宏定义

    word使用宏定义来批量设置图片大小 打开word中开发工具 xff0c 文件 选项 word选项 新建Visual Basic文件 点击 插入 模块 复制下列任意代码 xff0c 粘贴到右侧 xff08 注意可以灵活设置Myheigth或
  • postman设置不更新

    一 关闭自动更新目前有两种方案 xff1a 第一种 xff1a Hosts文件配置以下地址屏蔽连接 xff1a 1 以下配置粘贴到文件中 xff0c 文件位置 xff1a C Windows System32 drivers etc 0 0
  • ECharts多个折线图动态获取json数据

    ECharts 多个折线图动态获取json数据 效果图如下 xff1a 一 html部分 lt p id 61 34 TwoLineChart 34 style 61 34 width 100 height 400px 34 gt lt p
  • JS中setTimeout()的用法详解

    setTimeout 是属于 window 的 method 但我们都是略去 window 这顶层物件名称 这是用来设定一个时间 时间到了 就会执行一个指定的 method 1 SetTimeOut 1 1 SetTimeOut 语法例子
  • Java写个程序00001递增到99999

    NumberFormat f 61 new DecimalFormat 34 00000 34 for int i 61 1 i lt 10000 i 43 43 System out println f format i ER 00001
  • JQuery判断数组中是否包含某个元素

    inArray 34 元素字符串 34 数组名称 var arry 61 34 C 34 34 html 34 34 css 34 34 JavaScript 34 var result 61 inArray 34 C 34 arry 如果
  • JSP获得当前时间并显示

    lt 64 page import 61 34 java text SimpleDateFormat 34 gt lt 64 page import 61 34 java util 34 gt lt 64 page language 61
  • js 判断字符串是否包含另外一个字符串

    lt script type 61 34 text javascript 34 gt var str 61 34 测试一个字符串 ehtrzes 是否包含另外一个字符串 34 if str indexOf 34 ehtrzes 34 gt
  • js判断函数是否存在、判断是否为函数

    lt script type 61 34 text javascript 34 gt 判断是否为函数 try if typeof FunName 61 61 61 34 function 34 是函数 其中 FunName 为函数名称 al
  • python中的类和对象,属性和方法

    一 面向对象的概述 面向对象是一种描述业务问题 设计业务实体和实体之间关系的方法 二 类和对象 1 类和对象得区别 xff1a 类是对客观世界中事物得抽象 xff0c 而对象是类实例化后的实体 例如 xff1a 汽车模型就是一个类 xff0
  • 什么是“约瑟夫环”

    今天遇到一个关于 约瑟夫环 的问题 xff0c 于是上网查了下什么是 约瑟夫环 出自百度 xff1a 约瑟夫问题 xff08 有时也称为约瑟夫斯置换 xff0c 是一个出现在计算机科学和数学中的问题 在计算机编程的算法中 xff0c 类似问
  • 使用Fontcreator字体制作软件及字体设计学习

    fontcreator对于字体修改爱好者而言是一款极好的文字编辑工具 xff0c 门槛要求低 专业性强 集设计和修改为一体 xff0c 可用来制作 编辑 修改ttf xff0c otf xff0c ttc格式的字体文件 xff0c 非常的实
  • 远程连接centos 7 图形化桌面

    使用xrdp工具 xff0c 类似windows系统的远程桌面 xff08 rdp xff09 xff0c 需要在服务端安装远程桌面服务 如果你的服务器可以使用阿里的yum源 xff0c 可以直接使用epel仓库安装 xff0c 执行以下命
  • selinux - Android编写sepolicy

    为service编写sepolicy 由init启动的service服务要在各自的selinux domain中运行 具体flow如下 init devices rc中声明service xff0c 将在init时启动 xff1a Note
  • Spring Boot结合easyExcel实现自增序号

    有些业务功能要求能导出序号 xff0c 现在提供两种实现方式 通过mysql查询实现 xff1b 实现RowWriteHandler接口 xff0c 自定义拦截器 xff1b 一 通过mysql查询实现 通过自定义变量实现每行数据 43 1
  • Spring Boot 实体里的List集合参数验证

    Spring Boot 实体里的List集合参数验证 Spring Boot 通过Hibernate Validator 加验证大家都知道 不知道的话可以参考这篇文章SpringBoot里参数校验 参数验证 今天讲一下Spring Boot
  • 树形结构工具类,如:菜单、部门等

    1 树节点 span class token keyword package span span class token namespace com span class token punctuation span zjson span
  • EasyPoiUtil导出工具

    span class token keyword package span span class token namespace com span class token punctuation span zjson span class
  • ffmpeg部署和springboot使用

    视频存储部署 一 环境安装 1 1 yasm安装 在编译ffmpeg时 xff0c 执行 configure xff0c 报出了如下错误 xff1a nasm yasm not found or too old Use disable x8