青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

牽著老婆滿街逛

嚴以律己,寬以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

Speex 回聲消除

轉載自:http://blog.csdn.net/dxpqxb/article/details/7928591

為什么需要聲學回聲消除呢?在一般的VOIP軟件或視頻會議系統中,假設我們只有A和B兩個人在通話,首先,A的聲音傳給B,B然后用喇叭放出來,而這時B的MIC呢則會采集到喇叭放出來的聲音,然后傳回給A,如果這個傳輸的過程中時延足夠大,A就會聽到一個和自己剛才說過的話一樣的聲音,這就是回聲,聲學回聲消除器的作用就是在B端對B采集到的聲音進行處理,把采集到聲音包含的A的聲音去掉再傳給A,這樣,A就不會聽到自己說過的話了。
聲學回聲消除的原理我就不說了,這在網上有很多文檔,網上缺少的是實現,所以,我在這把一個開源的聲學回聲消除器介紹一下,希望對有些有人用,如果有人知道怎么把這消除器用的基于實時流的VOIP軟件中,希望能一起分享一下。
這個聲學回聲消除器是一個著名的音頻編解碼器speex中的一部分,1.1.9版本后的回聲消除器才起作用,以前版本的都不行,我用的也是這個版本,測試表明,用同一個模擬文件,它有效果比INTEL IPP庫4.1版中的聲學回聲消除器的還要好。
先說編譯。首先,從www.speex.org上下載speex1.1.9的源代碼,解壓,打開speex\win32\libspeex中的libspeex.dsw,這個工作區里有兩個工程,一個是 libspeex,另一個是libspeex_dynamic。然后,將libspeex中的mdf.c文件添加到工程libspeex中,編譯即可。
以下是我根據文檔封裝的一個類,里面有一個測試程序: //file name: speexEC.h
#ifndef SPEEX_EC_H
#define SPEEX_EC_H
#include <stdio.h>
#include <stdlib.h>
#include "speex/speex_echo.h"
#include "speex/speex_preprocess.h"
class CSpeexEC
{
public:
CSpeexEC();
~CSpeexEC();
void Init(int frame_size=160, int filter_length=1280, int sampling_rate=8000);
void DoAEC(short *mic, short *ref, short *out);

protected:
void Reset();

private:
bool      m_bHasInit;
SpeexEchoState*   m_pState;
    SpeexPreprocessState* m_pPreprocessorState;
int      m_nFrameSize;
int      m_nFilterLen;
int      m_nSampleRate;
float*      m_pfNoise;
};

#endif

//fine name:speexEC.cpp
#include "SpeexEC.h"

CSpeexEC::CSpeexEC()
{
m_bHasInit   = false;
m_pState   = NULL;
m_pPreprocessorState  = NULL;
m_nFrameSize   = 160;
m_nFilterLen   = 160*8;
m_nSampleRate   = 8000;
m_pfNoise   = NULL;
}

CSpeexEC::~CSpeexEC()
{
Reset();
}

void CSpeexEC::Init(int frame_size, int filter_length, int sampling_rate)
{
Reset();

if (frame_size<=0 || filter_length<=0 || sampling_rate<=0)
{
  m_nFrameSize  =160;
  m_nFilterLen  = 160*8;
  m_nSampleRate = 8000;
}
else
{
  m_nFrameSize  =frame_size;
  m_nFilterLen  = filter_length;
  m_nSampleRate = sampling_rate;
}

m_pState = speex_echo_state_init(m_nFrameSize, m_nFilterLen);
m_pPreprocessorState = speex_preprocess_state_init(m_nFrameSize, m_nSampleRate);
m_pfNoise = new float[m_nFrameSize+1];
m_bHasInit = true;
}

void CSpeexEC::Reset()
{
if (m_pState != NULL)
{
  speex_echo_state_destroy(m_pState);
  m_pState = NULL;
}
if (m_pPreprocessorState != NULL)
{
  speex_preprocess_state_destroy(m_pPreprocessorState);
  m_pPreprocessorState = NULL;
}
if (m_pfNoise != NULL)
{
  delete []m_pfNoise;
  m_pfNoise = NULL;
}
m_bHasInit = false;
}

void CSpeexEC:DoAEC(short* mic, short* ref, short* out)
{
if (!m_bHasInit)
  return;

speex_echo_cancel(m_pState, mic, ref, out, m_pfNoise);
    speex_preprocess(m_pPreprocessorState, (__int16 *)out, m_pfNoise);
   
}

可以看出,這個回聲消除器類很簡單,只要初始化一下就可以調用了。但是,要注意的是,傳給回聲消除器的兩個聲音信號,必須同步得非常的好,就是說,在B端,接收到A說的話以后,要把這些話音數據傳給回聲消除器做參考,然后再傳給聲卡,聲卡再放出來,這有一段延時,這時,B再采集,然后傳給回聲消除器,與那個參考數據比較,從采集到的數據中把頻域和參考數據相同的部分消除掉。如果傳給消除器的兩個信號同步得不好,即兩個信號找不到頻域相同的部分,就沒有辦法進行消除了。
測試程序:

#define NN 160
void main()
{
FILE* ref_fd, *mic_fd, *out_fd;
short ref[NN], mic[NN], out[NN];
ref_fd = fopen ("ref.pcm", "rb"); //打開參考文件,即要消除的聲音
mic_fd = fopen ("mic.pcm",  "rb");//打開mic采集到的聲音文件,包含回聲在里面
out_fd = fopen ("echo.pcm", "wb");//消除了回聲以后的文件

CSpeexEC ec;
ec.Init();

while (fread(mic, 1, NN*2, mic_fd))
   {
      fread(ref, 1, NN*2, ref_fd);  
      ec.DoAEC(mic, ref, out);
      fwrite(out, 1, NN*2, out_fd);
   }
 
   fclose(ref_fd);
   fclose(mic_fd);
   fclose(out_fd);
}

  以上的程序是用文件來模擬回聲和MIC,但在實時流中是大不一樣的,在一般的VOIP軟件中,接收對方的聲音并傳到聲卡中播放是在一個線程中進行的,而采集本地的聲音并傳送到對方又是在另一個線程中進行的,而聲學回聲消除器在對采集到的聲音進行回聲消除的同時,還需要播放線程中的數據作為參考,而要同步這兩個線程中的數據是非常困難的,因為稍稍有些不同步,聲學回聲消除器中的自適應濾波器就會發散,不但消除不了回聲,還會破壞原始采集到的聲音,使被破壞的聲音難以分辨。我做過好多嘗試,始終無法用軟件來實現對這兩個線程中的數據進行同步,導致實現失敗,希望有經驗的網友們一起分享一下這方面的經驗。



示例代碼:


Sample code

This section shows sample code for encoding and decoding speech using the Speex API. The commands can be used to encode and decode a file by calling:
% sampleenc in_file.sw | sampledec out_file.sw
where both files are raw (no header) files encoded at 16 bits per sample (in the machine natural endianness).

sampleenc.c

sampleenc takes a raw 16 bits/sample file, encodes it and outputs a Speex stream to stdout. Note that the packing used is NOT compatible with that of speexenc/speexdec.


#include <speex/speex.h>
#include <stdio.h>

#define FRAME_SIZE 160
int main(int argc, char **argv)
{
char *inFile;
FILE *fin;
short in[FRAME_SIZE];
float input[FRAME_SIZE];
char cbits[200];
int nbBytes;

void *state;

SpeexBits bits;
int i, tmp;

state = speex_encoder_init(&speex_nb_mode);

tmp=8;
speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp);
inFile = argv[1];
fin = fopen(inFile, "r");

speex_bits_init(&bits);
while (1)
{

fread(in, sizeof(short), FRAME_SIZE, fin);
if (feof(fin))
break;

for (i=0;i<FRAME_SIZE;i++)
input[i]=in[i];

speex_bits_reset(&bits);

speex_encode(state, input, &bits);

nbBytes = speex_bits_write(&bits, cbits, 200);

fwrite(&nbBytes, sizeof(int), 1, stdout);

fwrite(cbits, 1, nbBytes, stdout);
}

speex_encoder_destroy(state);

speex_bits_destroy(&bits);
fclose(fin);
return 0;
}

sampledec.c

sampledec reads a Speex stream from stdin, decodes it and outputs it to a raw 16 bits/sample file. Note that the packing used is NOT compatible with that of speexenc/speexdec.


#include <speex/speex.h>
#include <stdio.h>

#define FRAME_SIZE 160
int main(int argc, char **argv)
{
char *outFile;
FILE *fout;

short out[FRAME_SIZE];

float output[FRAME_SIZE];
char cbits[200];
int nbBytes;

void *state;

SpeexBits bits;
int i, tmp;

state = speex_decoder_init(&speex_nb_mode);

tmp=1;
speex_decoder_ctl(state, SPEEX_SET_ENH, &tmp);
outFile = argv[1];
fout = fopen(outFile, "w");

speex_bits_init(&bits);
while (1)
{

fread(&nbBytes, sizeof(int), 1, stdin);
fprintf (stderr, "nbBytes: %d\n", nbBytes);
if (feof(stdin))
break;

fread(cbits, 1, nbBytes, stdin);

speex_bits_read_from(&bits, cbits, nbBytes);

speex_decode(state, &bits, output);

for (i=0;i<FRAME_SIZE;i++)
out[i]=output[i];

fwrite(out, sizeof(short), FRAME_SIZE, fout);
}

speex_decoder_destroy(state);

speex_bits_destroy(&bits);
fclose(fout);
return 0;
}




 


 




開源 H323 協議中封裝的使用參考代碼:




#include <ptlib.h>

#ifdef __GNUC__
#pragma implementation "speexcodec.h"
#endif

#include "speexcodec.h"

#include "h323caps.h"
#include "h245.h"
#include "rtp.h"

extern "C" {
#include "speex/libspeex/speex.h"
};


#define new PNEW

#define XIPH_COUNTRY_CODE       0xB5  // (181) Country code for United States
#define XIPH_T35EXTENSION       0
#define XIPH_MANUFACTURER_CODE  0x0026 // Allocated by Delta Inc

#define EQUIVALENCE_COUNTRY_CODE        // Country code for Australia
#define EQUIVALENCE_T35EXTENSION       0
#define EQUIVALENCE_MANUFACTURER_CODE  61 // Allocated by Australian Communications Authority, Oct 2000

#define SAMPLES_PER_FRAME        160

#define SPEEX_BASE_NAME "Speex"

#define SPEEX_NARROW2_H323_NAME    SPEEX_BASE_NAME "Narrow-5.95k{sw}"
#define SPEEX_NARROW3_H323_NAME    SPEEX_BASE_NAME "Narrow-8k{sw}"
#define SPEEX_NARROW4_H323_NAME    SPEEX_BASE_NAME "Narrow-11k{sw}"
#define SPEEX_NARROW5_H323_NAME    SPEEX_BASE_NAME "Narrow-15k{sw}"
#define SPEEX_NARROW6_H323_NAME    SPEEX_BASE_NAME "Narrow-18.2k{sw}"

H323_REGISTER_CAPABILITY(SpeexNarrow2AudioCapability, SPEEX_NARROW2_H323_NAME);
H323_REGISTER_CAPABILITY(SpeexNarrow3AudioCapability, SPEEX_NARROW3_H323_NAME);
H323_REGISTER_CAPABILITY(SpeexNarrow4AudioCapability, SPEEX_NARROW4_H323_NAME);
H323_REGISTER_CAPABILITY(SpeexNarrow5AudioCapability, SPEEX_NARROW5_H323_NAME);
H323_REGISTER_CAPABILITY(SpeexNarrow6AudioCapability, SPEEX_NARROW6_H323_NAME);

#define XIPH_SPEEX_NARROW2_H323_NAME    SPEEX_BASE_NAME "Narrow-5.95k(Xiph){sw}"
#define XIPH_SPEEX_NARROW3_H323_NAME    SPEEX_BASE_NAME "Narrow-8k(Xiph){sw}"
#define XIPH_SPEEX_NARROW4_H323_NAME    SPEEX_BASE_NAME "Narrow-11k(Xiph){sw}"
#define XIPH_SPEEX_NARROW5_H323_NAME    SPEEX_BASE_NAME "Narrow-15k(Xiph){sw}"
#define XIPH_SPEEX_NARROW6_H323_NAME    SPEEX_BASE_NAME "Narrow-18.2k(Xiph){sw}"

H323_REGISTER_CAPABILITY(XiphSpeexNarrow2AudioCapability, XIPH_SPEEX_NARROW2_H323_NAME);
H323_REGISTER_CAPABILITY(XiphSpeexNarrow3AudioCapability, XIPH_SPEEX_NARROW3_H323_NAME);
H323_REGISTER_CAPABILITY(XiphSpeexNarrow4AudioCapability, XIPH_SPEEX_NARROW4_H323_NAME);
H323_REGISTER_CAPABILITY(XiphSpeexNarrow5AudioCapability, XIPH_SPEEX_NARROW5_H323_NAME);
H323_REGISTER_CAPABILITY(XiphSpeexNarrow6AudioCapability, XIPH_SPEEX_NARROW6_H323_NAME);

/////////////////////////////////////////////////////////////////////////

static int Speex_Bits_Per_Second(int mode) {
    void *tmp_coder_state;
    int bitrate;
    tmp_coder_state = speex_encoder_init(&speex_nb_mode);
    speex_encoder_ctl(tmp_coder_state, SPEEX_SET_QUALITY, &mode);
    speex_encoder_ctl(tmp_coder_state, SPEEX_GET_BITRATE, &bitrate);
    speex_encoder_destroy(tmp_coder_state);
    return bitrate;
}

static int Speex_Bytes_Per_Frame(int mode) {
    int bits_per_frame = Speex_Bits_Per_Second(mode) / 50; // (20ms frame size)
    return ((bits_per_frame+7)/8); // round up
}

OpalMediaFormat const OpalSpeexNarrow_5k95(OPAL_SPEEX_NARROW_5k95,
                                           OpalMediaFormat::DefaultAudioSessionID,
                                           RTP_DataFrame::DynamicBase,
                                           TRUE,  // Needs jitter
                                           Speex_Bits_Per_Second(2),
                                           Speex_Bytes_Per_Frame(2),
                                           SAMPLES_PER_FRAME, // 20 milliseconds
                                           OpalMediaFormat::AudioTimeUnits);

OpalMediaFormat const OpalSpeexNarrow_8k(OPAL_SPEEX_NARROW_8k,
                                         OpalMediaFormat::DefaultAudioSessionID,
                                         RTP_DataFrame::DynamicBase,
                                         TRUE,  // Needs jitter
                                         Speex_Bits_Per_Second(3),
                                         Speex_Bytes_Per_Frame(3),
                                         SAMPLES_PER_FRAME, // 20 milliseconds
                                         OpalMediaFormat::AudioTimeUnits);

OpalMediaFormat const OpalSpeexNarrow_11k(OPAL_SPEEX_NARROW_11k,
                                          OpalMediaFormat::DefaultAudioSessionID,
                                          RTP_DataFrame::DynamicBase,
                                          TRUE,  // Needs jitter
                                          Speex_Bits_Per_Second(4),
                                          Speex_Bytes_Per_Frame(4),
                                          SAMPLES_PER_FRAME, // 20 milliseconds
                                          OpalMediaFormat::AudioTimeUnits);

OpalMediaFormat const OpalSpeexNarrow_15k(OPAL_SPEEX_NARROW_15k,
                                          OpalMediaFormat::DefaultAudioSessionID,
                                          RTP_DataFrame::DynamicBase,
                                          TRUE,  // Needs jitter
                                          Speex_Bits_Per_Second(5),
                                          Speex_Bytes_Per_Frame(5),
                                          SAMPLES_PER_FRAME, // 20 milliseconds
                                          OpalMediaFormat::AudioTimeUnits);

OpalMediaFormat const OpalSpeexNarrow_18k2(OPAL_SPEEX_NARROW_18k2,
                                           OpalMediaFormat::DefaultAudioSessionID,
                                           RTP_DataFrame::DynamicBase,
                                           TRUE,  // Needs jitter
                                           Speex_Bits_Per_Second(6),
                                           Speex_Bytes_Per_Frame(6),
                                           SAMPLES_PER_FRAME, // 20 milliseconds
                                           OpalMediaFormat::AudioTimeUnits);


/////////////////////////////////////////////////////////////////////////

SpeexNonStandardAudioCapability::SpeexNonStandardAudioCapability(int mode)
  : H323NonStandardAudioCapability(1, 1,
                                   EQUIVALENCE_COUNTRY_CODE,
                                   EQUIVALENCE_T35EXTENSION,
                                   EQUIVALENCE_MANUFACTURER_CODE,
                                   NULL, 0, 0, P_MAX_INDEX)
{
  PStringStream s;
  s << "Speex bs" << speex_nb_mode.bitstream_version << " Narrow" << mode;
  PINDEX len = s.GetLength();
  memcpy(nonStandardData.GetPointer(len), (const char *)s, len);
}


/////////////////////////////////////////////////////////////////////////

SpeexNarrow2AudioCapability::SpeexNarrow2AudioCapability()
  : SpeexNonStandardAudioCapability(2)
{
}


PObject * SpeexNarrow2AudioCapability::Clone() const
{
  return new SpeexNarrow2AudioCapability(*this);
}


PString SpeexNarrow2AudioCapability::GetFormatName() const
{
  return SPEEX_NARROW2_H323_NAME;
}


H323Codec * SpeexNarrow2AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_5k95, 2, direction);
}


/////////////////////////////////////////////////////////////////////////

SpeexNarrow3AudioCapability::SpeexNarrow3AudioCapability()
  : SpeexNonStandardAudioCapability(3)
{
}


PObject * SpeexNarrow3AudioCapability::Clone() const
{
  return new SpeexNarrow3AudioCapability(*this);
}


PString SpeexNarrow3AudioCapability::GetFormatName() const
{
  return SPEEX_NARROW3_H323_NAME;
}


H323Codec * SpeexNarrow3AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_8k, 3, direction);
}


/////////////////////////////////////////////////////////////////////////

SpeexNarrow4AudioCapability::SpeexNarrow4AudioCapability()
  : SpeexNonStandardAudioCapability(4)
{
}


PObject * SpeexNarrow4AudioCapability::Clone() const
{
  return new SpeexNarrow4AudioCapability(*this);
}


PString SpeexNarrow4AudioCapability::GetFormatName() const
{
  return SPEEX_NARROW4_H323_NAME;
}


H323Codec * SpeexNarrow4AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_11k, 4, direction);
}


/////////////////////////////////////////////////////////////////////////

SpeexNarrow5AudioCapability::SpeexNarrow5AudioCapability()
  : SpeexNonStandardAudioCapability(5)
{
}


PObject * SpeexNarrow5AudioCapability::Clone() const
{
  return new SpeexNarrow5AudioCapability(*this);
}


PString SpeexNarrow5AudioCapability::GetFormatName() const
{
  return SPEEX_NARROW5_H323_NAME;
}


H323Codec * SpeexNarrow5AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_15k, 5, direction);
}


/////////////////////////////////////////////////////////////////////////

SpeexNarrow6AudioCapability::SpeexNarrow6AudioCapability()
  : SpeexNonStandardAudioCapability(6)
{
}


PObject * SpeexNarrow6AudioCapability::Clone() const
{
  return new SpeexNarrow6AudioCapability(*this);
}


PString SpeexNarrow6AudioCapability::GetFormatName() const
{
  return SPEEX_NARROW6_H323_NAME;
}


H323Codec * SpeexNarrow6AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_18k2, 6, direction);
}


/////////////////////////////////////////////////////////////////////////

XiphSpeexNonStandardAudioCapability::XiphSpeexNonStandardAudioCapability(int mode)
  : H323NonStandardAudioCapability(1, 1,
                                   XIPH_COUNTRY_CODE,
                                   XIPH_T35EXTENSION,
                                   XIPH_MANUFACTURER_CODE,
                                   NULL, 0, 0, P_MAX_INDEX)
{
  // FIXME: To be replaced by an ASN defined block of data
  PStringStream s;
  s << "Speex bs" << speex_nb_mode.bitstream_version << " Narrow" << mode;
  PINDEX len = s.GetLength();
  memcpy(nonStandardData.GetPointer(len), (const char *)s, len);
}


/////////////////////////////////////////////////////////////////////////

XiphSpeexNarrow2AudioCapability::XiphSpeexNarrow2AudioCapability()
  : XiphSpeexNonStandardAudioCapability(2)
{
}


PObject * XiphSpeexNarrow2AudioCapability::Clone() const
{
  return new XiphSpeexNarrow2AudioCapability(*this);
}


PString XiphSpeexNarrow2AudioCapability::GetFormatName() const
{
  return XIPH_SPEEX_NARROW2_H323_NAME;
}


H323Codec * XiphSpeexNarrow2AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_5k95, 2, direction);
}


/////////////////////////////////////////////////////////////////////////

XiphSpeexNarrow3AudioCapability::XiphSpeexNarrow3AudioCapability()
  : XiphSpeexNonStandardAudioCapability(3)
{
}


PObject * XiphSpeexNarrow3AudioCapability::Clone() const
{
  return new XiphSpeexNarrow3AudioCapability(*this);
}


PString XiphSpeexNarrow3AudioCapability::GetFormatName() const
{
  return XIPH_SPEEX_NARROW3_H323_NAME;
}


H323Codec * XiphSpeexNarrow3AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_8k, 3, direction);
}


/////////////////////////////////////////////////////////////////////////

XiphSpeexNarrow4AudioCapability::XiphSpeexNarrow4AudioCapability()
  : XiphSpeexNonStandardAudioCapability(4)
{
}


PObject * XiphSpeexNarrow4AudioCapability::Clone() const
{
  return new XiphSpeexNarrow4AudioCapability(*this);
}


PString XiphSpeexNarrow4AudioCapability::GetFormatName() const
{
  return XIPH_SPEEX_NARROW4_H323_NAME;
}


H323Codec * XiphSpeexNarrow4AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_11k, 4, direction);
}


/////////////////////////////////////////////////////////////////////////

XiphSpeexNarrow5AudioCapability::XiphSpeexNarrow5AudioCapability()
  : XiphSpeexNonStandardAudioCapability(5)
{
}


PObject * XiphSpeexNarrow5AudioCapability::Clone() const
{
  return new XiphSpeexNarrow5AudioCapability(*this);
}


PString XiphSpeexNarrow5AudioCapability::GetFormatName() const
{
  return XIPH_SPEEX_NARROW5_H323_NAME;
}


H323Codec * XiphSpeexNarrow5AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_15k, 5, direction);
}


/////////////////////////////////////////////////////////////////////////

XiphSpeexNarrow6AudioCapability::XiphSpeexNarrow6AudioCapability()
  : XiphSpeexNonStandardAudioCapability(6)
{
}


PObject * XiphSpeexNarrow6AudioCapability::Clone() const
{
  return new XiphSpeexNarrow6AudioCapability(*this);
}


PString XiphSpeexNarrow6AudioCapability::GetFormatName() const
{
  return XIPH_SPEEX_NARROW6_H323_NAME;
}


H323Codec * XiphSpeexNarrow6AudioCapability::CreateCodec(H323Codec::Direction direction) const
{
  return new SpeexCodec(OpalSpeexNarrow_18k2, 6, direction);
}


/////////////////////////////////////////////////////////////////////////////

const float MaxSampleValue   = 32767.0;
const float MinSampleValue   = -32767.0;

SpeexCodec::SpeexCodec(const char * name, int mode, Direction dir)
  : H323FramedAudioCodec(name, dir)
{
  PTRACE(3, "Codec\tSpeex mode " << mode << " " << (dir == Encoder ? "en" : "de")
         << "coder created");

  bits = new SpeexBits;
  speex_bits_init(bits);

  if (direction == Encoder) {
    coder_state = speex_encoder_init(&speex_nb_mode);
    speex_encoder_ctl(coder_state, SPEEX_GET_FRAME_SIZE, &encoder_frame_size);
    speex_encoder_ctl(coder_state, SPEEX_SET_QUALITY,    &mode);
  } else {
    coder_state = speex_decoder_init(&speex_nb_mode);
  }
}

SpeexCodec::~SpeexCodec()
{
  speex_bits_destroy(bits);
  delete bits;

  if (direction == Encoder)
    speex_encoder_destroy(coder_state);
  else
    speex_decoder_destroy(coder_state);
}


BOOL SpeexCodec::EncodeFrame(BYTE * buffer, unsigned & length)
{
  // convert PCM to float
  float floatData[SAMPLES_PER_FRAME];
  PINDEX i;
  for (i = 0; i < SAMPLES_PER_FRAME; i++)
    floatData[i] = sampleBuffer[i];

  // encode PCM data in sampleBuffer to buffer
  speex_bits_reset(bits);
  speex_encode(coder_state, floatData, bits);

  length = speex_bits_write(bits, (char *)buffer, encoder_frame_size);

  return TRUE;
}


BOOL SpeexCodec::DecodeFrame(const BYTE * buffer, unsigned length, unsigned &)
{
  float floatData[SAMPLES_PER_FRAME];

  // decode Speex data to floats
  speex_bits_read_from(bits, (char *)buffer, length);
  speex_decode(coder_state, bits, floatData);

  // convert float to PCM
  PINDEX i;
  for (i = 0; i < SAMPLES_PER_FRAME; i++) {
    float sample = floatData[i];
    if (sample < MinSampleValue)
      sample = MinSampleValue;
    else if (sample > MaxSampleValue)
      sample = MaxSampleValue;
    sampleBuffer[i] = (short)sample;
  }

  return TRUE;
}



VC++ 中使用 API的 char 單字節壓縮代碼示例:

Encoding and decoding problem in speex 1.0.4
Subject:     Encoding and decoding problem in speex 1.0.4
List-id:     speex-dev.xiph.org

Hi,
            I am using the speex 1.0.4 library from Windows.
            I have posted my problem before but didn't get a solution. I am doing an
            VOIP project
            in which i am recording sound and streaming it to the peer. I wanted to
            encode and decode
            wav files that brought me to this site.
            I am recording sound in the following format:-
            m_WaveFormatEx.wFormatTag          = WAVE_FORMAT_PCM;
            m_WaveFormatEx.nChannels           = 1;
            m_WaveFormatEx.wBitsPerSample      = 8;
            m_WaveFormatEx.cbSize              = 0;
            m_WaveFormatEx.nSamplesPerSec      = 8000;
            m_WaveFormatEx.nBlockAlign         = 1;
            m_WaveFormatEx.nAvgBytesPerSec     = 8000;
            The recording is as follows :-
            When the buffer(size = 2000 bytes) gets filled with sound data a
            function with the body shown
            below is called.
            LPWAVEHDR lpHdr = (LPWAVEHDR) lParam;
            if(lpHdr->dwBytesRecorded==0 || lpHdr==NULL)
            return ERROR_SUCCESS;
            ::waveInUnprepareHeader(m_hRecord, lpHdr, sizeof(WAVEHDR));
            Here lpHdr->lpData contains the audio data in a character array.
            Now here I want to use Speex codec for encoding the data so the encoding
            function is
            called (I am thankful to Tay YueWeng for the function).
            char *encode(char *buffer, int &encodeSize)
            {
            char   *encodedBuffer = new char[RECBUFFER/2];           
            short   speexShort;
            float  speexFloat[RECBUFFER/2];
            void   *mEncode       = speex_encoder_init(&speex_nb_mode);
           
            speex_bits_init(&mBits);
            // Convert the audio to a short then to a float buffer
            int    halfBufferSize = RECBUFFER/2;
            for (int i = 0; i < halfBufferSize; i++)
            {
            memcpy(&speexShort, &buffer[i*2], sizeof(short));
            speexFloat[i]     = speexShort;
            }
            // Encode the sound data using the float buffer
            speex_bits_reset(&mBits);
            speex_encode(mEncode, speexFloat, &mBits);
            encodeSize            = speex_bits_write(&mBits, encodedBuffer,
            RECBUFFER/2);
           
            speex_encoder_destroy(mEncode);
           
            speex_bits_destroy(&mBits);
            // Return the encoded buffer
            return encodedBuffer;
            }
            Here i noticed that though my captured audio data is 2000 bytes the
            compressed form is
            always 38 bytes. In the speexFloat array above i get values in the range
            -32767 to +32767.
            Is it correct. Also after calling the 'speex_encode' function the first
            160 values in the
            input float array i.e. speexFloat is changed (why does it happen?Is
            anything abnormal).
            Further after calling the above function for testing I decode the
            returned encoded data
            immediately by calling the decoding function shown bellow :-
            char *decode (char *buffer, int encodeSize)
            {
            char *decodedBuffer   = new char[RECBUFFER];
            short speexShort;
            float speexFloat[RECBUFFER/2];
            // Decode the sound data into a float buffer
            void  *mDecode        = speex_decoder_init(&speex_nb_mode);
           
            speex_bits_init(&mBits);
            int    halfBufferSize = RECBUFFER/2;
            speex_bits_reset(&mBits);
            speex_bits_read_from(&mBits, buffer, encodeSize);
            speex_decode(mDecode, &mBits, speexFloat);
            // Convert from float to short to char
            for (int i = 0; i < halfBufferSize; i++)
            {
            speexShort = speexFloat[i];
            memcpy(&decodedBuffer[i*2], &speexShort, sizeof(short));
            }
           
            speex_encoder_destroy(mDecode);
           
            speex_bits_destroy(&mBits);
            // Return the buffer
            return decodedBuffer;
            }
            After decoding using the above function only the first 160 values in the
            decodedBuffer array is
            changed. i.e i encoded an 2000 byte audio data to get a 38 byte encoded
            audio data. On decoding
            the 38 byte audio data i get an decompressed 160 byte data. I don't
            understand whats going
            wrong. I checked all the messages posted in this newsgroup and did'nt
            find an answer so i am
            posting this code hoping that it gets solved soon.  Thanks in advance.

posted on 2012-11-21 23:44 楊粼波 閱讀(4151) 評論(1)  編輯 收藏 引用 所屬分類: 文章收藏C++Windows

評論

# re: Speex 回聲消除 2015-03-16 20:13 王小亮

學習了。謝謝。  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区回区在观看免费视频| 亚洲天堂av图片| 久久精品中文字幕一区二区三区| 国产精品日韩在线一区| 午夜精品久久久久久久久久久久久 | 中文精品视频一区二区在线观看| 亚洲欧洲午夜| 欧美国产91| 亚洲欧美日韩综合| 欧美在线网站| 亚洲精品乱码久久久久| 日韩视频在线一区| 国产亚洲欧美日韩一区二区| 免费成人网www| 欧美日韩精品欧美日韩精品一 | 99精品视频免费在线观看| 在线视频欧美日韩精品| 国内精品久久久久影院 日本资源| 久久aⅴ国产欧美74aaa| 欧美日韩高清一区| 久久精品国产96久久久香蕉| 久久亚洲一区二区| 亚洲综合久久久久| 久久久亚洲综合| 亚洲永久免费精品| 久久综合久久美利坚合众国| 在线视频精品一| 久久免费偷拍视频| 欧美亚洲一级| 欧美连裤袜在线视频| 久久亚洲午夜电影| 国产精品伦子伦免费视频| 欧美激情第10页| 国产精品综合久久久| 亚洲国产精品成人| 国产综合激情| 亚洲午夜精品一区二区三区他趣| 亚洲第一主播视频| 欧美亚洲在线视频| 亚洲一区二区三区在线看| 老**午夜毛片一区二区三区| 午夜久久资源| 欧美色图首页| 亚洲国产一区二区精品专区| 好吊妞**欧美| 亚洲中午字幕| 西西裸体人体做爰大胆久久久 | 亚洲人成网站影音先锋播放| 今天的高清视频免费播放成人| 夜夜精品视频| 99在线观看免费视频精品观看| 久久久在线视频| 久久精品中文字幕一区| 国产精品视频精品视频| 999在线观看精品免费不卡网站| 亚洲国产专区校园欧美| 久久久免费精品| 久久久久五月天| 娇妻被交换粗又大又硬视频欧美| 亚洲欧美激情视频在线观看一区二区三区 | 午夜精品久久久| 性欧美大战久久久久久久久| 国产精品草草| 亚洲图片你懂的| 午夜免费电影一区在线观看| 国产精品久久久久久影院8一贰佰| 日韩视频永久免费| 一区电影在线观看| 国产精品wwwwww| 亚洲一区二区欧美| 久久精品人人做人人爽| 国产一区二区三区在线播放免费观看| 午夜精品久久久久久| 久久久久久久久久久久久9999| 国产无遮挡一区二区三区毛片日本| 亚洲免费视频一区二区| 久久精品久久综合| 激情一区二区三区| 欧美a级理论片| 亚洲精品一区中文| 欧美亚洲一区在线| 韩国成人精品a∨在线观看| 久久久久久一区| 99精品99| 激情伊人五月天久久综合| 亚洲综合清纯丝袜自拍| 久久精品卡一| 亚洲精品欧美在线| 国产精品久久久久久户外露出| 亚洲欧美精品一区| 欧美成人一二三| 亚洲一区二区在线观看视频| 国产欧美丝祙| 欧美国产精品中文字幕| 亚洲一区二区精品在线观看| 久久精品一级爱片| 99精品国产高清一区二区 | 久久一二三四| 亚洲一区二区三区在线| 美腿丝袜亚洲色图| 亚洲性感激情| 一区二区三区在线看| 欧美日韩不卡合集视频| 欧美中文字幕视频在线观看| 亚洲欧洲精品一区二区三区| 欧美亚洲综合久久| 99在线热播精品免费99热| 国产一区二区日韩精品| 欧美日韩国产成人| 久久最新视频| 欧美一级淫片播放口| 91久久夜色精品国产网站| 久久久噜噜噜久噜久久| 亚洲夜晚福利在线观看| 91久久国产综合久久91精品网站| 国产精品久久久久久久久免费桃花 | 久久天堂精品| 亚洲男人第一av网站| 亚洲激情欧美激情| 国内自拍亚洲| 国产欧美日韩精品专区| 欧美精选午夜久久久乱码6080| 久久精品国产亚洲a| 亚洲免费一在线| 99国内精品久久| 亚洲乱码国产乱码精品精天堂| 欧美黄色精品| 欧美成人激情视频| 久久免费视频一区| 久久精品国产96久久久香蕉| 欧美一级日韩一级| 欧美一区二区三区精品| 亚洲中无吗在线| 亚洲一卡二卡三卡四卡五卡| 日韩视频一区二区在线观看 | 亚洲在线中文字幕| 亚洲与欧洲av电影| 亚洲午夜激情网站| 亚洲一区二区在| 亚洲欧美精品伊人久久| 亚洲欧美日韩一区在线| 亚洲欧美在线x视频| 亚洲欧美日韩在线一区| 亚洲女人av| 欧美亚洲自偷自偷| 久久综合狠狠综合久久激情| 久久久视频精品| 美女999久久久精品视频| 美女图片一区二区| 欧美激情网站在线观看| 一级成人国产| 一区二区三区精品视频| 一本大道久久a久久精品综合| 亚洲精品中文字| 亚洲一级电影| 久久久精品性| 欧美成人中文字幕在线| 亚洲国产你懂的| 一区二区三区日韩在线观看| 亚洲一区二区视频在线| 久久精品人人做人人综合| 狼人社综合社区| 欧美性大战xxxxx久久久| 国产欧美三级| 91久久精品一区| 亚洲欧美日韩成人高清在线一区| 欧美一区二区三区电影在线观看| 久久久97精品| 亚洲日韩欧美视频一区| 亚洲无毛电影| 久久av老司机精品网站导航| 免费日本视频一区| 国产精品美女主播| 在线欧美影院| 亚洲尤物视频在线| 裸体一区二区三区| 一本一本大道香蕉久在线精品| 欧美一区二区成人| 欧美黄色影院| 韩国成人理伦片免费播放| 9久草视频在线视频精品| 欧美尤物巨大精品爽| 亚洲国产欧美日韩精品| 一个色综合av| 免费观看日韩| 国产日韩精品电影| 亚洲精品久久久久久一区二区| 欧美一区二区三区播放老司机| 欧美电影资源| 亚洲一区二区三区四区视频| 久久亚洲一区| 国产一区自拍视频| 亚洲欧美大片| 亚洲日本va午夜在线影院| 久久aⅴ乱码一区二区三区| 国产精品拍天天在线| 99精品欧美| 欧美激情一区二区三区在线视频观看| 亚洲欧美在线x视频| 国产精品成人免费|