一. windows使用

1. 安装包

链接:https://pan.baidu.com/s/1igxky8Wxhd5wFRLN9_YSgA 
提取码:0qo8

ffmpeg-2021-12-12-git-996b13fac4-full_build.7z 解压

java 视频加字幕 java 视频加水印_java

 

bin路径下:

java 视频加字幕 java 视频加水印_ide_02

 

2. 工具类

java 视频加字幕 java 视频加水印_ide_03

java 视频加字幕 java 视频加水印_java 视频加字幕_04

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * @ClassName: ResultStreamHandler
 * @Description 
 * @Author: 王志亭
 * @Date: 2021-12-16 16:31
 * @Version 1.0
 **/
public class ResultStreamHandler implements Runnable{
    private InputStream inputStream;

    ResultStreamHandler(InputStream inputStream ) {
        this.inputStream = inputStream;
    }

    public void run() {

        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader( new InputStreamReader( inputStream,"utf-8" ) );
            String line = null;

            while ( ( line = bufferedReader.readLine() ) != null ) {
                System.out.println( line );
            }
        }
        catch ( Throwable t ) {
        }
        finally {
            try {
                bufferedReader.close();
            }
            catch ( IOException e ) {
            }
        }
    }

    /**
     * 处理process输出流和错误流,防止进程阻塞
     * 在process.waitFor();前调用
     * @param process
     */
    public static void dealStream(Process process) {
        if (process == null) {
            return;
        }

        // 处理InputStream的线程
        new Thread() {
            @Override
            public void run() {
                System.out.println("run 111111111");
                BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line = null;
                try {
                    while ((line = in.readLine()) != null) {
                        // logger.info("output: " + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        // 处理ErrorStream的线程
        new Thread() {
            @Override
            public void run() {
                System.out.println("run 222222222");
                BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String line = null;
                try {
                    while ((line = err.readLine()) != null) {
                        //  logger.info("err: " + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        err.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

}

ResultStreamHandler 工具类

java 视频加字幕 java 视频加水印_ide_03

java 视频加字幕 java 视频加水印_java 视频加字幕_04

public interface CmdOutputGetter {
    public void dealLine(String str);
}

CmdOutputGetter

java 视频加字幕 java 视频加水印_ide_03

java 视频加字幕 java 视频加水印_java 视频加字幕_04

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * @ClassName: CmdExecutor
 * @Description FFmpeg 脚本命令执行器
 * @Author: 王志亭
 * @Date: 2021-12-18 15:17
 * @Version 1.0
 **/
@Slf4j
public class CmdExecutor {

    /**
     * CMD操作
     * @param getter 获取控制台打印信息
     * @param cmd 命令
     */
    public static void exec(CmdOutputGetter getter, String... cmd) {
        try {
            // 创建新线程
            ProcessBuilder builder = new ProcessBuilder();
            // 执行命令
            builder.command(cmd);
            builder.redirectErrorStream(true);
            Process proc = builder.start();
            BufferedReader stdout = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line;
            while ((line = stdout.readLine()) != null) {
                if (getter != null)
                    getter.dealLine(line);
            }
            proc.waitFor();
            stdout.close();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}

CmdExecutor 工具类

java 视频加字幕 java 视频加水印_ide_03

java 视频加字幕 java 视频加水印_java 视频加字幕_04

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName: FFmpegUtil
 * @Description ffmpeg 工具类
 * @Author: 王志亭
 * @Date: 2022-04-09 15:09
 * @Version 1.0
 **/
@Slf4j
@Service("ffmpegUtil")
public class FFmpegUtil {
    @Value("${ffmpeg.file}")
    private String FFMPEG_FILE;

    // 视频水印文件路径
    @Value("${ffmpeg.video.water.file}")
    private String VIDEO_WATER_FILE;

    // 音频水印文件路径
    @Value("${ffmpeg.audio.water.file}")
    private String AUDIO_WATER_FILE;

    // 图片水印
    @Value("${ffmpeg.images.water.file}")
    private String IMAGES_WATER_FILE;
    

    /**
     * @Author: 王志亭
     * @Description: 图片添加图片水印
     * scale=180:136 水印文件宽高
     * 图片水印的矩阵坐标设置
     * “overlay=10:main_h-overlay_h-10";    //左下
     *
     *  "overlay=main_w/2-overlay_w/2:main_h-overlay_h-10"; //正下
     *
     *  "overlay=main_w-overlay_w-10:main_h-overlay_h-10";  //右下
     *
     *  "overlay=10:main_h/2-overlay_h/2";  //中左
     *
     *  "overlay=main_w/2-overlay_w/2:main_h/2-overlay_h/2";  //正中
     *
     *  "overlay=main_w-overlay_w-10:main_h/2-overlay_h/2";  //中右
     *
     * "overlay=10:10";  //左上
     *
     * "overlay=main_w/2-overlay_w/2:10";  //正上
     *
     *  "overlay=main_w-overlay_w-10:10";  //右上
     * @Date: 2022-4-13 15:03
     * @return void
     **/
    public boolean imagesShuiyin(String imagesFile, String imagesWaterFile){
        String cmd = FFMPEG_FILE + " -i " + addQuotes(imagesFile) + " -vf \"movie=" + IMAGES_WATER_FILE + ",scale=180:136[watermask];[in][watermask] overlay=main_w-overlay_w-10:10[out]\" -y " + addQuotes(imagesWaterFile);
//        String cmd = FFMPEG_FILE + " -i " + addQuotes(imagesFile) + " -vf \"movie=C\\\\:/waterfile.png,scale=180:136[watermask];[in][watermask] overlay=main_w-overlay_w-10:10[out]\" -y " + addQuotes(imagesWaterFile);
        System.out.println("cmd *********************** " + cmd);
        boolean flag = generalCommand(cmd);

        return flag;
    }

    /**
     * @Author: 王志亭
     * @Description: 音频添加水印 新版本
     * @Date: 2022-4-9 17:52
     * @param audioFile: 源音频文件
     * @param audioWaterFile: 添加水印后的音频文件
     * @return void
     **/
    public boolean audioShuiYinNew(String audioFile, String audioWaterFile){
        String cmd = FFMPEG_FILE  + " -i " + addQuotes(audioFile) + " -i " + addQuotes(AUDIO_WATER_FILE)
                + " -filter_complex \"[0:0] [1:0] concat=n=2:v=0:a=1 [a]\" -map \"[a]\" \"-ar\" 48000 -y "
                + addQuotes(audioWaterFile);

        boolean flag = generalCommand(cmd);

        return flag;
    }

    /**
     * @Author: 王志亭
     * @Description: 音频添加水印 == 旧版
     * @Date: 2022-4-9 17:14
     * @param audioFile: 源音频文件
     * @param audioWaterFile: 添加水印后的音频文件
     * @return void
     **/
    public  void audioShuiYinOld(String audioFile, String audioWaterFile){
        String[] command4concat = {FFMPEG_FILE, " -i ", AUDIO_WATER_FILE.replaceAll(" ","\" \""), "-i", audioFile.replaceAll(" ","\" \""), "-filter_complex",
                "[0:0] [1:0] concat=n=2:v=0:a=1 [a]", "-map", "[a]", "-ar", "48000", audioWaterFile, "-y"};

        CmdExecutor.exec(new CmdOutputGetter() {
            @Override
            public void dealLine(String line) {
                //把cmd输出的信息每行syso,这个是实时输出的,可以换其他的处理方式
                System.out.println(line);
            }
        }, command4concat);

        log.info("水印连接「{}秒」间隔音频完成!");

    }

    /**
     * @Author: 王志亭
     * @Description: 视频 添加水印
     * @Date: 2021-12-19
     * @param input_path: 源文件路径
     * @param video_converted_path: 添加水印后的视频路径
     * @return void
     **/
    public boolean videoShuiYin(String input_path, String video_converted_path) {
        HashMap<String, String> dto=new HashMap<String, String>();
        dto.put("ffmpeg_path",FFMPEG_FILE);//必填:此处是ffmpeg.exe所在位置,也就FFmpeg文件夹bin目录下的ffmpeg.exe
        dto.put("input_path", input_path);//必填;此处是你要处理的视频位置
        dto.put("video_converted_path", video_converted_path);//必填;此处是完成添加水印后输入视频的位置并重新命名该视频
        dto.put("logo", VIDEO_WATER_FILE);//必填;此处是你要添加的水印位置,注意此处图片位置一定要加上转译符,否则识别不了盘符
        boolean flag = execute(dto);

        return flag;
    }

    /**
     * @Author: 王志亭
     * @Description: 视频添加水印
     * @Date: 2021-12-23 17:37
     * @param dto:
     * @return void
     **/
    private boolean execute(Map<String,String> dto)
    {
        StringBuffer waterlogo = new StringBuffer();
        waterlogo.append(" -i ");
        if(null!=dto.get("input_path")&& org.apache.commons.lang.StringUtils.isNotEmpty(dto.get("input_path"))){
            waterlogo.append(addQuotes(dto.get("input_path")));
        }
        waterlogo.append("  -vf \"movie=");
        String xaxis = "main_w-overlay_w-10";
        String yaxis = "10";
        if (null!=dto.get("logo")&& org.apache.commons.lang.StringUtils.isNotEmpty(dto.get("logo"))){
            waterlogo.append(dto.get("logo"));
        }

        waterlogo.append(",scale= 60: 30");
        waterlogo.append(" [watermark]; [in][watermark] overlay=main_w-overlay_w-5:5 [out]\" -y ");
        if (null!=dto.get("video_converted_path")&& org.apache.commons.lang.StringUtils.isNotEmpty(dto.get("video_converted_path"))){
            waterlogo.append(addQuotes(dto.get("video_converted_path")));
        }

        String ffmegPath = null;
        if (StringUtils.isNotEmpty(dto.get("ffmpeg_path"))){
            ffmegPath = dto.get("ffmpeg_path");
        }

        System.out.println("ffmegPath+waterlogo ===== " + ffmegPath+waterlogo);
        boolean flag = generalCommand(ffmegPath + waterlogo);

        return flag;

    }

    /**
     * @Author: 王志亭
     * @Description: 文件路径出现空格  处理方式
     * @Date: 2021-12-23 16:05
     * @param in: 文件路径
     * @return java.lang.String
     **/
    public static String addQuotes(String in ) {
        return "\"" + in + "\"";
    }

    /**
     * @Author: 王志亭
     * @Description: 通用命令
     * @Date: 2021-12-23 17:35
     * @param command: ffmpeg 命令
     * @return void
     **/
    public boolean generalCommand(String command){
        boolean flag = false;
        Runtime run = Runtime.getRuntime();

        InputStream inputStream = null;
        InputStream errorStream = null;
        try {
            java.lang.Process process = run.exec(command);
// 异步读取输出
            inputStream = process.getInputStream();
            errorStream = process.getErrorStream();

            ExecutorService service = Executors.newFixedThreadPool(2);

            ResultStreamHandler inputStreamHandler = new ResultStreamHandler(inputStream);
            ResultStreamHandler errorStreamHandler = new ResultStreamHandler(errorStream);

            service.execute(inputStreamHandler);
            service.execute(errorStreamHandler);

            new Thread(errorStreamHandler, "error stream").start();
            new Thread(inputStreamHandler, "output stream").start();
            process.waitFor();
            service.shutdownNow();
            flag = true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            try {
                errorStream.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        return flag;
    }
}

FFmpegUtil 工具类

3. application.yml 配置文件中添加 ffmpeg 

# ffmpeg 路径
ffmpeg:
  file: E:\wangzhiting\FFmpeg\bin\ffmpeg.exe
  # 视频水印文件路径
  video:
    water:
      file: C\\:/water.png
  # 音频水印文件路径
  audio:
    water:
      file: E:\音频水印.mp3
  # 图片水印文件路径  注意:路径 两个反斜杠必须添加
  images:
    water:
      file: C\\:/waterfile.png

* 注意:在windows下使用图片、视频文件添加图片水印时 盘符路径下必须添加两个反斜杠(\\)例如:C\\:/

4. 注意事项

(1)水印添加完的文件自动生成,ffmpeg命令执行之前生成文件会报错。

例如:如下代码

audioWaterFile:c:/file/1238795.jpg  中
1238795.jpg 文件是自动生成的,
c:/file/ 必须事先生成,不然会报文件或文件夹不存在
public boolean audioShuiYinNew(String audioFile, String audioWaterFile){
        String cmd = FFMPEG_FILE  + " -i " + addQuotes(audioFile) + " -i " + addQuotes(AUDIO_WATER_FILE)
                + " -filter_complex \"[0:0] [1:0] concat=n=2:v=0:a=1 [a]\" -map \"[a]\" \"-ar\" 48000 -y "
                + addQuotes(audioWaterFile);

        boolean flag = generalCommand(cmd);

        return flag;
    }

解决:可以添加 -y 解决文件

java 视频加字幕 java 视频加水印_java_11

 

 

 -y: 覆盖文件

二. linux 使用

1. 安装包

链接:https://pan.baidu.com/s/1PshVBEZ4W4eDqEXxsAw2uw 
提取码:jr51

ffmpeg-4.4.tar.gz  解压后的文件

java 视频加字幕 java 视频加水印_ide_12

 

 

 

前期准备:
在/usr/local/下新建一个ffmpeg的文件夹,并进入到ffmpeg文件夹;
安装gcc(yum install -y gcc)工具;
安装wget(yum -y install wget)工具;
安装(vim)yum install -y vim;
安装ffmpeg

①:将ffmpeg-4.1.3.tar.bz2上传到ffmpeg文件夹下

②:tar -xjvf ffmpeg-4.1.3.tar.bz2

③: cd ffmpeg-4.1.3

④:./configure --enable-shared --prefix=/monchickey/ffmpeg

⑤:make(花费时间会有点长)

⑥:make install

ffmpeg安装完毕
ffmpeg文件
查看一下发现有bin、include、lib、share这4个目录,其中bin是ffmpeg主程序二进制目录,include是C/C++头文件目录,lib是编译好的库文件目录,share是文档目录
配置ffmpeg的环境变量

①:完成以上步奏之后,还不能直接在linux任何位置使用ffmpeg命令,因为还没有配置ffmpeg环境变量,所以这里在原文基础上,新增环境变量这一步;

②:切换root用户,执行命令:"vim /etc/profile";在文件末尾加上下面的命令行:
#set my ffmpeg environment
export PATH=$PATH:/monchickey/ffmpeg/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/monchickey/ffmpeg/lib

  ③:然后执行生效命令:"source /etc/profile";

  ④:最后测试一下是否已经生效,在随便一个路径下执行命令:"ffmpeg -version";出现以下版本信息,说明ffmpeg环境变量配置成功,可直接在linux使用命令调用ffmpeg程序;

 

java 视频加字幕 java 视频加水印_java_13

 

 

 2. 使用方法跟windows不同的地方

(1)application.yml     ffmpeg 配置 

# ffmpeg 路径
ffmpeg:
  file: /usr/local/ffmpeg/bin/ffmpeg
  # 视频水印文件路径
  video:
    water:
      file: /usr/local/tomcat-news-server/water.png
  audio:
    water:
      file: /usr/local/tomcat-news-server/音频水印.mp3
  images:
    water:
      file: /usr/local/tomcat-news-server/waterfile.png

(2)FFmpegUtil 工具类中的  public boolean generalCommand(String command) 方法

windows 下的是:

java 视频加字幕 java 视频加水印_System_14

 

 

linux 下 是:

java 视频加字幕 java 视频加水印_java_15

 

java 视频加字幕 java 视频加水印_ide_03

FFmpegUtil  linux 下使用 工具类