opus是什么
以下内容取自opus官网:https://www.opus-codec.org
定义
Opus 是一种完全开放、免版税、用途广泛的音频编解码器。 Opus 在 Internet 上的交互式语音和音乐传输方面无与伦比,但也适用于存储和流媒体应用。它被互联网工程任务组 (IETF) 标准化为 RFC 6716,它结合了 Skype 的 SILK 编解码器和 Xiph.Org 的 CELT 编解码器的技术。
特点
Opus 可以处理范围广泛的音频应用,包括 IP 语音、视频会议、游戏内聊天,甚至远程现场音乐表演。它可以从低比特率窄带语音扩展到非常高质量的立体声音乐。支持的功能有:
- 比特率从 6 kb/s 到 510 kb/s
- 采样率从 8 kHz(窄带)到 48 kHz(全带)
- 帧大小从 2.5 ms 到 60 ms
- 支持恒定比特率 (CBR) 和可变比特率 (VBR)
- 从窄带到全带的音频带宽
- 支持语音和音乐
- 支持单声道和立体声
- 支持多达 255 个通道(多流帧)
- 动态可调比特率、音频带宽和帧大小
- 良好的丢包鲁棒性和丢包隐藏 (PLC)
- 浮点和定点实现
优点
音频带宽。Opus编码器覆盖了低频段到高频段的全带音频
低延迟。延迟依赖于帧规格,Opus最低帧规格2.5ms,非常适合实时音视频场景
opus库
概述
编解码器libopus: https://www.opus-codec.org/docs/opus_api-1.2/index.html
封装器opusfile:https://www.opus-codec.org/docs/opusfile_api-0.7/index.html
opus库包括三部分:libopus、opus-tools、opusfile
- libopus:opus编解码的源码和可执行文件(注意:这里编码出来的opus文件是播放不了的,并且解码也必须用那种播放不了的opus文件,后面解释为什么)
- opus-tools:工具包,其中包含了libogg(.wav2.opus / .opus2.wav)
- opusfile:将可播放的opus文件解码成wav的工具,可分析出这个可播放的opus文件的信息,其中包含了libogg
可播放opus与不可播放opus文件
ogg文件里面包含了opus编码的音频,相当于MP4文件中包含了aac
- 不可播放opus:只有编码层opus数据的音频(没有ogg的封装只经过libopus编码),后缀名是.opus
- 可播放的opus:opus编码的音频外部套用了一层ogg的封装(经过ogg的封装,opus-tools编码的文件),后缀名可以是.opus也可以是.ogg
opus结构
每个 Opus 包以一个 TOC (Table of Contents)字节开头
配置数(config) | 编码模式 | 音频带宽 | 帧长度 |
---|---|---|---|
0…3 | SILK-only | NB | 10, 20, 40, 60 ms |
4…7 | SILK-only | MB | 10, 20, 40, 60 ms |
8…11 | SILK-only | WB | 10, 20, 40, 60 ms |
12…13 | Hybrid | SWB | 10, 20 ms |
14…15 | Hybrid | FB | 10, 20 ms |
16…19 | CELT-only | NB | 2.5, 5, 10, 20 ms |
20…23 | CELT-only | WB | 2.5, 5, 10, 20 ms |
24…27 | CELT-only | SWB | 2.5, 5, 10, 20 ms |
28…31 | CELT-only | FB | 2.5, 5, 10, 20 ms |
立体声标志位(s)取值 0 表示单声道,1 表示多声道立体声。
TOC 中最后两位(c)表示:
- 0:一个包中只有一帧音频。
- 1:一个包中有两帧音频,并且大小相同。
- 2:一个包中有两帧音频,但是大小不同。
opusfile API
opusfile高级API官方文档:https://opus-codec.org/docs/opusfile_api-0.12/
参考文档:
https://juejin.cn/post/6844903998831460360
https://chenliang.org/2020/04/17/ogg-encapsulation-for-opus/
op_open_file() / op_free()
打开/关闭一个解码器
op_head() / op_tags()
op_head函数可用于获取channels、samplerate等参数
op_tags函数可获得用户自定义参数,例如:标题、歌手、编码方式标准等等,其中tags->user_comments[i]可获取用户自定义的信息
- op_pcm_total() / op_pcm_tell() / op_pcm_seek()
- op_pcm_total 可以返回该opus文件转换成pcm文件后的总的pcm长度
- op_pcm_tell 可以放回目前文件已经播放的pcm的长度
- op_pcm_seek 可以通过参数指定让音频进行跳转播放
- op_pcm_read()
从op_open_file打开的文件流中读取pcm数据进行播放。注意解码的数量并不等于传入buffer的大小,需要使用到该函数的返回值
Ogg
全称:OGGVobis(oggVorbis) 一个自由且开放标准的容器格式,“.ogg”结尾命名
OGG是以页(page)为单位将逻辑流组织链接起来,每个页都有pageheader和pagedata。
- capture_pattern页标识:ASCII字符,0x4f ‘O’ 0x67 ‘g’ 0x67 ‘g’ 0x53 ‘S’,4个字节大小,它标识着一个页的开始。
- stream_structure_version版本id:一般当前版本默认为0,1个字节。
- header_type_flag类型标识:标识当前的页的类型,1个字节, - 0x01:本页媒体编码数据与前一页属于同一个逻辑流的同一个packet,若此位没有设,表示本页是以一个新的packet开始的; - 0x02:表示该页为逻辑流的第一页,bos标识,如果此位未设置,那表示不是第一页; - 0x04:表示该页位逻辑流的最后一页,eos标识,如果此位未设置,那表示本页不是最后一页。
- granule_position:媒体编码相关的参数信息,8个字节,对于音频流来说,它存储着到本页为止逻辑流在PCM输出中采样码的数目,可以由它来算得时间戳。对于视频流来说,它存储着到本页为止视频帧编码的数目。若此值为-1,那表示截止到本页,逻辑流的packet未结束。(小端)
- serial_number:当前页中的流的id,4个字节,它是区分本页所属逻辑流与其他逻辑流的序号,我们可以通过这个值来划分流。(小端)
- page_seguence_number:本页在逻辑流的序号,4个字节。
- CRC_cbecksum:循环冗余效验码效验,4个字节,用来效验每页的有效性。
- number_page_segments:给定本页在segment_table域中出现的segement个数,1个字节。
- segment_table:从字面看它就是一个表,表示着每个segment的长度,取值范围是0~255。由segment(1个segment就是1个字节)可以得到packet的值,每个packet的大小是以最后一个不等于255的segment结束的,从页头中的segment_table可以得到每个packet长度,举例:如果一组segment依次顺序为FF 45 FF FF FF 40FF 05FF FF FF 66(共4个packet,含12个segment,每个packet的长度是:FF 45【324】;FF FF FF 40【829】;FF 05【260】;FF FF FF 66【847】),那么第一个packet的长度为255+69 = 324,第二个packet大小829,同理。