ffmpeg使用及java操作

这篇具有很好参考价值的文章主要介绍了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 mis.shared.date.DateUnitl;
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;
import java.util.Calendar;

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

    /**
     * 通过本地路径获取多媒体文件信息(宽,高,时长,编码等)
     *
     * @param filePath 文件路径
     * @return MultimediaInfo 媒体对象,包含 (宽,高,时长,编码等)
     */
    public static MultimediaInfo GetMediaInfo(String filePath) {
        MultimediaInfo multimediaInfo = null;
        try {
            multimediaInfo = new MultimediaObject(new File(filePath)).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.debug("ffmpeg压缩{}花费时间:{}秒", inputPath, (System.currentTimeMillis() - start) / 1000);
            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;
            }
            log.debug("start copy,inputPath:{},outputPath:{}", inputPath, outputPath);
            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("{}花费时间:{}毫秒", outputPath, 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 inputPath, String outputPath) {
        try {
            File target = new File(outputPath);
            if (target.exists()) {
                log.error("目标文件已存在,outputPath:{}", outputPath);
                return false;
            }

            MultimediaObject multimediaObject = new MultimediaObject(new File(inputPath));
            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;
        }
    }

    /**
     * 获取视频第多少秒的缩略图
     */
    public static boolean GetThumbnail(String inputPath, int second, 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(inputPath);
            ffmpeg.addArgument("-ss");//第多少秒的视频画面
            ffmpeg.addArgument("" + second);
            ffmpeg.addArgument("-s");
            ffmpeg.addArgument("600*360");//图片宽*高
            ffmpeg.addArgument(outputPath);
            ffmpeg.execute();

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

    /**
     * 添加水印
     *
     * @param inputPath     输入视频路径
     * @param waterMarkPath 水印文件路径
     * @param x             距离左上角水平距离
     * @param y             距离左上角垂直距离
     * @param outputPath    输出视频路径
     */
    public static boolean AddWatermark(String inputPath, String waterMarkPath,
                                       int x, int y, 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(inputPath);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(waterMarkPath);
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument("overlay=" + x + ":" + y);
            ffmpeg.addArgument(outputPath);
            ffmpeg.execute();

            //等待执行完成
            WaitFfmpegFinish(ffmpeg);
        } catch (Exception e) {
            log.error("添加水印异常", e);
            return false;
        } finally {
            if (ffmpeg != null) {
                ffmpeg.destroy();
            }
        }
        return true;
    }

    /**
     * 获取ffmpeg默认路径
     */
    public static String GetDefaultFFMPEGPath() {
        return new File(System.getProperty("java.io.tmpdir"), "jave/").getAbsolutePath();
    }

    /**
     * 将第多少秒转换为视频时间(HH:mm:ss)
     * 例: 第70秒为00:01:10
     *
     * @param second 视频中的第多少秒
     */
    public static String TransferVideoTime(int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.add(Calendar.SECOND, second);
        return DateUnitl.ToString(calendar.getTime(), "HH:mm:ss");
    }

    /**
     * 等待命令执行完成
     */
    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//test685m_10_42min.mp4";
        String waterMarKFile = "e://develop//tmp//watermark100x75.png";
        String outputPng = "e://develop//tmp//mainTest3.png";

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

        //修改视频分辨率
        //ChangeScale(inputFile, outputFile, 640, 480);

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

        //添加水印
        //AddWatermark(inputFile, waterMarKFile, 50, 50, outputFile);

        //获取视频第多少秒的缩略图
        System.out.println(GetThumbnail(inputFile, 1, outputPng));
    }

}

附录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复制到上面的目录下

ffmpeg使用及java操作,java,java

         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文章来源地址https://www.toymoban.com/news/detail-817594.html

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);
    }

}

到了这里,关于ffmpeg使用及java操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java工程使用ffmpeg进行音视频格式转换(ws.schild)

    JAVE (Java Audio Video Encoder)是一个纯Java的音视频编码器和解码器库,它是基于FFmpeg。JAVE库提供了一些简单易用的API,用于音频和视频格式的转换、编码、解码等操作。它对于一些基本的音视频处理任务来说是一个不错的选择。 这些库都是基于FFmpeg的,并允许在Java中处理音频和

    2024年02月14日
    浏览(87)
  • FFmpeg添加字幕的详细操作

    在视频中添加字幕可以使视频更具可读性,并为观众提供更好的观看体验,这在多语种内容中尤为重要。FFmpeg是一个流行的开源视频处理工具,它可以被用来给视频添加字幕。本文将介绍FFmpeg集成libass的编译流程,介绍SRT和ASS字幕格式及其参数,如何使用FFmpeg向视频添加硬字

    2024年02月06日
    浏览(43)
  • ffmpeg 配合Fiddler抓包操作

    一.获取普通网站视频 1.安装Fiddler软件,直接点击绿色软件中Fiddler.exe,打开即可 2.打开后需要设置一下https解码 3.打开普通视频,获取视频链接在网页打开即可 二.获取一级反爬网站视频 1.随便找一个video/mp4属性的点击 2.点击探测器,再点击探测器下面的标头 3.找到Conten

    2024年02月11日
    浏览(32)
  • FFMPEG基本操作命令指南(二)

    FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。FFmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。 接上第一篇基础的几个命令,下面介绍几个看起来比较复杂的 一:视频剪切 命令示例: ffmpeg -

    2023年04月24日
    浏览(32)
  • ffmpeg操作MP4视频封面

    提取视频封面 视频流中提取帧图 3.重新设置视频封面 更多参考: https://blog.csdn.net/m0_37624402/article/details/125123818

    2024年02月04日
    浏览(40)
  • ffmpeg 配合Fiddler抓包获取视频操作

    一.获取普通网站视频 1.安装Fiddler软件,直接点击绿色软件中Fiddler.exe,打开即可 2.打开后需要设置一下https解码 3.打开普通视频,获取视频链接在网页打开即可 二.获取一级反爬网站视频 1.随便找一个video/mp4属性的点击 2.点击探测器,再点击探测器下面的标头 3.找到Conten

    2024年02月10日
    浏览(51)
  • PHP-FFMpeg 操作音视频

    目录 🎈 安装PHP-FFMpeg 🎈 视频中提取一张图片 🎈 视频中提取多张图片 🎈 调整视频大小 🎈 视频添加水印 🎈 生成音频波形 🎈 音频转换 🎈 给音频添加元数据 🎈 拼接多个音视频 🎈 截取音视频 🎈 提取 gif 动图 🎈 裁剪视频 🎈 转换视频格式 🎈 调整视频帧率 🎈 获取

    2024年02月08日
    浏览(39)
  • 视频行为分析——视频图像转换与ffmpeg相关操作

    工具类说明 1.1 视频输出gif 1.2 将文件夹下图片转视频 2.1 ffmpeg安装 FFmpeg 的官方网站(https://ffmpeg.org/)上找到更详细的安装文档和指南。 2.1.1 linux 安装 编译安装:如果你需要更新或自定义的 FFmpeg 版本,你可以从源代码编译安装。你可以从 FFmpeg 的官方网站下载源代码,并按

    2024年02月11日
    浏览(36)
  • 使用java操作redis

    目录 一、java连接redis 1、前置条件:开启redis服务  2、连接驱动  pom依赖  3、测试连接  二、java操作String 1、设值  2、拿取对象  3、删除  4、修改  5、给键值对设置过期时间: 6、获取键值对剩余的存活时间:  三、Java操作哈希 1、同时将多个field-value设置到哈希表key中:

    2023年04月23日
    浏览(67)
  • Java 操作RestHighLevelClient基本使用

    在使用 RestHighLevelClient的过程中发现,它已经标记为过时了。 在 Elasticsearch7.15版本之后,Elasticsearch官方将它的高级客户端 RestHighLevelClient标记为弃用状态。 同时推出了全新的 Java API客户端 Elasticsearch Java API Client,该客户端也将在 Elasticsearch8.0及以后版本中成为官方推荐使用的

    2024年02月11日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包