ffmpeg使用及java操作

1.文档

官网: FFmpeg
官方使用文档: ffmpeg Documentation

中文简介: https://www.cnblogs.com/leisure_chn/p/10297002.html

函数及时间: ffmpeg日记1011-过滤器-语法高阶,逻辑,函数使用_ffmpeg gte(t,2)-CSDN博客

java集成ffmpeg: SpringBoot集成ffmpeg实现视频转码播放_jave-all-deps-CSDN博客 

2.命令

快速复制视频片段
ffmpeg -ss 00:00:40 -i test.mp4 -to 00:01:00 -c:v copy -c:a copy  testOutput40.mp4

复制视频片段,并调整视频质量,crf一般为23,crf越大压缩越厉害,质量下降越多
ffmpeg -i test.mp4 -ss 00:30 -to 00:50 -c:v libx264 -crf 23 newTest1.mp4

调整视频分辨率(调整的分辨率超过原来的,不能提升画质)
ffmpeg -i test.mp4 -vf scale=432:240 video_240p.mp4 -hide_banner
ffmpeg -i test.mp4 -vf scale=-1:240 video_240p.mp4 -hide_banner

加水印(10:10水印距离左上角的像素距离)
ffmpeg -i test.mp4 -i used100.png -filter_complex "overlay=10:10" testOutputWater.mp4

--保真加水印,不怎么改变视频编码及质量
ffmpeg -i test.mp4 -i used100.png -filter_complex "overlay=10:10" -c:v libx264 -c:a copy testOutputWater2.mp4

--视频2秒后开始显示水印,gte(t\,2)
ffmpeg -i test.mp4 -vf "movie=used100.png[logo];[in][logo]overlay=x='if(gte(t\,2)\,0\,NAN)'" testOutputWater6.mp4

--在指定时间范围(20-30秒)显示水印,between(t\,20\,30)
ffmpeg -i test.mp4 -vf "movie=used100.png[logo];[in][logo]overlay=x='if(between(t\,20\,30)\,0\,NAN)'" testOutputWater9.mp4

加硬字幕
ffmpeg -i test.mp4 -vf subtitles=test.srt mp4_add_captions1.mp4

3.java代码

        maven依赖,使用集成的ffmpeg程序,缺点是打成的jar包很大,优点是不需要手动安装ffmpeg

        <!--   音视频   -->
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-all-deps</artifactId>
            <version>3.0.1</version>
            <exclusions>
                <!--  排除windows 32位系统      -->
                <exclusion>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-win32</artifactId>
                </exclusion>
                <!--  排除linux 32位系统      -->
                <exclusion>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-linux32</artifactId>
                </exclusion>
                <!-- 排除Mac系统-->
                <exclusion>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-osx64</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

          第二种方式,不引入集成的ffmpeg,手动在程序运行的服务器上安,优点是打成的jar包较小,关于如何手动在服务器上配置ffmpeg,请见附录2

        <!--音视频操作-->
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-core</artifactId>
            <version>3.0.1</version>
        </dependency>

        工具类

package mis.shared.file;

import lombok.extern.slf4j.Slf4j;
import ws.schild.jave.Encoder;
import ws.schild.jave.EncoderException;
import ws.schild.jave.MultimediaObject;
import ws.schild.jave.encode.AudioAttributes;
import ws.schild.jave.encode.EncodingAttributes;
import ws.schild.jave.encode.VideoAttributes;
import ws.schild.jave.info.MultimediaInfo;
import ws.schild.jave.process.ProcessWrapper;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;

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

/**
 * 音视频操作
 *
 * @since 2024/1/22
 */
@Slf4j
public class FfmpegUtil {

    /**
     * 通过本地路径获取多媒体文件信息(宽,高,时长,编码等)
     *
     * @param localPath 文件路径
     * @return MultimediaInfo 媒体对象,包含 (宽,高,时长,编码等)
     */
    public static MultimediaInfo GetMediaInfo(String localPath) {
        MultimediaInfo multimediaInfo = null;
        try {
            multimediaInfo = new MultimediaObject(new File(localPath)).getInfo();
        } catch (EncoderException e) {
            log.error("获取媒体信息异常!", e);
        }
        return multimediaInfo;
    }

    /**
     * 修改视频分辨率,修改分辨率超过原视频,不能提高画质
     * 标清SD(Standard Definition) 宽 x 高
     * 480p 640x480 704x480 720x480 848x480
     * 高清 HD(High Definition)
     * 720p 960x720 1280x720
     * 1080p 1440x1080 1920x1080
     * 超高清UHD(Ultra High Definition)
     * 4k 4096×3112 4096*2160
     *
     * @param inputPath  视频来源地址
     * @param outputPath 输出视频地址
     * @param width      宽度
     * @param height     高度
     */
    public static boolean ChangeScale(String inputPath, String outputPath, int width, int height) {
        ProcessWrapper ffmpeg = null;
        try {
            if (new File(outputPath).exists()) {
                log.error("目标文件已存在,outputPath:{}", outputPath);
                return false;
            }

            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(inputPath);
            ffmpeg.addArgument("-vf");
            ffmpeg.addArgument("scale=" + width + ":" + height);
            ffmpeg.addArgument("-c:a");
            ffmpeg.addArgument("copy");
            ffmpeg.addArgument(outputPath);
            long start = System.currentTimeMillis();
            //异步执行
            ffmpeg.execute();
            //等待完成
            WaitFfmpegFinish(ffmpeg);
            log.info("花费时间:{}", System.currentTimeMillis() - start);
            return true;
        } catch (Exception e) {
            log.error("修改视频画质异常", e);
        } finally {
            if (ffmpeg != null) {
                ffmpeg.destroy();
            }
        }
        return false;
    }

    /**
     * 复制视频片段
     *
     * @param inputPath  视频来源地址
     * @param outputPath 输出视频地址
     * @param startTime  开始时间,01:02:03在视频的第1小时第2分钟第3秒处
     * @param endTime    结束时间,格式同startTime
     */
    public static boolean CopyVideo(String inputPath, String outputPath, String startTime, String endTime) {
        ProcessWrapper ffmpeg = null;
        try {
            if (new File(outputPath).exists()) {
                log.error("目标文件已存在,outputPath:{}", outputPath);
                return false;
            }

            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-ss");
            ffmpeg.addArgument(startTime);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(inputPath);
            ffmpeg.addArgument("-to");
            ffmpeg.addArgument(endTime);
            ffmpeg.addArgument("-c:v");
            ffmpeg.addArgument("copy");
            ffmpeg.addArgument("-c:a");
            ffmpeg.addArgument("copy");
            ffmpeg.addArgument(outputPath);
            long start = System.currentTimeMillis();
            //异步执行
            ffmpeg.execute();
            //等待完成
            WaitFfmpegFinish(ffmpeg);
            log.info("花费时间:{}", System.currentTimeMillis() - start);
            return true;
        } catch (Exception e) {
            log.error("复制视频片段异常", e);
        } finally {
            if (ffmpeg != null) {
                ffmpeg.destroy();
            }
        }
        return false;
    }

    /**
     * 视频格式转换为mp4
     */
    public static boolean FormatToMp4(String localPath, String outputPath) {
        try {
            File target = new File(outputPath);
            if (target.exists()) {
                log.error("目标文件已存在,outputPath:{}", outputPath);
                return false;
            }

            MultimediaObject multimediaObject = new MultimediaObject(new File(localPath));
            EncodingAttributes attributes = new EncodingAttributes();
            // 设置视频的音频参数
            AudioAttributes audioAttributes = new AudioAttributes();
            attributes.setAudioAttributes(audioAttributes);
            // 设置视频的视频参数
            VideoAttributes videoAttributes = new VideoAttributes();
            // 设置帧率
            videoAttributes.setFrameRate(25);
            attributes.setVideoAttributes(videoAttributes);
            // 设置输出格式
            attributes.setOutputFormat("mp4");
            Encoder encoder = new Encoder();
            encoder.encode(multimediaObject, target, attributes);
            return true;
        } catch (Exception e) {
            log.error("视频转换异常!", e);
            return false;
        }
    }

    /**
     * 获取视频缩略图
     * 获取视频第0秒的第一帧图片
     */
    public static boolean GetThumbnail(String localPath, String outputPath) {
        ProcessWrapper ffmpeg = null;
        try {
            File target = new File(outputPath);
            if (target.exists()) {
                log.error("目标文件已存在,outputPath:{}", outputPath);
                return false;
            }

            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(localPath);
            ffmpeg.addArgument("-ss");
            ffmpeg.addArgument("0");
            ffmpeg.addArgument(outputPath);
            ffmpeg.execute();

            //等待执行完成
            WaitFfmpegFinish(ffmpeg);
        } catch (Exception e) {
            log.error("获取视频缩略图异常", e);
            return false;
        } finally {
            if (ffmpeg != null) {
                ffmpeg.destroy();
            }
        }
        return true;
    }

    /**
     * 等待命令执行完成
     */
    private static void WaitFfmpegFinish(ProcessWrapper processWrapper) throws Exception {
        //输出执行情况不是通过inputStream,而是errorStream
        try (BufferedReader br = new BufferedReader(new InputStreamReader(processWrapper.getErrorStream()))) {
            String processInfo;
            while ((processInfo = br.readLine()) != null) {
                //打印执行过程
                log.trace(processInfo);
            }
        } catch (Exception e) {
            log.error("等待执行完成异常!", e);
        }
    }

    public static void main(String[] args) {
        String inputFile = "e://develop//tmp//test.mp4";
        String outputFile = "e://develop//tmp//testOutput14.mp4";

        //复制视频指定片段
        CopyVideo(inputFile, outputFile, "00:00:10", "00:01:00");

        //获取媒体信息
        // MultimediaInfo multimediaInfo = GetMediaInfo(inputFile);
        // log.info("文件信息:{}", multimediaInfo);
        // VideoSize videoSize = multimediaInfo.getVideo().getSize();
        // log.info("文件信息,宽:{},高:{}", videoSize.getWidth(), videoSize.getHeight());

        //修改视频画质
        //ChangeScale(inputFile, outputFile, 640, 480);
    }

}

附录1

         字幕test.srt

1
00:00:20,000 --> 00:00:30,000
这是视频第20秒到30秒将显示的字幕

2
00:00:50,000 --> 00:00:60,000
这是视频第50秒到60秒将显示的字幕

附录2

        关于ffmpeg在服务器上的位置,参考如下代码

  public DefaultFFMPEGLocator() {
    String os = System.getProperty("os.name").toLowerCase();
    boolean isWindows = os.contains("windows");
    boolean isMac = os.contains("mac");
    LOG.debug("Os name is <{}> isWindows: {} isMac: {}", os, isWindows, isMac);

    // Dir Folder
    File dirFolder = new File(System.getProperty("java.io.tmpdir"), "jave/");
    if (!dirFolder.exists()) {
      LOG.debug(
          "Creating jave temp folder to place executables in <{}>", dirFolder.getAbsolutePath());
      dirFolder.mkdirs();
    } else {
      LOG.debug("Jave temp folder exists in <{}>", dirFolder.getAbsolutePath());
    }

    // -----------------ffmpeg executable export on disk.-----------------------------
    String suffix = isWindows ? ".exe" : (isMac ? "-osx" : "");
    String arch = System.getProperty("os.arch");

    // File
    File ffmpegFile = new File(dirFolder, "ffmpeg-" + arch + "-" + Version.getVersion() + suffix);
    LOG.debug("Executable path: {}", ffmpegFile.getAbsolutePath());

    // Check the version of existing .exe file
    if (ffmpegFile.exists()) {
      // OK, already present
      LOG.debug("Executable exists in <{}>", ffmpegFile.getAbsolutePath());
    } else {
      LOG.debug("Need to copy executable to <{}>", ffmpegFile.getAbsolutePath());
      copyFile("ffmpeg-" + arch + suffix, ffmpegFile);
    }

    // Need a chmod?
    if (!isWindows) {
      try {
        Runtime.getRuntime().exec(new String[] {"/bin/chmod", "755", ffmpegFile.getAbsolutePath()});
      } catch (IOException e) {
        LOG.error("Error setting executable via chmod", e);
      }
    }

    // Everything seems okay
    path = ffmpegFile.getAbsolutePath();
    if (ffmpegFile.exists())
    {
        LOG.debug("ffmpeg executable found: {}", path);
    }
    else
    {
        LOG.error("ffmpeg executable NOT found: {}", path);
    }
  }

       windows环境,打开cmd窗口,执行echo %TEMP%获取临时文件夹,打开临时文件夹,创建子文件夹jave(最终路径例子C:\Users\TN\AppData\Local\Temp\jave)

        下载ws.schild的maven对应系统jar包,并解压jave-nativebin-win64-3.0.1,找到里面的ffmpeg-amd64.exe复制到上面的目录下

         linux通过脚本获取默认目录,原理是通过编译运行FfmpegHelper.java获得

#!/bin/bash

cd /tmp

# download 
if [ -e "/tmp/FfmpegHelper.java" ]
then
    echo "FfmpegHelper.java already exist!"
else
    echo "FfmpegHelper.java does not exist,start download"
    wget https://fs-im-kefu.7moor-fs1.com/29397395/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1705980395189/FfmpegHelper.java
fi

# compile
if [ -e "/tmp/FfmpegHelper.class" ]
then
    echo "FfmpegHelper.class already exist!"
else
    echo "FfmpegHelper.class does not exist,start compile"
    javac FfmpegHelper.java
fi

# run
java FfmpegHelper

# clean
rm -rf /tmp/FfmpegHelper.class
rm -rf /tmp/FfmpegHelper.java

        FfmpegHelper.java

import java.io.File;

public class FfmpegHelper {
	
    public static String GetDefaultFFMPEGPath() {
        return new File(System.getProperty("java.io.tmpdir"), "jave/").getAbsolutePath();
    }

    public static void main(String[] args) {
        String defaultFFMPEGPath = GetDefaultFFMPEGPath();
        System.out.println(defaultFFMPEGPath);
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【网络安全】-基本工具msf

secure 1、有此漏洞的目标主机2、无此漏洞的目标主机&#xff08;常用&#xff09; ps.本着兴趣爱好&#xff0c;加强电脑的安全防护能力&#xff0c;并严格遵守法律和道德规范。msf&#xff08;metasploit framework&#xff09;是一个开源的渗透测试框架&#xff0c;用于开发…

“智汇语言·驭领未来”——系列特辑:LLM大模型信息获取与企业应用变革

“智汇语言驭领未来”——系列特辑&#xff1a;LLM大模型信息获取与企业应用变革 原创 认真的飞速小软 飞速创软 2024-01-16 09:30 发表于新加坡 本期引言 LLM&#xff08;Large Language Model&#xff09;大型语言模型以其自然语言理解和生成能力&#xff0c;正以前所未有的…

函数极限与连续复盘

文章目录 函数的概念与特性反函数复合函数重要函数图像三个重要结论隐函数函数的四种特性有界性单调性奇偶性定义判断式复合函数的奇偶性:两个要记住的函数奇偶性:导数的奇偶性性质:一种特殊的形式 周期性重要结论 函数的图像基本初等函数与初等函数有趣的特性: 函数极限的概念…

Linux用户和权限

目录 1 root用户 1.1 root用户&#xff08;超级管理员&#xff09; ​​​​1.2 用户切换目录 1.3 sudo命令 2 用户、用户组管理 2.1 用户、用户组的概念 2.2 用户、用户组管理的相关命令 3 查看权限控制 4 修改权限控制 -chmod 5 修改权限控制 -chown 1 root用户 …

五分钟搞懂 POM 设计模式

今天&#xff0c;我们来聊聊 Web UI 自动化测试中的 POM 设计模式。 为什么要用 POM 设计模式 前期&#xff0c;我们学会了使用 PythonSelenium 编写 Web UI 自动化测试线性脚本 线性脚本&#xff08;以快递 100 网站登录举栗&#xff09;&#xff1a; PYTHON 1 2 3 4 5 6 …

MapReduce概述

文章目录 1. 分布式系统的驱动力和挑战2. 分布式系统的抽象和实现工具3. 可扩展性、可用性、一致性4. MapReduce基本工作方式5. Map函数和Reduce函数 1. 分布式系统的驱动力和挑战 分布式系统的核心是通过网络来协调&#xff0c;共同完成一致任务的一些计算机。构建分布式系统…

shopee最新选品:Shopee平台上的最新选品策略和方法

在Shopee平台上进行选品是卖家们必须经历的重要步骤。通过精心选择和定位产品&#xff0c;卖家可以提高产品的市场接受度和销售业绩。然而&#xff0c;要在竞争激烈的电商市场中脱颖而出&#xff0c;并不是一件容易的事情。本文将介绍一些在Shopee平台上进行最新选品时可以采用…

动态权限有哪些

定位权限&#xff1a; ACCESS_FINE_LOCATION&#xff1a;精确位置ACCESS_COARSE_LOCATION&#xff1a;大致位置 相机权限&#xff1a; CAMERA&#xff1a;访问摄像头 存储权限&#xff1a; READ_EXTERNAL_STORAGE&#xff1a;读取外部存储WRITE_EXTERNAL_STORAGE&#xff1a;…

【测试必备】汉化Postman竟如此简单,秒变中文,真香

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

RTX 4090D解禁真香警告?核心阉割性能“只下降”了5%

从 RTX 4090 传出禁售消息&#xff0c;再到反转再反转最终落实&#xff0c;这几个月所发生的可以用猝不及防来形容。 当然放现在来说&#xff0c;这一切又都可以理解了&#xff0c;毕竟 2022 年发布的 RTX 4090 性能「过于强大」。 好在老黄可不会就这么放弃国内市场&#xff…

路飞项目--03

二次封装Response模块 # drf提供的Response&#xff0c;前端想接收到的格式 {code:xx,msg:xx} 后端返回&#xff0c;前端收到&#xff1a; APIResponse(tokneasdfa.asdfas.asdf)---->{code:100,msg:成功,token:asdfa.asdfas.asdf} APIResponse(code101,msg用户不存在) ---…

分布式日志

1 日志管理 1.1 日志管理方案 服务器数量较少时 直接登录到目标服务器捞日志查看 → 通过 rsyslog 或shell/python 等脚本实现日志搜集并集中保存到统一的日志服务器 服务器数量较多时 ELK 大型的日志系统&#xff0c;实现日志收集、日志存储、日志检索和分析 容器环境 …

Redis学习——入门篇①

Redis学习——入门篇① 1、2&#xff1a;Redis入门概述3&#xff1a;Redis安装配置10 安装Redis-cli命令 4&#xff1a;Redis——十大数据类型11 redis数据类型12 命令查阅13 key常用命令介绍14 类型大小写和帮助命令15 String 命令&#xff08;上&#xff09;16 String 命令&a…

peer eslint-plugin-vue@“^7.0.0“ from @vue/eslint-config-standard@6.1.0

问题&#xff1a; 用vue/cli脚手架安装项目时&#xff0c;选择ESlint&#xff0c;再安装依赖包的时候&#xff0c;会报以下错误&#xff0c; 原因&#xff1a; npmV7 之前的版本遇到依赖冲突时&#xff0c;会忽视冲突&#xff0c;继续安装&#xff1b; npmV7版本开始不再自动忽…

安裝火狐和穀歌流覽器插件FoxyProxy管理海外動態IP代理

代理生態系統擁有大量有用的實用程式&#xff0c;使海外代理IP代理設置的使用變得簡單起來。其中一種類型叫做代理管理工具&#xff0c;像FoxyProxy就是該工具集比較受歡迎的。 本文將全面解析FoxyProxy擴展的功能和特性、Foxyproxy怎麼下載、以及如何在穀歌流覽器和火狐流覽器…

9款最新文生图模型汇总!含华为、谷歌、Stability AI等大厂创新模型(附论文和代码)

2023年真是文生图大放异彩的一年&#xff0c;给数字艺术界和创意圈注入了新鲜血液。从起初的基础图像创作跃进到现在的超逼真效果&#xff0c;这些先进的模型彻底变革了我们制作和享受数字作品的途径。 最近&#xff0c;一些大公司比如华为、谷歌、还有Stability AI等人工智能巨…

信用评价研究MATLAB仿真代码

信用评价是各种店铺卖家分析买家信用行为的重要内容, 本文给出随机仿真代码模拟实际交易过程的信用评价. 主要研究内容有: (1)研究最大交易额和信用度的关系 (2)研究买家不评价率对信用度影响 (3)研究交易次数对信用度影响 MATLAB程序如下: 主程序main.m %% clc;close a…

宝塔FTP文件传输服务结合cpolar内网穿透实现远程连接本地服务

⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 文章目录 ⛳️ 推荐1. Linux安装Cpolar2. 创建FTP公网地址3. 宝塔FTP服务设置4. FTP服务远程连接小结 5. 固定FTP公网地址6. 固…

NVMe TCG安全数据存储简介

NVMe&#xff08;非易失性内存主机控制器接口规范&#xff09;与TCG&#xff08;可信计算组&#xff09;的集成主要体现在数据安全、固件验证和硬件信任根等方面&#xff0c;以确保存储设备的数据保护能力和安全性。 TCG Opal定义了一套针对自加密硬盘&#xff08;SED, Self-En…

人工智能原理实验4(2)——贝叶斯、决策求解汽车评估数据集

&#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1; 汽车数据集 车子具有 buying,maint,doors,persons,lug_boot and safety六种属性&#xff0c;而车子的好坏分为uncc,ucc,good and vgood四种。 &#x1f9e1;&#x1f9e1;贝叶斯求解&#x1f9e1;&#x1f9e1;…