Java获取音频文件的持续时间的实现方案

 更新时间:2025年11月04日 08:41:48   作者:一键难忘  
在音视频处理开发中,FFmpeg 一直是最常用的跨平台音视频处理工具,然而在很多实际场景中,FFmpeg 并不总是理想的选择,本文将展示一种完全不依赖 FFprobe / FFmpeg 的方案,使用 Java 自带的 javax.sound.sampled API 来获取音频文件的持续时间,需要的朋友可以参考下

一、背景:为什么要“去 FFmpeg 化”

在音视频处理开发中,FFmpeg 一直是最常用的跨平台音视频处理工具。通过 FFprobe 命令,我们可以轻松获取音频的时长、码率、采样率等信息。

例如,以下命令即可返回音频的持续时间:

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.wav

然而在很多实际场景中,FFmpeg 并不总是理想的选择:

  • 部署复杂:需要在服务器或容器中额外安装二进制依赖;
  • 跨平台受限:不同操作系统的命令路径、权限处理差异较大;
  • 执行开销大:调用外部进程带来额外的 I/O 与启动成本;
  • 安全审计问题:某些环境(如内网部署或受限沙箱)禁止执行外部命令。

因此,在很多对性能和环境可控性要求较高的 Java 项目中,更倾向于使用 纯 Java 实现 去完成音频信息的解析。

本文将展示一种完全不依赖 FFprobe / FFmpeg 的方案,使用 Java 自带的 javax.sound.sampled API 来获取音频文件的持续时间(毫秒级精度)。

在这里插入图片描述

二、原方案:基于 FFprobe 的外部命令实现

在传统实现中,我们通常会通过执行 FFprobe 命令来获取音频持续时间。例如:

public static long audioDuration(String audioPath) throws IOException, InterruptedException {
    // 调用外部命令 ffprobe 获取时长
    ProcessBuilder processBuilder = new ProcessBuilder(
            "ffprobe", "-v", "error", "-show_entries", "format=duration",
            "-of", "default=noprint_wrappers=1:nokey=1", audioPath);
    String result = executeCommand(processBuilder);
    double duration = Double.parseDouble(result);
    return (long) (duration * 1000);
}

虽然这段代码功能上没有问题,但其主要痛点在于:

  • 依赖外部程序;
  • 平台兼容性差;
  • 额外进程调用开销较大。

在这里插入图片描述

三、改进方案:纯 Java 解析音频头信息

Java 自带的 javax.sound.sampled 包提供了读取音频文件的底层能力,我们可以直接通过以下方式获取音频的关键元数据:

  • AudioSystem.getAudioFileFormat(file):获取文件的音频格式信息;
  • AudioSystem.getAudioInputStream(file):获取音频流;
  • AudioFormat:包含采样率、通道数、位深等;
  • getFrameLength() 与 getFrameRate():计算时长的关键指标。

以下是完整的改进版本实现:

    public static long audioDuration(String audioPath) throws IOException, UnsupportedAudioFileException {
        File file = new File(audioPath);
        try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file)) {
            AudioFormat format = audioInputStream.getFormat();
            AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(file);

            long frameLength = audioInputStream.getFrameLength();
            float frameRate = format.getFrameRate();

            if (frameRate <= 0 || frameLength <= 0) {
                throw new IOException("无法计算音频时长:帧率或帧长度无效");
            }

            double durationInSeconds = frameLength / frameRate;
            return (long) (durationInSeconds * 1000);
        }
    }

在这里插入图片描述

四、实现原理解析

要理解为什么这段代码能计算时长,我们需要先了解音频文件的基本结构。

音频的时长(秒)通常可以通过公式计算:

duration = totalFrames / frameRate

  • frameLength:文件中包含的总帧数;
  • frameRate:每秒包含的帧数(即采样率 / 每帧样本数);
  • 1 秒 = 1000 毫秒 → 最终换算成毫秒即可。

WAV、AIFF、AU 等常见 PCM 格式音频都可以通过这种方式精确获得时长。

例如:

参数
采样率44,100 Hz
每帧样本数1(单声道)
总帧数441,000
计算结果441,000 ÷ 44,100 = 10 秒 = 10,000 毫秒

五、异常与兼容性处理建议

虽然该方法简单高效,但在实际应用中仍需注意以下几点:

1. 仅适用于已知音频格式

Java 原生 AudioSystem 只支持部分常见音频格式:

  • PCM 编码的 WAV;
  • AIFF;
  • AU;
  • 部分不压缩的 AIFF-C。

对于 MP3、AAC、FLAC 等压缩格式,则需要引入额外的解码库(如 MP3SPIJLayer)。

2. 无法处理流式音频

AudioSystem.getAudioInputStream() 需要完整的文件输入流,暂不支持实时流式音频(例如网络音频流)。

3. 需要合理的异常捕获

文件损坏、帧率无效或音频头异常时,应进行明确的异常提示。例如:

catch (UnsupportedAudioFileException e) {
    throw new IOException("不支持的音频格式:" + audioPath, e);
}

六、性能对比:外部命令 vs 纯 Java 方案

指标FFprobe 实现Java 纯实现
执行效率慢(需启动外部进程)快(直接读取文件头)
依赖性需要 FFmpeg无外部依赖
兼容性全格式支持支持有限(主要是 WAV/AIFF)
安全性存在命令注入风险纯本地执行更安全
可移植性优秀

从结果来看,对于需要在受限环境中运行、或仅处理常见 PCM 音频的项目,纯 Java 实现是更优选择。

七、总结与扩展

本文通过实例演示了如何在 Java 中使用标准库 javax.sound.sampled 获取音频文件的持续时间,完全摆脱 FFmpeg 依赖。

这种方式具有以下优势:

✅ 无需外部程序安装;
✅ 跨平台一致性好;
✅ 性能更优、启动开销低;
✅ 更易于集成进现有 Java 应用中。

当然,对于 MP3、AAC、OGG 等压缩格式,可以进一步结合第三方库(如 mp3spijaudiotagger)实现统一的时长提取方案。

本文介绍了在 Java 中无需依赖 FFmpeg 或 FFprobe,即可通过标准库 javax.sound.sampled 获取音频文件持续时间的实现方案。相比外部命令方式,纯 Java 方法更加轻量、安全、跨平台,能直接解析 WAV、AIFF 等常见 PCM 格式文件的帧率与帧长度,计算出精确的毫秒级时长。该方案不仅减少了系统依赖和进程开销,也更易于在受限环境或嵌入式场景中部署。如果需要支持 MP3、AAC 等压缩格式,则可结合第三方音频解码库进一步扩展。

在这里插入图片描述

以上就是Java获取音频文件的持续时间的实现方案的详细内容,更多关于Java获取音频文件持续时间的资料请关注脚本之家其它相关文章!

相关文章

  • Java用20行代码实现抖音小视频批量转换为gif动态图

    Java用20行代码实现抖音小视频批量转换为gif动态图

    这篇文章主要介绍了Java用20行代码实现抖音小视频批量转换为gif动态图,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Spring的Model 和 Map的原理源码解析

    Spring的Model 和 Map的原理源码解析

    这篇文章主要介绍了Spring的Model 和 Map的原理解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • SpringBoot整合Echarts绘制静态数据柱状图和饼图

    SpringBoot整合Echarts绘制静态数据柱状图和饼图

    这篇文章给大家介绍了SpringBoot整合Echarts绘制静态数据柱状图和饼图,文中通过代码示例给大家介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2024-03-03
  • Java Benchmark 基准测试的实例详解

    Java Benchmark 基准测试的实例详解

    这篇文章主要介绍了Java Benchmark 基准测试的实例详解的相关资料,这里提供实例帮助大家学习理解这部分内容,需要的朋友可以参考下
    2017-08-08
  • Java定义泛型接口和类的方法实例分析

    Java定义泛型接口和类的方法实例分析

    这篇文章主要介绍了Java定义泛型接口和类的方法,结合实例形式分析了泛型相关概念、原理及泛型接口与类的定义实现方法,需要的朋友可以参考下
    2019-08-08
  • springboot实现多实例crontab抢占定时任务(实例代码)

    springboot实现多实例crontab抢占定时任务(实例代码)

    这篇文章主要介绍了springboot实现多实例crontab抢占定时任务,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01
  • java 虚拟机深入了解

    java 虚拟机深入了解

    这篇文章主要介绍了java 虚拟机深入了解的相关资料,ava虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统,需要的朋友可以参考下
    2017-03-03
  • Java中zip文件压缩与解压之ZipInputStream和ZipOutputStream

    Java中zip文件压缩与解压之ZipInputStream和ZipOutputStream

    这篇文章主要给大家介绍了关于Java中zip文件压缩与解压之ZipInputStream和ZipOutputStream的相关资料,ZipInputStream 和 ZipOutputStream 可以用于处理 ZIP文件格式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • java实现手写一个简单版的线程池

    java实现手写一个简单版的线程池

    有些人可能对线程池比较陌生,并且更不熟悉线程池的工作原理。本文就来手写一个简单版的线程池,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • SpringBoot快速过滤出一次请求的所有日志的示例代码

    SpringBoot快速过滤出一次请求的所有日志的示例代码

    在现网出现故障时,我们经常需要获取一次请求流程里的所有日志进行定位,本文给大家介绍了SpringBoot如何快速过滤出一次请求的所有日志,文中有相关的代码和示例供大家参考,需要的朋友可以参考下
    2024-03-03

最新评论