Fork me on GitHub
0%

Opus Ogg详解

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/

  1. op_open_file() / op_free()

    打开/关闭一个解码器

  2. op_head() / op_tags()

  • op_head函数可用于获取channels、samplerate等参数

  • op_tags函数可获得用户自定义参数,例如:标题、歌手、编码方式标准等等,其中tags->user_comments[i]可获取用户自定义的信息

  1. op_pcm_total() / op_pcm_tell() / op_pcm_seek()
  • op_pcm_total 可以返回该opus文件转换成pcm文件后的总的pcm长度
  • op_pcm_tell 可以放回目前文件已经播放的pcm的长度
  • op_pcm_seek 可以通过参数指定让音频进行跳转播放
  1. op_pcm_read()

从op_open_file打开的文件流中读取pcm数据进行播放。注意解码的数量并不等于传入buffer的大小,需要使用到该函数的返回值

Ogg

参考 : https://juejin.cn/post/6844904016254599175

全称:OGGVobis(oggVorbis) 一个自由且开放标准的容器格式,“.ogg”结尾命名

OGG是以页(page)为单位将逻辑流组织链接起来,每个页都有pageheader和pagedata。

  1. capture_pattern页标识:ASCII字符,0x4f ‘O’ 0x67 ‘g’ 0x67 ‘g’ 0x53 ‘S’,4个字节大小,它标识着一个页的开始。
  2. stream_structure_version版本id:一般当前版本默认为0,1个字节。
  3. header_type_flag类型标识:标识当前的页的类型,1个字节, - 0x01:本页媒体编码数据与前一页属于同一个逻辑流的同一个packet,若此位没有设,表示本页是以一个新的packet开始的; - 0x02:表示该页为逻辑流的第一页,bos标识,如果此位未设置,那表示不是第一页; - 0x04:表示该页位逻辑流的最后一页,eos标识,如果此位未设置,那表示本页不是最后一页。
  4. granule_position:媒体编码相关的参数信息,8个字节,对于音频流来说,它存储着到本页为止逻辑流在PCM输出中采样码的数目,可以由它来算得时间戳。对于视频流来说,它存储着到本页为止视频帧编码的数目。若此值为-1,那表示截止到本页,逻辑流的packet未结束。(小端)
  5. serial_number:当前页中的流的id,4个字节,它是区分本页所属逻辑流与其他逻辑流的序号,我们可以通过这个值来划分流。(小端)
  6. page_seguence_number:本页在逻辑流的序号,4个字节。
  7. CRC_cbecksum:循环冗余效验码效验,4个字节,用来效验每页的有效性。
  8. number_page_segments:给定本页在segment_table域中出现的segement个数,1个字节。
  9. 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,同理。