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);
        }
    }
相关推荐
codeRichLife27 分钟前
Mybatisplus3.5.6,用String处理数据库列为JSONB字段
java·数据库
来自星星的猫教授33 分钟前
Java 文件注释规范(便于生成项目文档)
java·注释
zhimeng337 分钟前
自己学习原理
java
程序员鱼皮40 分钟前
学 Java 还是 Go 语言?这事儿很简单!
java·后端·计算机·程序员·开发·编程经验·自学编程
Lanqing_076044 分钟前
淘宝商品详情图API接口返回参数说明
java·服务器·前端·api·电商
矮油0_o1 小时前
第一部分 -- ①语法分析的概要
java·编译器·解释器·语法分析
写bug写bug1 小时前
Dubbo中SPI机制的实现原理和优势
java·后端·dubbo
浮游本尊1 小时前
第2天Java学习作业 - 完整解答
java
一叶萩Charles1 小时前
线程与进程(java)
java·开发语言
武昌库里写JAVA1 小时前
iview组件库:当后台返回到的数据与使用官网组件指定的字段不匹配时,进行修改某个属性名再将response数据渲染到页面上的处理
java·开发语言·spring boot·学习·课程设计