jjzjj

javacv从入门到精通——第五章:音频处理

ayou_llf 2023-09-24 原文
  1. 学习如何使用javacv进行音频处理

使用 javacv 进行音频处理需要使用 FFmpeg 的 libavcodec 库进行音频解码、编码以及音频转换等操作,同时还需要使用 OpenCV 的视频 I/O 模块进行音频数据读写。

以下是一些常见的音频处理操作以及使用 javacv 实现这些操作的方法:

  1. 音频格式转换:可以使用 FFmpeg 的 libswresample 库进行音频格式转换。可以通过 javacv 中的 FFmpegFrameGrabberFFmpegFrameRecorder 类进行音频解码和编码。具体实现方法可以参考上述的视频处理部分。

  1. 音频增益处理:可以使用 javacv 中的 JavaCV.audioGain 类进行音频增益处理。该类提供了 changeVolume() 方法,可以调整音频的音量大小。

  1. 音频降噪处理:可以使用 javacv 中的 JavaCV.noiseReduction 类进行音频降噪处理。该类提供了 reduceNoise() 方法,可以对音频进行降噪处理。

  1. 音频合并处理:可以使用 javacv 中的 JavaCV.audioMerge 类进行音频合并处理。该类提供了 mergeAudio() 方法,可以将多个音频文件进行合并。

  1. 音频切割处理:可以使用 javacv 中的 JavaCV.audioCut 类进行音频切割处理。该类提供了 cutAudio() 方法,可以对音频文件进行切割处理。

以下是一个使用javacv进行音频处理的示例代码,该代码演示了如何使用javacv读取音频文件、对音频进行降噪和增益处理、并将处理后的音频保存到新文件中:

import org.bytedeco.javacv.*;

public class AudioProcessingExample {
    public static void main(String[] args) {
        // 定义输入和输出文件路径
        String inputFilePath = "input.wav";
        String outputFilePath = "output.wav";

        // 创建FFmpegFrameGrabber来读取音频文件
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFilePath);

        try {
            // 开启抓取器
            grabber.start();

            // 获取音频信息
            int numChannels = grabber.getAudioChannels();
            int sampleRate = grabber.getSampleRate();

            // 创建FFmpegFrameRecorder来写入音频文件
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFilePath, numChannels);

            // 设置音频编码器
            recorder.setAudioCodec(grabber.getAudioCodecName());

            // 设置音频格式
            recorder.setAudioFormat(grabber.getSampleFormat());

            // 设置音频采样率
            recorder.setSampleRate(sampleRate);

            // 设置音频比特率
            recorder.setAudioBitrate(grabber.getAudioBitrate());

            // 开启录制器
            recorder.start();

            // 创建一个降噪器
            OpenCVFrameFilter denoiser = new OpenCVFrameFilter("noiseprofile=denoise=1:noise=10");

            // 创建一个增益器
            OpenCVFrameFilter gain = new OpenCVFrameFilter("volume=3dB");

            // 读取音频帧
            Frame audioFrame = null;
            while ((audioFrame = grabber.grabFrame()) != null) {
                // 过滤器处理音频帧
                denoiser.push(audioFrame);
                Frame denoisedFrame = denoiser.pull();

                gain.push(denoisedFrame);
                Frame gainFrame = gain.pull();

                // 将处理后的音频帧写入新文件
                recorder.record(gainFrame);
            }

            // 释放抓取器和录制器
            grabber.stop();
            grabber.release();
            recorder.stop();
            recorder.release();
        } catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
            e.printStackTrace();
        }
    }
}

该示例代码中使用了FFmpegFrameGrabber来读取音频文件,FFmpegFrameRecorder来写入音频文件,以及OpenCVFrameFilter来进行降噪和增益处理。读取音频帧的过程和读取视频帧的过程类似,只是音频帧没有像素数据,而是包含音频采样数据。因此,对音频进行处理的方法也不同于对视频进行处理,需要使用专门的音频过滤器来进行处理。

  1. 学习如何对音频进行剪辑、拼接和混合等操作

  1. 音频剪辑:使用FFmpegFrameGrabber和FFmpegFrameRecorder分别读取和写入音频文件,然后对音频进行剪辑操作,最后将剪辑后的音频写入到新的音频文件中。

public static void audioClip(String srcFile, String dstFile, int startMs, int endMs) throws Exception {
    FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(srcFile);
    grabber.start();
    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(dstFile, grabber.getAudioChannels());
    recorder.setSampleRate(grabber.getSampleRate());
    recorder.start();
    Frame frame;
    int startFrame = (int) (startMs * grabber.getSampleRate() / 1000);
    int endFrame = (int) (endMs * grabber.getSampleRate() / 1000);
    while ((frame = grabber.grabFrame()) != null) {
        if (frame.samples == null) {
            break;
        }
        int frameNumber = grabber.getFrameNumber();
        if (frameNumber >= startFrame && frameNumber <= endFrame) {
            recorder.recordSamples(frame.samples);
        }
        if (frameNumber > endFrame) {
            break;
        }
    }
    grabber.stop();
    recorder.stop();
}
  1. 音频拼接:使用FFmpegFrameGrabber和FFmpegFrameRecorder分别读取和写入音频文件,然后将多个音频文件的音频数据按顺序写入到新的音频文件中。

public static void audioConcat(List<String> srcFiles, String dstFile) throws Exception {
    List<FFmpegFrameGrabber> grabbers = new ArrayList<>();
    List<Integer> sampleRates = new ArrayList<>();
    for (String srcFile : srcFiles) {
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(srcFile);
        grabber.start();
        grabbers.add(grabber);
        sampleRates.add(grabber.getSampleRate());
    }
    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(dstFile, 1);
    recorder.setSampleRate(sampleRates.get(0));
    recorder.start();
    Frame frame;
    for (int i = 0; i < grabbers.size(); i++) {
        FFmpegFrameGrabber grabber = grabbers.get(i);
        while ((frame = grabber.grabFrame()) != null) {
            if (frame.samples == null) {
                break;
            }
            recorder.recordSamples(frame.samples);
        }
    }
    for (FFmpegFrameGrabber grabber : grabbers) {
        grabber.stop();
    }
    recorder.stop();
}
  1. 音频混合:使用FFmpegFrameGrabber和FFmpegFrameRecorder分别读取和写入音频文件,然后将多个音频文件的音频数据按一定的比例混合后写入到新的音频文件中。

// 输入文件名和输出文件名
String inputFile1 = "input1.mp3";
String inputFile2 = "input2.mp3";
String outputFile = "output.mp3";

// 创建音频读取器和写入器
FFmpegFrameGrabber grabber1 = new FFmpegFrameGrabber(inputFile1);
grabber1.start();
FFmpegFrameGrabber grabber2 = new FFmpegFrameRecorder(inputFile2);
grabber2.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 2);
recorder.setAudioCodec(AV_CODEC_ID_MP3);
recorder.setAudioBitrate(128000);

// 混合音频
Frame frame1, frame2;
while ((frame1 = grabber1.grabFrame()) != null && (frame2 = grabber2.grabFrame()) != null) {
    Frame mixedFrame = new Frame();
    mixedFrame.samples = new ShortBuffer[] { frame1.samples[0], frame2.samples[0] };
    mixedFrame.sampleRate = frame1.sampleRate;
    mixedFrame.audioChannels = 2;
    mixedFrame.opaque = frame1.opaque;
    mixedFrame.timestamp = Math.max(frame1.timestamp, frame2.timestamp);
    recorder.record(mixedFrame);
}

recorder.stop();
grabber1.stop();
grabber2.stop();
  1. 学习如何进行音频特效处理

JavaCV 提供了一些常见的音频特效处理功能,例如音频变速、音频变调、音频混响和音频降噪等。下面是一些基本的音频特效处理操作的示例。

音频变速

要对音频进行变速处理,可以使用 FFmpegFrameGrabber 类读取原始音频文件的音频流,然后使用 FFmpegFrameFilter 类设置变速过滤器并将音频流输入到该过滤器中。最后,使用 FFmpegFrameRecorder 类将变速后的音频流写入新的音频文件中。

// 输入文件名和输出文件名
String inputFile = "input.mp3";
String outputFile = "output.mp3";

// 创建音频读取器和写入器
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
grabber.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getAudioChannels());
recorder.setAudioCodec(grabber.getAudioCodec());
recorder.setAudioBitrate(grabber.getAudioBitrate());

// 创建变速过滤器
String filter = String.format("atempo=%.2f", 1.5f);
FFmpegFrameFilter frameFilter = new FFmpegFrameFilter(filter, grabber.getAudioChannels());
frameFilter.start();

// 变速并写入音频
Frame frame;
while ((frame = grabber.grabFrame()) != null) {
    frameFilter.push(frame);
    Frame filteredFrame;
    while ((filteredFrame = frameFilter.pull()) != null) {
        recorder.record(filteredFrame);
    }
}
frameFilter.stop();
recorder.stop();
grabber.stop();

这个示例使用 atempo 过滤器实现变速功能,atempo 参数的值表示变速倍数,1.0 表示不变速,1.5 表示变速 1.5 倍。

音频变调

要对音频进行变调处理,可以使用 FFmpegFrameGrabber 类读取原始音频文件的音频流,然后使用 FFmpegFrameFilter 类设置变调过滤器并将音频流输入到该过滤器中。最后,使用 FFmpegFrameRecorder 类将变调后的音频流写入新的音频文件中。

// 输入文件名和输出文件名
String inputFile = "input.mp3";
String outputFile = "output.mp3";

// 创建音频读取器和写入器
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
grabber.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getAudioChannels());
recorder.setAudioCodec(grabber.getAudioCodec());
recorder.setAudioBitrate(grabber.getAudioBitrate());

// 创建变调过滤器
String filter = String.format("asetrate=%d,atempo=%.2f", 44100, 1.5f);
FFmpegFrameFilter frameFilter = new FFmpegFrameFilter(filter, grabber.getAudioChannels());
frameFilter.start();

// 变调并写入音频
Frame frame;
while ((frame = grabber.grabFrame()) != null) {
    frameFilter.push(frame);
    Frame filteredFrame;
    while ((filteredFrame = frameFilter.pull()) != null) {
        recorder.record(filteredFrame);
    }
}
frameFilter.stop();
recorder.stop();
grabber.stop();

这个示例使用 asetrateatempo 过滤器实现变调功能,其中 asetrate 参数的值表示变换后的采样率,这里设置为 44100,atempo 参数的值表示变调倍数,这里设置为 1.5 倍。您可以根据需要修改这些参数的值。

音频混响

音频混响是一种通过添加混响效果来增强音频质量的方法。在 JavaCV 中,我们可以使用 sox 工具来实现音频混响。sox 是一个命令行工具,它可以在各种操作系统上使用,可以在 Linux,Windows 和 macOS 等操作系统上安装使用。

// 输入文件名和输出文件名
String inputFile = "input.mp3";
String outputFile = "output.mp3";

// 创建音频读取器和写入器
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
grabber.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getAudioChannels());
recorder.setAudioCodec(grabber.getAudioCodec());
recorder.setAudioBitrate(grabber.getAudioBitrate());

// 创建混响过滤器
String filter = "reverb";
FFmpegFrameFilter frameFilter = new FFmpegFrameFilter(filter, grabber.getAudioChannels());
frameFilter.start();

// 添加混响效果并写入音频
Frame frame;
while ((frame = grabber.grabFrame()) != null) {
    frameFilter.push(frame);
    Frame filteredFrame;
    while ((filteredFrame = frameFilter.pull()) != null) {
        recorder.record(filteredFrame);
    }
}
frameFilter.stop();
recorder.stop();
grabber.stop();

这个示例使用 reverb 过滤器实现音频混响效果。您可以根据需要选择不同的混响效果。另外,请确保已安装并配置了 sox 工具,以便 JavaCV 可以正确地使用它。

音频降噪

音频降噪是一种通过去除噪声来提高音频质量的方法。在 JavaCV 中,我们可以使用 WebRTC 库来实现音频降噪。WebRTC 是一个开源项目,它提供了实时通信功能,包括音频和视频通信。

// 输入文件名和输出文件名
String inputFile = "input.mp3";
String outputFile = "output.mp3";

// 创建音频读取器和写入器
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
grabber.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getAudioChannels());
recorder.setAudioCodec(grabber.getAudioCodec());
recorder.setAudioBitrate(grabber.getAudioBitrate());

// 创建降噪过滤器
String filter = "anlmdn=ns=16:ss=16:fa=500";
FFmpegFrameFilter frameFilter = new FFmpegFrameFilter(filter, grabber.getAudioChannels());
frameFilter.start();

// 降噪并写入音频
Frame frame;
while ((frame = grabber.grabFrame()) != null) {
    frameFilter.push(frame);
    Frame filteredFrame;
    while ((filteredFrame = frameFilter.pull())!= null) {
        recorder.record(filteredFrame);
    }
}
frameFilter.stop();
recorder.stop();
grabber.stop();

这个示例使用 `anlmdn` 过滤器实现音频降噪效果。您可以根据需要调整降噪参数。另外,请确保已安装并配置了 WebRTC 库,以便 JavaCV 可以正确地使用它。

有关javacv从入门到精通——第五章:音频处理的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  3. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  4. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  5. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  6. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

    我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

  7. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  8. ruby - 如何使用 Ruby HTTP::Net 处理 404 错误? - 2

    我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。

  9. ruby-on-rails - 使用 Ruby 正确处理 Stripe 错误和异常以实现一次性收费 - 2

    我查看了Stripedocumentationonerrors,但我仍然无法正确处理/重定向这些错误。基本上无论发生什么,我都希望他们返回到edit操作(通过edit_profile_path)并向他们显示一条消息(无论成功与否)。我在edit操作上有一个表单,它可以POST到update操作。使用有效的信用卡可以正常工作(费用在Stripe仪表板中)。我正在使用Stripe.js。classExtrasController5000,#amountincents:currency=>"usd",:card=>token,:description=>current_user.email)

  10. ruby-on-rails - Rails 处理 .Erb 与 Nils - 2

    当profile为nil时,总是让我感到悲伤...我该怎么办? 最佳答案 在View中使用变量之前,始终检查变量是否为nil。我确信这个问题有更优雅的解决方案,但这应该能让您入门。 关于ruby-on-rails-Rails处理.Erb与Nils,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/2709605/

随机推荐