ffmpeg部署和springboot使用

视频存储部署

一、环境安装

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);
	  }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值