springboot 处理编码的格式为opus的音频数据解决方案【java8】

news2025/4/16 22:16:28

opus编码的格式概念:

Opus是一个有损声音编码的格式,由Xiph.Org基金会开发,之后由IETF(互联网工程任务组)进行标准化,目标是希望用单一格式包含声音和语音,取代Speex和Vorbis,且适用于网络上低延迟的即时声音传输,标准格式定义于RFC 6716文件。Opus格式是一个开放格式,使用上没有任何专利或限制。

Opus集成了两种声音编码的技术:以语音编码为导向的SILK和低延迟的CELT。Opus可以无缝调节高低比特率。在编码器内部它在较低比特率时使用线性预测编码在高比特率时候使用变换编码(在高低比特率交界处也使用两者结合的编码方式)。Opus具有非常低的算法延迟(默认为22.5 ms),非常适合用于低延迟语音通话的编码,像是网上上的即时声音流、即时同步声音旁白等等,此外Opus也可以透过降低编码码率,达成更低的算法延迟,最低可以到5 ms。在多个听觉盲测中,Opus都比MP3、AAC、HE-AAC等常见格式,有更低的延迟和更好的声音压缩率。

需求场景:

最近我在对接一个可以接收声音的 硬件设备,通信模式为 websocket。
通过测试 ,接收到的音频格式为 :opus 格式。
我接收到这个格式的 音频后,首先需要给这个格式的音频进行解码,然后得到PCM编码格式的数据。
解码后的 PCM 数据则是还原后的音频信号,是原始音频的近似表示,可以直接输出音频信号。

PCM解释:

PCM(脉冲编码调制,Pulse Code Modulation)编码是一种将模拟信号转换为数字信号的方法,广泛用于音频、视频和通信系统中。PCM编码的主要目的是将模拟信号的幅度表示为一系列的数字值,这样可以在数字系统中更容易地存储、处理和传输。
PCM编码的基本过程
采样:首先,将模拟信号按一定的时间间隔进行采样。每次采样得到的值称为“采样点”。
量化:将每个采样点的模拟信号值转换成最接近的数字值。量化的精度由量化位数(通常是8位、16位或更高)决定,位数越高,表示的数字精度越高,信号的失真越小。
编码:将量化后的数字信号进行二进制编码,即将每个采样点的数字值转化为二进制形式,形成一串二进制代码。
PCM的常见应用
音频:例如CD音质的音频数据就是使用PCM编码的,通常采用44.1kHz的采样率和16位的量化深度。
通信:PCM也用于电话通信和其他语音传输领域。
视频:PCM有时也用于视频信号的音频部分编码。

对于做网站开发的我,也是第一次处理关于音频的数据,这篇文章就把我遇到的一些问题做一个分享,希望能帮助看到这篇文章的你。
这个设备提供的代码是python版本的。
但是我是使用 java语言,springboot 框架 来处理数据的。

在调试的过程中 遇到了一个问题:opus格式的音频解码的问题?
对于python来说 这个语言 有现成的包 opuslib 还是比较好处理的

# Opus音频解码
import opuslib
import opuslib.api.encoder
import opuslib.api.decoder


class OpusDecoder():
    def __init__(self, samplerate: int, channels: int, seq_time: float) -> None:
        self.samplerate = samplerate
        # 创建解码器
        self.decoder = opuslib.Decoder(fs=self.samplerate, channels=channels)
        self.seq_length = int(seq_time*self.samplerate*2)

    def decode(self, input_bytes: bytes):
        # 直接解码opus数据
        dec_output = self.decoder.decode(bytes(input_bytes), self.seq_length)
        # print('decode seq len: {}'.format(len(dec_output))) 
        return dec_output

当我来使用java的时候 发现 网上java对于这个格式音频处理的相关文章非常的少,相关依赖也非常的少,至于找到的可以用的依赖,也没找到相关文档怎么使用。
通过我在 github上的搜索和 maven仓库里的寻找,终于找到了java对于 opus格式的音频的解决方案。
下面就直接上代码了:
第一步引入依赖:

      <dependency>
            <groupId>club.minnced</groupId>
            <artifactId>opus-java</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>4.1.0</version>
        </dependency>

第二步封装 工具类:

package com.agentai.base.utils;

/***
 * opus 解码器工具类
 * User: Json
 * Date: 2025/4/11
 **/
import club.minnced.opus.util.OpusLibrary;
import com.sun.jna.ptr.PointerByReference;
import tomp2p.opuswrapper.Opus;

import java.io.IOException;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Base64;

public class OpusDecoder {
    private int samplerate;
    private int seqLength;
    private PointerByReference opusDecoder;

    // 加载 Opus 库  对于这个加载 opus库的 写法 文章下方 有截图的解释。
    static {
        try {
            // 尝试通过 OpusLibrary 加载 JAR 内的本地库
            if (!OpusLibrary.loadFromJar()) {
                throw new UnsatisfiedLinkError("未加载到 opus处理文件!");
            }
        } catch (IOException e1) {
            try {
                // 如果失败,尝试通过默认的 System.loadLibrary() 加载 找本地系统的
                System.loadLibrary("opus");
            } catch (UnsatisfiedLinkError e2) {
                e1.printStackTrace();
            }
        }
    }

    public OpusDecoder(int samplerate, int channels, float seqTime) {
        this.samplerate = samplerate;
        // 创建 Opus 解码器
        IntBuffer error = IntBuffer.allocate(4);
        this.opusDecoder = Opus.INSTANCE.opus_decoder_create(samplerate, channels, error);
        this.seqLength = (int) (seqTime * this.samplerate * 2);
    }

    public short[] decode(String base64Audio) {
        // 1. 解码 Base64 音频数据
        byte[] audioBytes = Base64.getDecoder().decode(base64Audio);

        // 2. 创建用于存储解码后的数据的 ShortBuffer
        ShortBuffer decodedData = ShortBuffer.allocate(1024 * 1024);

        // 3. 解码 Opus 数据
        int decoded = Opus.INSTANCE.opus_decode(opusDecoder, audioBytes, audioBytes.length, decodedData, seqLength, 0);

        // 4. 返回解码后的短音频数据
        short[] result = new short[decoded];
        decodedData.get(result, 0, decoded);
        return result;
    }

    public byte[] decodeToBytes(String base64Audio) {
        // 1. 解码 Base64 音频数据
        byte[] audioBytes = Base64.getDecoder().decode(base64Audio);

        // 2. 创建用于存储解码后的数据的 ShortBuffer
        ShortBuffer decodedData = ShortBuffer.allocate(1024 * 1024);

        // 3. 解码 Opus 数据
        int decoded = Opus.INSTANCE.opus_decode(opusDecoder, audioBytes, audioBytes.length, decodedData, seqLength, 0);

        // 4. 转换 short[] 为 byte[]
        short[] shortData = new short[decoded];
        decodedData.get(shortData, 0, decoded);
        byte[] byteData = convertShortToByte(shortData);

        return byteData; // 返回 byte[] 类型的音频数据
    }

    private byte[] convertShortToByte(short[] shortArray) {
        byte[] byteArray = new byte[shortArray.length * 2];
        for (int i = 0; i < shortArray.length; i++) {
            byteArray[i * 2] = (byte) (shortArray[i] & 0xFF);        // 低字节
            byteArray[i * 2 + 1] = (byte) ((shortArray[i] >> 8) & 0xFF); // 高字节
        }
        return byteArray;
    }

    // 销毁解码器,释放资源
    public void close() {
        Opus.INSTANCE.opus_decoder_destroy(opusDecoder);
    }

    // 测试解码功能
    public static void main(String[] args) {
        // 假设这是接收到的 Base64 编码的音频数据 
        // 因为我的音频是先base了一下 所以我需要先用base64 解码,
        //如果你的音频没有 base64 这个步骤跳过即可
        String base64Audio =  ""; // 你的音频数据流
        // 创建解码器对象
        OpusDecoder decoder = new OpusDecoder(16000, 1, 0.02f);
        // 解码音频
        byte[] decodedAudio = decoder.decodeToBytes(base64Audio);
        // 打印解码结果长度
        System.out.println("Decoded audio length: " + decodedAudio.length);
        // 关闭解码器
        decoder.close();
    }
}


这个工具类的封装 也是我找的依赖 看他们的源码 自己封装的,
因为 开源的相关依赖没有提供非常完整的 使用文档,所以只能自己看源码 。
下面就是我在源码里看到的:
我的理解:
java 没有现成处理这种opus格式音频的能力,也许这就是为啥网上关于java处理这个音频的的文章比较少的原因。
看到源码后,这个依赖的解决方案就是,把可以处理 opus格式的 扩展打包到 java的jar里,然后通过java 来加载 这些 扩展,然后通过java调用这些扩展里的方法从来 实现 opus格式的音频解码。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2333222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3568 基于Gstreamer的多媒体调试记录

文章目录 1、环境介绍2、概念理清3、提前准备4、GStreamer编译5、GStreamer基础介绍6、视频播放初体验7、视频硬编码7.1、h2647.2、h265 8、视频硬解码8.1、解码视频并播放8.2、解码视频并播放带音频 1、环境介绍 硬件&#xff1a;飞凌ok3568-c开发板 软件&#xff1a;原厂rk…

VS Code 的 .S 汇编文件里面的注释不显示绿色

1. 确认文件语言模式 打开 .S 文件后&#xff0c;查看 VS Code 右下角的状态栏&#xff0c;确认当前文件的识别模式&#xff08;如 Assembly、Plain Text 等&#xff09;。如果显示为 Plain Text 或其他非汇编模式&#xff1a; 点击状态栏中的语言模式&#xff08;如 Plain Te…

5分钟读懂ArgoCD:在Kubernetes中实现持续部署

Kubernetes中的Argo CD介绍 Argo CD是用于Kubernetes的声明式GitOps持续交付工具。它遵循GitOps模式&#xff0c;以Git仓库作为定义所需应用程序状态的唯一真实来源&#xff0c;能在指定的目标环境中自动部署应用程序&#xff0c;并持续监控应用程序的运行状态&#xff0c;确保…

cs224w课程学习笔记-第10课

cs224w课程学习笔记-第10课 异构图 前言一、异构图1、异构图定义2、异构图与同构图 二、异构图下的GNN1、GCN扩展至RGCN1.1 RGCN原理1.2 异构图的任务预测特点1.3 异构图任务预测基础案例 2、完整的异构图GCN三、异构图下的Transformer 前言 异构图的定义是节点内部存在类型不…

OpenCV 图形API(26)图像滤波-----方框滤波函数boxFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 使用方框滤波器模糊图像。 该函数使用以下内核来平滑图像&#xff1a; K α [ 1 1 … 1 1 1 … 1 ⋮ ⋮ ⋱ ⋮ 1 1 … 1 ] K \alpha \begin{b…

大模型上下文协议MCP详解(2)—核心功能

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl1. 标准化上下文交互技术 1.1 实时数据接入能力 MCP(Model Context Protocol)通过标准化的接口,为 AI 模型提供了强大的实时数据接入能力,使其能够快速获取和处理来自不同数据源的实时信息。…

剑指Offer(数据结构与算法面试题精讲)C++版——day8

剑指Offer&#xff08;数据结构与算法面试题精讲&#xff09;C版——day8 题目一&#xff1a;链表中环的入口节点题目二&#xff1a;两个链表的第1个重合节点题目三&#xff1a;反转链表附录&#xff1a;源码gitee仓库 题目一&#xff1a;链表中环的入口节点 这道题的有如下三个…

【Qt】QxOrm:下载、安装、使用

1、下载源码 github地址:https://github.com/QxOrm/QxOrm 稳定版本下载:https://github.com/QxOrm/QxOrm/releases/tag/1.5.0 2、编译源码 QxOrm支持cmake编译(CMakeLists.txt)、Qt pro工程编译(QxOrm.pro) 以 QxOrm.pro 为例,编译生成的库,没有在 build-QxOrm-1.5…

CISCO组建RIP V2路由网络

1.实验准备&#xff1a; 2.具体配置&#xff1a; 2.1根据分配好的IP地址配置静态IP&#xff1a; 2.1.1PC配置&#xff1a; PC0&#xff1a; PC1&#xff1a; PC2&#xff1a; 2.1.2路由器配置&#xff1a; R0&#xff1a; Router>en Router#conf t Enter configuration…

【数学建模】(智能优化算法)鲸鱼优化算法(Whale Optimization Algorithm)详解与应用

鲸鱼优化算法(Whale Optimization Algorithm)详解与应用 文章目录 鲸鱼优化算法(Whale Optimization Algorithm)详解与应用1. 引言2. 算法原理2.1 生物学基础2.2 数学模型[^3]1. 包围猎物阶段2. 气泡网攻击&#xff08;螺旋更新&#xff09;3. 随机搜索猎物&#xff08;全局探索…

【深度洞察】解码饮料行业破局点:场景革命

当东鹏特饮以 “大瓶装 防尘盖” 精准解决货车司机的场景化需求&#xff0c;当农夫山泉通过 “冷藏版东方树叶” 打开年轻白领的早餐场景 —— 这些现象级案例背后&#xff0c;是饮料行业底层逻辑的深刻变革&#xff1a;真正的市场增量&#xff0c;藏在对消费场景的极致拆解中…

工业科学级天文相机:跨界融合的高精密成像解决方案

随着国内科技的快速发展&#xff0c;工业相机领域正悄然兴起一场"天文级"的技术革命。这类兼具工业设备可靠性与天文观测精度的特殊相机&#xff0c;正在半导体制造、天文观测、空间探测等领域开辟新的应用疆域。其核心技术突破不仅体现在传感器性能的提升&#xff0…

回文日期2

#include <bits/stdc.h> using namespace std; bool huiwen(int date) {int tempdate;int r0;while(temp>0){rr*10temp%10;temp/10;}return dater; }int main() {// 请在此输入您的代码int n,m;cin>>n>>m;int tempfn/100,tempem/100;int yearfn/10000,mon…

Ubuntu搭建Pytorch环境

Ubuntu搭建Pytorch环境 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Ubuntu搭建Pytorch环境前言一、Anaconda二、Cuda1.安装流程2、环境变量&#…

图书管理系统(Python)

运行结果&#xff1a; 源代码&#xff1a; # 定义一个图书类 class Book: def __init__(self, title, author, isbn): self.title title self.author author self.isbn isbn def show_info(self): print(f"{self.title},{self.author},{self.isbn}") # 图书列表…

大模型本地部署系列(3) Ollama部署QwQ[阿里云通义千问]

大家好&#xff0c;我是AI研究者&#xff0c; 今天教大家部署 一个阿里云通义千问大模型。 QwQ大模型简介 QwQ是由阿里云通义千问&#xff08;Qwen&#xff09;团队推出的开源推理大模型&#xff0c;专注于提升AI在数学、编程和复杂逻辑推理方面的能力。其核心特点包括&#x…

操作系统 4.1-I/O与显示器

外设工作起来 操作系统让外设工作的基本原理和过程&#xff0c;具体来说&#xff0c;它概括了以下几个关键步骤&#xff1a; 发出指令&#xff1a;操作系统通过向控制器中的寄存器发送指令来启动外设的工作。这些指令通常是通过I/O指令&#xff08;如out指令&#xff09;来实现…

前端-Vue3

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n 经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#xff0c;最…

Facebook账号类型一览

对于跨境出海从业者来说&#xff0c;Facebook是必不可少的内容营销和广告投放平台。针对Facebook的营销策略和发挥空间都很丰富&#xff0c;因此了解Facebook账号的类型、特点、适用场景和相关工具还是很有用的。 一、账号类型及特点 1.小黑号 无主页、无好友、无历史操作&am…

Java学习手册:Java基本语法与数据类型

Java语言以其简洁明了的语法和强大的数据类型系统而闻名。掌握Java的基本语法和数据类型是成为一名合格Java开发者的第一步。本文将深入探讨Java的基本语法结构和数据类型&#xff0c;帮助读者打下坚实的基础。 Java的基本语法 Java语言的语法设计简洁而强大&#xff0c;强调…