ffmpeg音频处理-java实现

音频响度归一化

概述

FFmpeg的loudnorm滤镜 是一个实现了EBU R128标准的音频响度(loudness)归一化滤镜。在音频领域中,响度是指音频的感知音量水平,这与音量的技术度量(比如分贝)略有不同。响度归一化旨在调整音频轨道的响度,使得它们在不同的播放环境下提供一致的听觉体验。

使用loudnorm滤镜可以自动将音频调整到指定的响度目标,符合广播行业对响度的标准化要求。该滤镜特别有用于处理可能响度不一致的多个音频文件,比如电视节目、电影、广告和音乐。

EBU R128是欧洲广播联盟制定响度标准的推荐实践。该标准建议的流行音乐响度目标级别为-16 LUFS(Loudness Units Full Scale),而loudnorm滤镜能够根据此标准自动调节音频轨道。

loudnorm滤镜参数

loudnorm滤镜具有许多参数,可以对响度的整个归一化过程进行详细配置。以下是loudnorm常用参数:

  • I:设置集成响度(Integrated Loudness)目标,默认值为-24 LUFS。
  • LRA:设置响度范围(Loudness Range)目标,用于捕捉音频信号的动态范围,默认值为7 LU。
  • TP:设置真峰目标(True Peak),默认值为-2.0 dBTP(分贝相对于True Peak)。
  • measured_I、measured_LRA、measured_TP、measured_thresh:这些参数通常由第一次运行loudnorm滤镜时生成,用于在双遍响度归一化过程中的第二遍中使用。

代码

java 复制代码
    /**
     * 使用 FFmpeg 对音频文件进行标准化处理
     *
     * @param inputFilePath  输入音频文件路径
     * @param outputFilePath 输出音频文件路径
     * @param targetLoudness 目标响度级别,以 LUFS 为单位 (例如流行音乐 -16)
     * @param loudnessRange  响度范围调整 (例如 11)
     * @throws IOException 如果在执行 FFmpeg 命令时发生 IO 错误
     */
    public static void normalizeAudio(String inputFilePath, String outputFilePath, double targetLoudness, double loudnessRange) throws IOException {

        String command = String.format(
                "ffmpeg -i %s -f mp3 -af \"loudnorm=I=%.1f:LRA=%.1f\" %s",
                inputFilePath, targetLoudness, loudnessRange, outputFilePath
        );

        // 执行命令
        Process process = Runtime.getRuntime().exec(command);

        // 读取错误输出
        Thread errorThread = new Thread(() -> {
            try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                String line;
                while ((line = errorReader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        errorThread.start();

        // 检查命令是否成功执行
        try {
            errorThread.join();
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new IOException("FFmpeg 命令执行失败,退出代码: " + exitCode);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("FFmpeg 命令执行被中断", e);
        }
    }

加强音频人声频段

概述

FFmpeg的equalizer(均衡器)滤镜是一个强大的音频滤波器,用于调节音频信号中各个频率的增益。通过操控不同频率的增益,均衡器可以提升或衰减音频信号中特定频段的音量,从而改变音频的整体音色或突出某些频率范围。均衡器滤镜常用于音频处理,如增强人声、去除背景噪声或调整音乐音色,以达到更好的听觉效果。

equalizer滤镜参数

equalizer滤镜提供了多个参数,允许用户精确地调节音频频谱的各个部分。以下是equalizer滤镜的常用参数:

  • f:设置要调整的频率(以Hz为单位)。这个参数指定了希望增强或削弱的中心频率。
  • width_type:设置频率带宽的类型,可以选择q(品质因数)、h(赫兹)、或o(八度)。带宽决定了受影响的频率范围的宽度。
  • width:设置频率带宽的数值,取决于width_type的选择。对于o类型,width的值表示影响的八度数。
  • g:设置频率的增益(以dB为单位),正值表示增强该频率,负值表示削弱该频率。

代码

java 复制代码
   /**
     * 使用 FFmpeg 加强人声频段
     *
     * @param inputFilePath  输入音频文件路径
     * @param outputFilePath 输出音频文件路径
     * @throws IOException 如果在执行 FFmpeg 命令时发生 IO 错误
     */
    public static void enhanceVocalRange(String inputFilePath, String outputFilePath) throws IOException {
        // FFmpeg 命令,使用均衡器滤镜增强人声频段
        String command = String.format(
                "ffmpeg -i %s -af \"equalizer=f=300:width_type=o:width=2:g=5, " +
                        "equalizer=f=1000:width_type=o:width=2:g=10, " +
                        "equalizer=f=3000:width_type=o:width=2:g=10\" %s",
                inputFilePath, outputFilePath
        );

        // 执行命令
        Process process = Runtime.getRuntime().exec(command);

        // 读取错误输出
        Thread errorThread = new Thread(() -> {
            try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                String line;
                while ((line = errorReader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        errorThread.start();

        // 检查命令是否成功执行
        try {
            errorThread.join();
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new IOException("FFmpeg 命令执行失败,退出代码: " + exitCode);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("FFmpeg 命令执行被中断", e);
        }
    }

获取音频音量信息

概述

FFmpeg的volumedetect滤镜是一个用于检测音频文件中音量信息的滤镜。通过分析音频文件,volumedetect能够提供详细的音量统计数据,包括最大音量、平均音量和音量峰值等。这些信息对于音频处理和后期制作非常有用,可以帮助工程师了解音频文件的动态范围和响度水平,从而做出相应的调整,如音量归一化、动态范围压缩等。

volumedetect滤镜输出信息

volumedetect滤镜本身不需要复杂的参数配置,使用非常简便。以下是该滤镜的输出信息及其含义:

  • mean_volume:表示音频文件的平均音量(以dB为单位)。
  • max_volume:表示音频文件的最大音量(以dB为单位),即音频中响度最高的部分。
  • min_volume:表示音频文件的最小音量(以dB为单位),通常出现在音频文件的安静部分。
  • max_volume:表示音频文件的最大峰值(以dB为单位),这个值对于防止音频过载(剪切)非常重要。

代码

java 复制代码
    /**
     * 获取音频文件的音量信息
     *
     * @param filePath 音频文件路径
     * @throws IOException 如果在执行 FFmpeg 命令时发生 IO 错误
     */
    public static void printAudioVolumeInfo(String filePath) throws IOException {
        String command = String.format("ffmpeg -i %s -af volumedetect -f null -", filePath);

        Process process = Runtime.getRuntime().exec(command);

        Thread errorThread = new Thread(() -> {
            try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                String line;
                while ((line = errorReader.readLine()) != null) {
                    if (line.contains("Parsed_volumedetect")) {
                        System.out.println(line);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        errorThread.start();

        try {
            errorThread.join();
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new IOException("FFmpeg 命令执行失败,退出代码: " + exitCode);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("FFmpeg 命令执行被中断", e);
        }
    }
相关推荐
KIKIiiiiiiii15 小时前
微信个人号开发中如何高效实现API二次开发
java·前端·python·微信
胡八一15 小时前
30 分钟上手 exp4j:在 Java 中安全、灵活地计算数学表达式
java·开发语言·安全
张较瘦_16 小时前
环境搭建 | [入门级]VSCode(Cursor|Trae|Qoder)搭建Java(Springboot3)企业开发环境全流程
java·ide·vscode
007php00716 小时前
百度面试题解析:synchronized、volatile、JMM内存模型、JVM运行时区域及堆和方法区(三)
java·开发语言·jvm·缓存·面试·golang·php
YSRM16 小时前
Leetcode+Java+图论II
java·leetcode·图论
十铭忘16 小时前
基于SAM2的眼动数据跟踪2
java·服务器·前端
八月的雨季 最後的冰吻16 小时前
FFmpeg--FlvPaser源码解析
ffmpeg
okjohn16 小时前
浅谈需求分析与管理
java·架构·系统架构·软件工程·产品经理·需求分析·规格说明书
追风201916 小时前
OSS存储的视频,安卓和PC端浏览器打开正常,苹果端打开不播放,什么原因?
音视频
用户03321266636717 小时前
Java添加、设置和删除PDF图层:
java