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

发布于 2024-09-10 10:48:36 字数 5825 浏览 8 评论 0原文

过去三天我一直在寻找错误,但我有点放弃了。我已经研究了 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 setup

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;
        }
      }
    }

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

I've been hunting bugs for the past three days and I've kind of given up. I've plowed through all the samples in the OpenAL SDK and the Vorbis examples, but to no avail, so I hope someone can help me.

The problem:
I record audio using OpenAL, and for debug reasons i output it to C:/out.wav which i can then play with any audio player of choice and it plays back whatever i recorded.

The exact same buffer i get from openAL is what I input into libvorbisenc
(I request a buffer with vorbis_analysis_buffer and run alcCaptureSamples on it, after which i let vorbis do it's thing.)

The point being : Why is vorbis returning silence to my output file and how do i get valid compressed audio in my file "C:/out.ogg" ?

Don't worry about some missing or extra parentheses , they were lost in the copy+paste and removal of comments
the code runs, but it's output just isn't valid.

Relevant defines etc:

//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 setup

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


};

The problematic code:

* // 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;
        }
      }
    }

It's a lot to digest, but I really hope someone can help me.
Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

哆啦不做梦 2024-09-17 10:48:36

错误在于将 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;  
}

The error is in passing 16 bit samples to a float (32bit!!!) vorbis buffer, where i was assuming float was also 16 bit ( doh)

so allocating a buffer

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

and moving the stuff over to the float vorbis buffer solves the whole thing

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; 
}

so for humans thats as follows:

  • take the right byte of the sample, shift it 8 bits to the left in a 32 bit buffer
  • take the left byte of the sample, and run an AND operator on it with the buffer
  • shift the whole thing 16 bits to the left (/32768) (least significant byte first )

might sound over-complicated but when de-interlacing stereo it makes perfect sense, which would look like this ( yes i stole this from the SDK's, but i simply didn't get it when i read it)

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;  
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文