绝大数人都知道mp3格式编码,以及aac,amr等压缩格式编码。

而在语音通信界有一个强悍的音频格式编码opus.

经过实测,压缩比最高可以达到1:10。

100KB 压缩后 10KB

虽然是有损压缩,

但是根据实际对比试听,

几乎听不出差别。

而且还原度还比mp3高,压缩比也比mp3高。

用来压缩传输音频,绝对是一大杀器。

项目官方地址:

https://opus-codec.org/

维基上的描述:

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

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

更重要的是要看这条:

Opus被提出用于在IETF上标准化新的音频格式,最终被IETF编解码器工作组接受和授予。它基于Xiph.Org基金会和Skype技术公司两项最初分开的标准提案。其主要开发人员包括Jean-Marc Valin(Xiph.Org,Octasic,Mozilla Corporation),Koen Vos(Skype)和Timothy B. Terriberry(Xiph.Org,Mozilla Corporation)。其中包括Juin-Hwey(Raymond)Chen(Broadcom),Gregory Maxwell(Xiph.Org,Wikimedia)和Christopher Montgomery(Xiph.Org)也参与其中。

这个项目被几大公司加持,也难怪能有如此出色的压缩比。

由于是纯C代码,比较好理解。

抽了点空,俺写个wav压缩解压的示例代码,

分享出来,权当抛砖引玉。

示例代码位置:

https://github.com/cpuimage/opus/blob/master/example/opus.cpp

贴上完整C++代码:

#include <opus_types.h>
#include  <opus.h>
#include <cstring>
#include <memory>

#include <vector>
// https://github.com/mackron/dr_libs/blob/master/dr_wav.h
#define DR_WAV_IMPLEMENTATION

#include "dr_wav.h"

#define FRAME_SIZE 480
#define MAX_FRAME_SIZE (6*FRAME_SIZE)

#define MAX_CHANNELS 1
#define MAX_PACKET_SIZE (3*1276)

#pragma pack(push)
#pragma pack(1)

struct WavInfo {
    uint16_t channels;
    uint32_t sampleRate;
    uint32_t bitsPerSample;
};

#pragma pack(pop)

#ifndef  nullptr
#define  nullptr NULL
#endif

class FileStream {
public:
    FileStream() {
        cur_pos = ;
    }

    void Append(const char *data, size_t size) {
        if (cur_pos + size > Size()) {
            vec.resize(cur_pos + size);
        }
        memcpy(vec.data() + cur_pos, data, size);
        cur_pos += size;
    }

    void AppendU32(uint32_t val) {
        Append((char *) (&val), sizeof(val));
    }

    char *Data() {
        return vec.data();
    }

    size_t Size() {
        return vec.size();
    }

    size_t Read(void *buff, size_t elemSize, size_t elemCount) {
        size_t readed = std::min((vec.size() - cur_pos), (elemCount * elemSize)) / elemSize;
        ) {
            memcpy(buff, vec.data() + cur_pos, readed * elemSize);
            cur_pos += readed * elemSize;
        }
        return readed;
    }

    bool SeekCur(int offset) {
        if (cur_pos + offset > vec.size()) {
            cur_pos = !vec.empty() ? (vec.size() - ) : ;
            return false;
        } else {
            cur_pos += offset;
            return true;
        }
    }

    ) {
        cur_pos = ;
        return SeekCur(offset);
    }

    bool WriteToFile(const char *filename) {
        FILE *fin = fopen(filename, "wb");
        if (!fin) {
            return false;
        }
        fseek(fin, , SEEK_SET);
        fwrite(vec.data(), sizeof(char), vec.size(), fin);
        fclose(fin);
        return true;
    }

    bool ReadFromFile(const char *filename) {
        FILE *fin = fopen(filename, "rb");
        if (!fin) {
            return false;
        }
        fseek(fin, , SEEK_END);
        long fileSize = ftell(fin);
        vec.resize(static_cast<unsigned long long int>(fileSize));
        fseek(fin, , SEEK_SET);
        fread(vec.data(), sizeof(char), vec.size(), fin);
        fclose(fin);
        return true;
    }

private:
    std::vector<char> vec;
    size_t cur_pos;
};

bool Wav2Opus(FileStream *input, FileStream *output);

bool Opus2Wav(FileStream *input, FileStream *output);

bool wav2stream(char *input, FileStream *output);

bool stream2wav(FileStream *input, char *output);

bool wavWrite_int16(char *filename, int16_t *buffer, int sampleRate, uint32_t totalSampleCount) {
    drwav_data_format format = {};
    format.container = drwav_container_riff;     // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
    format.format = DR_WAVE_FORMAT_PCM;          // <-- Any of the DR_WAVE_FORMAT_* codes.
    format.channels = ;
    format.sampleRate = (drwav_uint32) sampleRate;
    format.bitsPerSample = ;
    drwav *pWav = drwav_open_file_write(filename, &format);
    if (pWav) {
        drwav_uint64 samplesWritten = drwav_write(pWav, totalSampleCount, buffer);
        drwav_uninit(pWav);
        if (samplesWritten != totalSampleCount) {
            fprintf(stderr, "ERROR\n");
            return false;
        }
        return true;
    }
    return false;
}

int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint64_t *totalSampleCount) {
    unsigned int channels;
    int16_t *buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
    if (buffer == nullptr) {
        fprintf(stderr, "ERROR\n");
        return nullptr;
    }
    ) {
        drwav_free(buffer);
        buffer = nullptr;
        *sampleRate = ;
        *totalSampleCount = ;
    }
    return buffer;
}

bool wav2stream(char *input, FileStream *output) {
    uint32_t sampleRate = ;
    uint64_t totalSampleCount = ;
    int16_t *wavBuffer = wavRead_int16(input, &sampleRate, &totalSampleCount);
    if (wavBuffer == nullptr) return false;
    WavInfo info = {};
    info.bitsPerSample = ;
    info.sampleRate = sampleRate;
    info.channels = ;
    output->SeekBeg();
    output->Append((char *) &info, sizeof(info));
    output->Append((char *) wavBuffer, totalSampleCount * sizeof(int16_t));
    free(wavBuffer);
    return true;
}

bool stream2wav(FileStream *input, char *output) {
    WavInfo info = {};
    input->SeekBeg();
    size_t read = input->Read(&info, );
    ) {
        return false;
    }
    size_t totalSampleCount = (input->Size() - ;
    return wavWrite_int16(output, (int16_t *) (input->Data() + sizeof(info)), info.sampleRate,
                          static_cast<uint32_t>(totalSampleCount));
}

bool Wav2Opus(FileStream *input, FileStream *output) {
    WavInfo in_info = {};
    input->SeekBeg();
    size_t read = input->Read(&in_info, );
    ) {
        return false;
    }
    uint32_t bitsPerSample = in_info.bitsPerSample;
    uint32_t sampleRate = in_info.sampleRate;
    uint16_t channels = in_info.channels;
    ;
    if (channels > MAX_CHANNELS) {
        return false;
    }
    OpusEncoder *encoder = opus_encoder_create(sampleRate, channels, OPUS_APPLICATION_AUDIO, &err);
    ) {
        fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err));
        if (!encoder) {
            opus_encoder_destroy(encoder);
        }
        return false;
    }
    const uint16_t *data = (uint16_t *) (input->Data() + sizeof(in_info));
    size_t size = (input->Size() - ;
    opus_int16 pcm_bytes[FRAME_SIZE * MAX_CHANNELS];
    size_t index = ;
    size_t step = static_cast<size_t>(FRAME_SIZE * channels);
    FileStream encodedData;
    unsigned char cbits[MAX_PACKET_SIZE];
    size_t frameCount = ;
    size_t readCount = ;
    while (index < size) {
        memset(&pcm_bytes, , sizeof(pcm_bytes));
        if (index + step <= size) {
            memcpy(pcm_bytes, data + index, step * sizeof(uint16_t));
            index += step;
        } else {
            readCount = size - index;
            memcpy(pcm_bytes, data + index, (readCount) * sizeof(uint16_t));
            index += readCount;
        }
        int nbBytes = opus_encode(encoder, pcm_bytes, channels * FRAME_SIZE, cbits, MAX_PACKET_SIZE);
        ) {
            fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes));
            break;
        }
        ++frameCount;
        encodedData.AppendU32(static_cast<uint32_t>(nbBytes));
        encodedData.Append((char *) cbits, static_cast<size_t>(nbBytes));
    }
    WavInfo info = {};
    info.bitsPerSample = bitsPerSample;
    info.sampleRate = sampleRate;
    info.channels = channels;
    output->SeekBeg();
    output->Append((char *) &info, sizeof(info));
    output->Append(encodedData.Data(), encodedData.Size());
    opus_encoder_destroy(encoder);
    return true;
}

bool Opus2Wav(FileStream *input, FileStream *output) {
    WavInfo info = {};
    input->SeekBeg();
    size_t read = input->Read(&info, );
    ) {
        return false;
    }
    int channels = info.channels;
    if (channels > MAX_CHANNELS) {
        return false;
    }
    output->SeekBeg();
    output->Append((char *) &info, sizeof(info));
    ;
    OpusDecoder *decoder = opus_decoder_create(info.sampleRate, channels, &err);
    ) {
        fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
        if (!decoder) {
            opus_decoder_destroy(decoder);
        }
        return false;
    }
    unsigned char cbits[MAX_PACKET_SIZE];
    opus_int16 out[MAX_FRAME_SIZE * MAX_CHANNELS];
    ;
    while (true) {
        uint32_t nbBytes;
        size_t readed = input->Read(&nbBytes, );
        ) {
            break;
        }

        if (nbBytes > sizeof(cbits)) {
            fprintf(stderr, "nbBytes > sizeof(cbits)\n");
            break;
        }
        readed = input->Read(cbits, sizeof(char), nbBytes);
        if (readed != nbBytes) {
            fprintf(stderr, "readed != nbBytes\n");
            break;
        }
        );
        ) {
            fprintf(stderr, "decoder failed: %s\n", opus_strerror(frame_size));
            break;
        }
        ++frameCount;
        output->Append((]));
    }
    opus_decoder_destroy(decoder);
    return true;
}

void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {
    const char *end;
    const char *p;
    const char *s;
    ] && path[] == ':') {
        if (drv) {
            *drv++ = *path++;
            *drv++ = *path++;
            *drv = '\0';
        }
    } else if (drv)
        *drv = '\0';
    for (end = path; *end && *end != ':';)
        end++;
    for (p = end; p > path && *--p != '\\' && *p != '/';)
        if (*p == '.') {
            end = p;
            break;
        }
    if (ext)
        for (s = end; (*ext = *s++);)
            ext++;
    for (p = end; p > path;)
        if (*--p == '\\' || *p == '/') {
            p++;
            break;
        }
    if (name) {
        for (s = p; s < end;)
            *name++ = *s++;
        *name = '\0';
    }
    if (dir) {
        for (s = path; s < p;)
            *dir++ = *s++;
        *dir = '\0';
    }
}

void opus2wav(const char *in_file, char *out_file) {
    FileStream input;
    FileStream output;
    input.ReadFromFile(in_file);
    Opus2Wav(&input, &output);
    stream2wav(&output, out_file);
}

void wav2opus(char *in_file, char *out_file) {
    FileStream input;
    FileStream output;
    wav2stream(in_file, &input);
    Wav2Opus(&input, &output);
    output.WriteToFile(out_file);
}

int main(int argc, char *argv[]) {
    printf("Opus Demo\n");
    printf("blog:http://tntmonks.cnblogs.com/\n");
    printf("e-mail:gaozhihan@vip.qq.com\n");
    )
        ;
    ];
    ];
    ];
    ];
    ];
    ];
    splitpath(in_file, drive, dir, fname, ext);
    ) {
        sprintf(out_file, "%s%s%s.out", drive, dir, fname);
        wav2opus(in_file, out_file);
    } ) {
        sprintf(out_file, "%s%s%s_out.wav", drive, dir, fname);
        opus2wav(in_file, out_file);
    }
    printf("done.\n");
    printf("press any key to exit.\n");
    getchar();
    ;
}

项目地址:

https://github.com/cpuimage/opus

示例具体流程为:

1.压缩

加载wav(拖放wav文件到可执行文件上)->压缩->保存为out

2.解压

加载out(拖放out文件到可执行文件上)->解压->保存为wav

示例比较简单,用cmake即可进行编译示例代码,详情见CMakeLists.txt。

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

音频压缩编码 opus 附完整C++代码示例的更多相关文章

  1. 音频降噪算法 附完整C代码

    降噪是音频图像算法中的必不可少的. 目的肯定是让图片或语音 更加自然平滑,简而言之,美化. 图像算法和音频算法 都有其共通点. 图像是偏向 空间 处理,例如图片中的某个区域. 图像很多时候是以二维数据 ...

  2. 基于RNN的音频降噪算法 (附完整C代码)

    前几天无意间看到一个项目rnnoise. 项目地址: https://github.com/xiph/rnnoise 基于RNN的音频降噪算法. 采用的是 GRU/LSTM 模型. 阅读下训练代码,可 ...

  3. 基于傅里叶变换的音频重采样算法 (附完整c代码)

    前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...

  4. 音频增益响度分析 ReplayGain 附完整C代码示例

    人们所熟知的图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...

  5. 音频增益响度分析 ReplayGain 附完整C代码示例【转】

    转自:http://www.cnblogs.com/cpuimage/p/8846951.html 人们所熟知的图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像 ...

  6. WebRTC 音频采样算法 附完整C++示例代码

    之前有大概介绍了音频采样相关的思路,详情见<简洁明了的插值音频重采样算法例子 (附完整C代码)>. 音频方面的开源项目很多很多. 最知名的莫过于谷歌开源的WebRTC, 其中的音频模块就包 ...

  7. 音频自动增益 与 静音检测 算法 附完整C代码

    前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用于评估一定长度音频的音量强度, 而分析之后,很多类似的需求,肯定是做音频增益,提高音量诸如此类做法. ...

  8. 音频自动增益 与 静音检测 算法 附完整C代码【转】

    转自:https://www.cnblogs.com/cpuimage/p/8908551.html 前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用 ...

  9. 经典傅里叶算法小集合 附完整c代码

    前面写过关于傅里叶算法的应用例子. <基于傅里叶变换的音频重采样算法 (附完整c代码)> 当然也就是举个例子,主要是学习傅里叶变换. 这个重采样思路还有点瑕疵, 稍微改一下,就可以支持多通 ...

随机推荐

  1. Django+xadmin打造在线教育平台(十)

    十四.xadmin的进阶开发 14.1.权限管理 (1)用户权限 超级用户拥有所有权限,其它添加的用户默认没有任何权限 进后台添加一个用户“Editor1”,勾上“职员状态”后,这个用户才可以登录进后 ...

  2. SpringMVC学习笔记三 整合jdbc和事务

    spring整合JDBC spring提供了很多模板整合Dao技术,用于简化编程. 引入相关jar包 spring中提供了一个可以操作数据库的对象,JDBCTemplate(JDBC模板对象).对象封 ...

  3. Alpha第六天

    Alpha第六天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  4. Beta冲刺第六天

    一.昨天的困难 没有困难. 二.今天进度 1.林洋洋:更新申请ip为域名,去除druid数据源统计 2.黄腾达:协作详情中添加成员对话框优化 3.张合胜:修复侧栏菜单mini状态下不能显示问题 三.明 ...

  5. 用virtualenv建立多个Python独立开发环境

    不同的人喜欢用不同的方式建立各自的开发环境,但在几乎所有的编程社区,总有一个(或一个以上)开发环境让人更容易接受. 使用不同的开发环境虽然没有什么错误,但有些环境设置更容易进行便利的测试,并做一些重复 ...

  6. android头像选择(拍照,相册,裁剪)

    组织头像上传时候,不兼容android6.0,并且 imageview.setImageBitmap(BitmapFactory.decodeFile(IMAGE_FILE_LOCATION));// ...

  7. Cypher语法

    cypher是neo4j官网提供的声明式查询语言,非常强大,用它可以完成任意的图谱里面的查询过滤,我们知识图谱的一期项目 基本开发完毕,后面会陆续总结学习一下neo4j相关的知识.今天接着上篇文章来看 ...

  8. Something about SeekingJob---Resume简历

    这几天脑子里满满的装的都是offer.offer.offer快到碗里来,但是offer始终不是巧克力,并没那么甜美可口易消化. 找工作刚开始,就遇到了不小的阻力,看到Boss直聘上各种与IT相关的工作 ...

  9. JAVA_SE基础——2.环境变量的配置&测试JDK

    哈喽,利用晚上的空余时间再写篇心的~~~  谢谢大家 前一篇文章 JAVA_SE基础--JDK&JRE下载及安装http://blog.csdn.net/thescript_j/article ...

  10. LeetCode & Q38-Count and Say-Easy

    String Description: The count-and-say sequence is the sequence of integers with the first five terms ...