2

过去三天我一直在寻找虫子,但我有点放弃了。我已经浏览了 OpenAL SDK 和 Vorbis 示例中的所有示例,但无济于事,所以我希望有人能帮助我。

问题:我使用 OpenAL 录制音频,出于调试原因,我将其输出到 C:/out.wav,然后我可以使用任何选择的音频播放器播放它,它会播放我录制的任何内容。

我从 openAL 获得的完全相同的缓冲区是我输入 libvorbisenc的内容
(我请求一个带有 vorbis_analysis_buffer 的缓冲区并在其上运行 alcCaptureSamples,之后我让 vorbis 做这件事。)

重点是:为什么 vorbis 将静音返回到我的输出文件以及如何在我的文件“C:/out.ogg”中获得有效的压缩音频?

不要担心一些丢失或多余的括号,它们在复制+粘贴和删除
代码运行的注释时丢失了,但它的输出只是无效的。

相关定义等:

//due to strange formatting constraints of this site the's are omitted  
define CHANNELS                 1  
define HERTZ                22050  
define BITSPERSAMPLE                16  
define BYTESPERSAMPLE               2  
define SAMPLES              4410  
define  SAMPLESIZE          2  
define ALIGN                (CHANNELS*BITSPERSAMPLE/8)  
define BUFFERSIZE           (SAMPLES*SAMPLESIZE)

typedef struct
{
    char            szRIFF[4];  
    long            lRIFFSize;  
    char            szWave[4];  
    char            szFmt[4];  
    long            lFmtSize;  
    WAVEFORMATEX    wfex;  
    char            szData[4];  
    long            lDataSize;  
} WAVEHEADER;  

class vorbispacker{  
public:  
    vorbispacker();  
    ~vorbispacker();  
    void consume();  

    muxer * mux;  
        // the needed ogg_stream_state is found at this->mux->state;  


    ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */  
    ogg_packet       op; /* one raw packet of data for decode */  

    vorbis_info      vi; /* struct that stores all the static vorbis bitstream  
                         settings */  
    vorbis_comment   vc; /* struct that stores all the user comments */   

    vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */  
    vorbis_block     vb; /* local working space for packet->PCM decode */  
};  

vorbis 设置

void vorbispacker::setup(){

    this->mux = new muxer;

    vorbis_info_init(&this->vi);
    int ret = vorbis_encode_init_vbr(&this->vi,CHANNELS,HERTZ,0.7);
    vorbis_comment_init(&this->vc);
    vorbis_comment_add_tag(&this->vc,"ENCODER","Test");
    ret =vorbis_analysis_init(&this->vd,&this->vi);
    ret= vorbis_block_init(&this->vd,&this->vb);

    iSize=0;
    iDataSize=0;
    //TEST//

    out = fopen("C:/out.wav","wb");
    // Prepare a WAVE file header for the captured data
    sprintf(swaveheader.szRIFF, "RIFF");
    swaveheader.lRIFFSize = 0;
    sprintf(swaveheader.szWave, "WAVE");
    sprintf(swaveheader.szFmt, "fmt ");
    swaveheader.lFmtSize = sizeof(WAVEFORMATEX);        
    swaveheader.wfex.nChannels = CHANNELS;
    swaveheader.wfex.wBitsPerSample = BITSPERSAMPLE;
    swaveheader.wfex.wFormatTag = WAVE_FORMAT_PCM;
    swaveheader.wfex.nSamplesPerSec = HERTZ;
    swaveheader.wfex.nBlockAlign = swaveheader.wfex.nChannels * swaveheader.wfex.wBitsPerSample / 8;
    swaveheader.wfex.nAvgBytesPerSec = swaveheader.wfex.nSamplesPerSec * swaveheader.wfex.nBlockAlign;
    swaveheader.wfex.cbSize = 0;
    sprintf(swaveheader.szData, "data");
    swaveheader.lDataSize = 0;

    fwrite(&swaveheader, sizeof(WAVEHEADER), 1, out);




    srand(time(NULL));
    ret = ogg_stream_init(&this->mux->state,rand());


    this->eos=0;

    ogg_packet header;
    ogg_packet header_comm;
    ogg_packet header_code;



    vorbis_analysis_headerout(&this->vd,&this->vc,&header,&header_comm,&header_code);
    ret = ogg_stream_packetin(&this->mux->state,&header); 
    ret =ogg_stream_packetin(&this->mux->state,&header_comm);
    ret =ogg_stream_packetin(&this->mux->state,&header_code);



    while(1){
        int res = ogg_stream_flush(&this->mux->state,&this->og);
        if(!res)break;
        this->mux->write(this->og);

    }


      // this code works great, the headers are correct , and are output to out.ogg


};

有问题的代码:

* // set up buffer*

float ** vorbisbuffer =  vorbis_analysis_buffer(&this->vd,SAMPLES);  
*// retrieve audio samples ( MONO 16 bit)*  
alcCaptureSamples(mic->pdevice,vorbisbuffer[0],SAMPLES);    


    //this goes to debug .wav file -> the exact same buffer that goes into vorbis  
    fwrite(vorbisbuffer[0], BUFFERSIZE, 1, out);  
    iDataSize +=BUFFERSIZE;  

    int eos =0;  




      /* tell the library how much we actually submitted */    

    //SAMPLES is what is inserted into openAL , hence what we put in vorbis  
      vorbis_analysis_wrote(&vd,SAMPLES);    




    while(vorbis_analysis_blockout(&this->vd,&this->vb)==1){

      /* analysis, assume we want to use bitrate management */
      vorbis_analysis(&this->vb,NULL);
      vorbis_bitrate_addblock(&this->vb);

      while(vorbis_bitrate_flushpacket(&this->vd,&this->op)){

        /* weld the packet into the bitstream */
        ogg_stream_packetin(&this->mux->state,&op);

        /* write out pages (if any) */
        while(!eos){
          //if result > 0 there are more packets available
          int result=ogg_stream_pageout(&this->mux->state,&this->og);
          if(result==0)break;
          //write ogg page to stream 
          // since that function outputs the ogg headers OK, i suppose there's no error there.
          this->mux->write(this->og);

          /* this could be set above, but for illustrative purposes, I do
             it here (to show that vorbis does know where the stream ends) */

          if(ogg_page_eos(&og))eos=1;
        }
      }
    }

要消化的东西很多,但我真的希望有人能帮助我。
提前致谢。

4

1 回答 1

2

错误在于将 16 位样本传递给浮点数(32 位!!!)vorbis 缓冲区,我假设浮点数也是 16 位(doh)

所以分配一个缓冲区

char * data[SAMPLES*2]; // for 16 bit mono samples

并将这些东西移到浮动 vorbis 缓冲区解决了整个问题

vorbisbuffer =  vorbis_analysis_buffer(&this->vd,SAMPLES);//still 4410 samples
alcCaptureSamples(mic->pdevice,data,SAMPLES); // move the data to the  "data"buffer

for(int i =0;i<SAMPLES;i++){
    // make floats out of 16 bit samples
    vorbisbuffer[0][i]=((data[i*2+1]<<8)|(0x00ff&(int)data[i*2]))/32768.f; 
}

所以对于人类来说如下:

  • 取样本的右字节,在 32 位缓冲区中将其向左移动 8 位
  • 取样本的左字节,并在缓冲区上运行 AND 运算符
  • 将整个内容向左移动 16 位(/32768)(首先是最低有效字节)

听起来可能过于复杂,但是当去隔行立体声时它非常有意义,看起来像这样(是的,我从 SDK 中偷了这个,但是当我阅读它时我根本没有得到它)

vorbisbuffer =  vorbis_analysis_buffer(&this->vd,SAMPLES*CHANNELS);
alcCaptureSamples(mic->pdevice,data,SAMPLES); // open al init'ed to stereo16
//where the first dimension is the audio channel and the second the sample index
for(int i =0;i<SAMPLES;i++){  
    vorbisbuffer[0][i]=((data[i*4+1]<<8)|
              (0x00ff&(int)data[i*4]))/32768.f;
    vorbisbuffer[1][i]=((data[i*4+3]<<8)|
              (0x00ff&(int)data[i*4+2]))/32768.f;  
}
于 2010-07-17T14:28:38.363 回答