音频输出到.wav文件是有效的,但是当用Vorbis编码时,它会记录静音吗?

时间:2010-07-17 13:11:43

标签: c++ audio openal ogg vorbis

过去三天我一直在寻找虫子,我有点放弃了。我已经浏览了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;
        }
      }
    }

要消化很多,但我真的希望有人可以帮助我 提前谢谢。

1 个答案:

答案 0 :(得分:2)

错误是将16位样本传递给float(32bit !!!)vorbis缓冲区,其中我假设float也是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;  
}