opusコーデックの使用

4749 ワード

opusの概要と利点:


Opusは損失のある音声符号化のフォーマットで、Xiph.Org財団が開発した後、インターネットエンジニアリングタスクグループ(IETF)によって標準化され、SPeexとVorbisの代わりに単一のフォーマットで音声と音声を含むことが望ましいことを目標とし、ネットワーク上の低遅延のインスタント音声伝送に適用され、標準フォーマットはRFC 6716ファイルに定義されている.Opusフォーマットはオープンフォーマットであり、使用上特許や制限はありません.Opusは,音声符号化を指向したSILKと低遅延CELTの2つの音声符号化技術を統合した.Opusは高低ビットレートをシームレスに調整できる.エンコーダ内部では、より低いビットレートで線形予測符号化を用い、高いビットレートでは変換符号化を用いる(高低ビットレート境界でも両者を組み合わせた符号化方式を用いる).Opusは非常に低いアルゴリズム遅延(デフォルト22.5 ms)を有し、ネットワーク上のインスタント音声ストリーム、インスタント同期音声ナレーションなどの低遅延音声通話の符号化に非常に適している.また、Opusは符号化ビットレートを低減することによって、より低いアルゴリズム遅延を達成することができ、最低5 msまで可能である.複数の聴覚盲検では、OpusはMP 3、AAC、HE−ACなどの一般的なフォーマットよりも低く、より低い遅延とより良い音声圧縮率を有する.

decodeステップと踏んだ穴を使用します。


手順:


1.opusデコーダの作成:

OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
  opus_int32 Fs,// , 8000, 12000, 16000, 24000, 48000.
  int channels,// , 
  int *error// , 0 
  );

2.復号化:

OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
    OpusDecoder *st,          // 
    const unsigned char *data,// 
    opus_int32 len,           // 
    opus_int16 *pcm,          // , 16 
    int frame_size,           // pcm 
    int decode_fec            // fec, 0 ,1 
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);

3.復号データを文字配列に入れる


//大端着信であることに注意//注:frameSizeは、前のステップの戻り値、すなわち、各チャネルで返される2バイト単位の配列長//pcmは復号後のデータ、すなわち、前のステップのパラメータ4
char *pcmData = new char[frameSize * channels * sizeof(opus_int16)];
for (int i = 0; i < channels * frameSize; ++i)
{
  pcmData[i * 2] = pcm[i] & 0xFF;
  pcmData[i * 2 + 1] = (pcm[i] >> 8) & 0xFF;
}

4.デコーダを解放する

OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);

踏んだ穴:


1.連続した音声の場合、必ず1つのデコーダしか使用できない(作成後に解放してからデコーダを作成することはできない)


2.fecを使用する場合は、seqを自分でチェックして紛失を確認してからfecを使用し、パケットごとにfecを使用すると、それぞれが復号されます。


demo、およびdecodeを使用してまとめます


demo

class HandlerOpusImpl
{
  public:
  // 
    HandlerOpusImpl() : _perSecNum(0)
    {
      int sampleRate = 48000;
      int channels = 1;
      int err;
      _decoder = opus_decoder_create(sampleRate, channels, &err);
    }
    // srcData,  string result
    bool DecodeData(std::string srcData, std::string &result)
    {
         int frameSize;
         int channels = CHANNELS;
         int sampleRate = SAMPLE_RATE;
         opus_int16 *out;
         char *pcmData;

       out = new opus_int16[SAMPLE_RATE / 50 * CHANNELS];
       // , frameSize 0, 
       frameSize = opus_decode(_decoder, (const unsigned char *)srcData.data(), srcData.size(), out, SAMPLE_RATE / 50 * CHANNELS, 0);
       if (frameSize <= 0)
       {
          return false;
       }
         pcmData = new char[frameSize * channels * sizeof(opus_int16)];

         ++_perSecNum;
         for (int i = 0; i < channels * frameSize; ++i)
         {
              pcmData[i * 2] = out[i] & 0xFF;
            pcmData[i * 2 + 1] = (out[i] >> 8) & 0xFF;
         }
       // result
         std::string(pcmData, sizeof(opus_int16) * channels * frameSize).swap(result);

         delete[]out;
         delete[]pcmData;
         return true;
    }

    // fec , , fec 1
    bool HandleLosePack(std::string srcData, std::string &result)
    {
        int frameSize;
        int channels = CHANNELS;
        int sampleRate = SAMPLE_RATE;
        opus_int16 *out;
        char *pcmData;

        out = new opus_int16[SAMPLE_RATE / 50 * CHANNELS];
        frameSize = opus_decode(_decoder, NULL, 0, out, SAMPLE_RATE / 50 * CHANNELS, 1);
        if (frameSize <= 0)
        {
              return false;
        }
        pcmData = new char[frameSize * channels * sizeof(opus_int16)];

        ++_perSecNum;
        for (int i = 0; i < channels * frameSize; ++i)
        {
              pcmData[i * 2] = out[i] & 0xFF;
              pcmData[i * 2 + 1] = (out[i] >> 8) & 0xFF;
        }

        std::string(pcmData, sizeof(opus_int16) * channels * frameSize).swap(result);

        delete[]out;
        delete[]pcmData;
        return true;
    }
    void DeleteCodec()
    {
      opus_decoder_destroy(_decoder);
      _decoder = NULL;
    }
  private:
    int _perSecNum;
    OpusDecoder *_decoder;
};

まとめ:


opusの使用は複雑ではありませんが、ネット上の資料は限られています.お兄さんたちが前に書いたコードで少し理解しました.皆さんに助けてほしいです.上のコードはプログラムの一部で、直接使うことはできません.