😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍opus编解码库(opus-1.4)的使用🍭
😎金句分享😎:🍭🍭
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、opus 库编译
- ✨2.1 编译环境
- ✨2.2 opus-1.4 库编译
- ✨2.3 opus_demo 使用
- 🎄三、opus-1.4 库函数介绍
- ✨3.1 opus 编码相关库函数
- ✨3.2 opus 解码相关库函数
- 🎄四、opus 解码流程及源码
- 🎄五、总结
🎄一、概述
Opus是一款完全开放、免版税、高度通用的音频编解码器。Opus在互联网上的交互式语音和音乐传输方面无与伦比,但也适用于存储和流媒体应用。它被互联网工程任务组(IETF)标准化为 RFC 6716,它结合了Skype的SILK编解码器和Xiph.Org的CELT编解码器的技术。
Opus可以处理广泛的音频应用程序,包括IP语音、视频会议、游戏内聊天,甚至远程现场音乐表演。它可以从低比特率的窄带语音扩展到非常高质量的立体声音乐。支持的功能包括:
-
比特率从6 kb/s到510 kb/s
-
采样率从8kHz(窄带)到48kHz(全频带)
-
帧大小从2.5毫秒到60毫秒
-
支持恒定比特率(CBR)和可变比特率(VBR)
-
从窄带到全频带的音频带宽
-
支持语音和音乐
-
支持单声道和立体声
-
最多支持255个通道(多流帧)
-
可动态调整的比特率、音频带宽和帧大小
-
良好的丢失鲁棒性和丢包隐藏性(PLC)
-
浮点和定点实现
需要了解更多opus的内容,可以到opus官网:https://www.opus-codec.org 。
🎄二、opus 库编译
下载 opus 库,点击链接:https://www.opus-codec.org/downloads/,本文下载的是opus-1.4.tar.gz
。
✨2.1 编译环境
$ uname -a
Linux ubuntu 4.4.0-128-generic #154~14.04.1-Ubuntu SMP Fri May 25 14:58:51 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.5 LTS
Release: 14.04
Codename: trusty
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04.4' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)
✨2.2 opus-1.4 库编译
tar zxvf opus-1.4.tar.gz
cd opus-1.4/
./configure --prefix=`pwd`/result_gcc
make && make install
✨2.3 opus_demo 使用
opus-1.4 库编译之后,在opus-1.4/.libs
目录会出现一个名为 opus_demo
的可执行程序,该程序的源码在opus-1.4/src/opus_demo.c
路径。
opus_demo
是演示 opus-1.4 库 API 函数的一个demo,功能是将PCM音频文件编码成opus数据,或者将opus数据解码成PCM文件。注意,它编码出来的opus并不能直接使用VLC播放,因为只是一些数据包,并没有封装成VLC可识别的音频文件。
使用下面命令进行opus编码,这里将
48000Hz-16bit-2ch-ChengDu.pcm
作为输入文件,输入采样率48000、通道数2、510000的比特流,最后编码输出opus_demo.out
文件:./opus_demo -e audio 48000 2 510000 48000Hz-16bit-2ch-ChengDu.pcm opus_demo.out
使用下面命令可以将上面的输出文件
opus_demo.out
还原回PCM音频文件opus_demo_dec.pcm
./opus_demo -d 48000 2 opus_demo.out opus_demo_dec.pcm
🎄三、opus-1.4 库函数介绍
opus-1.4 的库函数都在 opus.h
头文件中,库函数总共分为下面6个部分,在头文件搜索defgroup
可以依次跳到各个部分开头,现在只有前三个部分。:
- opus_encoder :编码相关
- opus_decoder :解码相关
- opus_repacketizer :重新打包器相关
- opus_multistream
- opus_libinfo
- opus_custom
每个API函数在 opus.h
头文件中都要详细的英文解释,部分函数还有实例代码,如果还有不懂,就看opus_demo.c
的代码,也有助于清楚怎么使用。
下面摘取个别常用的库函数:
✨3.1 opus 编码相关库函数
int opus_encoder_get_size(int channels);
功能:获取一个 OpusEncoder 结构体的大小
参数:
channels:通道数,必须1或2;
返回值:以字节为单位的大小
//---------------------------------------
OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, int *error);
功能:分配并初始化编码器状态
参数:
Fs:采样率,必须是 8000, 12000, 16000, 24000, 48000 之一;
channels:声道数,1或2;
application:OPUS_APPLICATION_VOIP 或 OPUS_APPLICATION_AUDIO 或 PUS_APPLICATION_RESTRICTED_LOWDELAY
error:输出参数,错误码;
返回值:成功返回编码器指针,失败返回NULL;
//---------------------------------------
int opus_encoder_init(OpusEncoder *st, opus_int32 Fs, int channels, int application);
功能:初始化之前分配的编码器状态;
//---------------------------------------
opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes);
功能:编码一个Opus帧;
//---------------------------------------
opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes);
功能:从浮点输入编码一个Opus帧
//---------------------------------------
void opus_encoder_destroy(OpusEncoder *st);
功能:释放 opus_encoder_create 分配的 OpusEncoder 指针;
//---------------------------------------
int opus_encoder_ctl(OpusEncoder *st, int request, ...);
功能:在Opus编码器上执行控制功能。
✨3.2 opus 解码相关库函数
int opus_decoder_get_size(int channels);
功能:获取一个 OpusDecoder 结构体的大小
参数:
channels:通道数,必须1或2;
返回值:以字节为单位的大小
//---------------------------------------
OpusDecoder *opus_decoder_create(opus_int32 Fs,int channels,int *error);
功能:分配并初始化解码器状态
参数:
Fs:采样率,必须是 8000, 12000, 16000, 24000, 48000 之一;
channels:声道数,1或2;
error:输出参数,错误码;
返回值:成功返回解码器指针,失败返回NULL;
//---------------------------------------
int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels);
功能:初始化之前分配的解码器状态;
//---------------------------------------
int opus_decode(OpusDecoder *st, const unsigned char *data, opus_int32 len,
opus_int16 *pcm, int frame_size, int decode_fec);
功能:解码一个Opus数据包。
//---------------------------------------
int opus_decode_float(OpusDecoder *st, const unsigned char *data, opus_int32 len,
float *pcm, int frame_size, int decode_fec);
功能:用浮点输出解码一个Opus数据包。
//---------------------------------------
int opus_decoder_ctl(OpusDecoder *st, int request, ...);
功能:在Opus解码器上执行控制功能。
//---------------------------------------
void opus_decoder_destroy(OpusDecoder *st);
功能:释放 opus_decoder_create分配的 OpusDecoder 指针;
//---------------------------------------
int opus_packet_parse(const unsigned char *data,opus_int32 len, unsigned char *out_toc,
const unsigned char *frames[48],opus_int16 size[48],int *payload_offset);
//---------------------------------------
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
/** Gets the number of samples per frame from an Opus packet.
* @param [in] data <tt>char*</tt>: Opus packet.
* This must contain at least one byte of
* data.
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
* This must be a multiple of 400, or
* inaccurate results will be returned.
* @returns Number of samples per frame.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
/** Gets the number of channels from an Opus packet.
* @param [in] data <tt>char*</tt>: Opus packet
* @returns Number of channels
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
/** Gets the number of frames in an Opus packet.
* @param [in] packet <tt>char*</tt>: Opus packet
* @param [in] len <tt>opus_int32</tt>: Length of packet
* @returns Number of frames
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
/** Gets the number of samples of an Opus packet.
* @param [in] packet <tt>char*</tt>: Opus packet
* @param [in] len <tt>opus_int32</tt>: Length of packet
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
* This must be a multiple of 400, or
* inaccurate results will be returned.
* @returns Number of samples
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
/** Gets the number of samples of an Opus packet.
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
* @param [in] packet <tt>char*</tt>: Opus packet
* @param [in] len <tt>opus_int32</tt>: Length of packet
* @returns Number of samples
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
* the signal is already in that range, nothing is done. If there are values
* outside of [-1,1], then the signal is clipped as smoothly as possible to
* both fit in the range and avoid creating excessive distortion in the
* process.
* @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM
* @param [in] frame_size <tt>int</tt> Number of samples per channel to process
* @param [in] channels <tt>int</tt>: Number of channels
* @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)
*/
OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
🎄四、opus 解码流程及源码
opus 解码流程:
1、创建 opus 解码器:opus_decoder_create;
2、配置 opus 解码器:opus_decoder_ctl;
3、取出 opus 包;
4、使用 opus_decode 函数对 opus 包解码;
示例代码:
/**
* @file opusDec.h
* @author wkd_007
* @date 2023-10-27 15:47:38
*/
#ifndef __OPUS_DEC_H__
#define __OPUS_DEC_H__
#include "opus/opus.h"
#define MAX_OPUS_DEC_FRAME 48000 // opus解码最大采样点个数,如果个数时间小于120ms,可能停止解码,这里设置1000ms的个数
#define OPUS_DEC_CHANNELS 2
class COpusDec
{
public:
COpusDec();
~COpusDec();
int CreateOpusDecoder(int sampleRate, int channels);
int OpusDecode(unsigned char* in_data, int in_len, short *out_buf);
private:
OpusDecoder *decoder; // opus 解码器指针
int sample_rate; // 采样率
int channel_num; // 通道数
};
#endif// __OPUS_DEC_H__
/**
* @file opusDec.cpp
* @author wkd_007
* @brief opus 解码
* @date 2023-10-27 15:38:43
*/
#include <stdio.h>
#include "opusDec.h"
COpusDec::COpusDec()
{
decoder = NULL;
sample_rate = 0;
channel_num = 0;
}
COpusDec::~COpusDec()
{
sample_rate = 0;
channel_num = 0;
if(decoder)
{
opus_decoder_destroy(decoder);
decoder = NULL;
}
}
int COpusDec::CreateOpusDecoder(int sampleRate, int channels)
{
int err = 0;
decoder = opus_decoder_create(sampleRate, channels, &err);
if(err != OPUS_OK || decoder == NULL)
{
printf("[%s %d]err=%d decoderIsNULL=%d\n",__FILE__,__LINE__,err, decoder == NULL);
return -1;
}
opus_decoder_ctl(decoder, OPUS_SET_LSB_DEPTH(16));
sample_rate = sampleRate;
channel_num = channels;
return err;
}
int COpusDec::OpusDecode(unsigned char* in_data, int in_len, short *out_buf)
{
if(decoder == NULL)
return -1;
int frame_size = opus_decode(decoder, in_data, in_len, out_buf, MAX_OPUS_DEC_FRAME, 0);
if (frame_size < 0)
{
printf("[%s %d] frame_size=%d in_len=%d\n",__FILE__,__LINE__, frame_size,in_len);
return frame_size;
}
return frame_size;
}
🎄五、总结
本文介绍了opus-1.4 库的下载、编译,demo程序的使用,以及简单介绍常用的opus编解码库函数 ,最后给出opus解码示例代码;
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考资料:
从RTP包中分析OPUS码流:https://blog.csdn.net/hclbeloved/article/details/115528990
libopus 实现pcm 编码到opus:https://blog.csdn.net/sinat_27720649/article/details/126530085