Аудиовыход в файл .wav действителен, но при кодировании с помощью Vorbis он записывает тишину? - PullRequest
2 голосов
/ 17 июля 2010

Последние три дня я охотился на жуков и отчасти отказался. Я просмотрел все примеры в 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 Ответ

2 голосов
/ 17 июля 2010

Ошибка в передаче 16-битных сэмплов в плавающий (32-битный !!!) буфер vorbis, где я предполагал, что float также был 16-битным (до))

таким образом, выделяя буфер

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

и перемещение материала в буфер float 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; 
}

так для людей это выглядит следующим образом:

  • взять правый байт семпла, сдвинуть его на 8 бит влево в 32-битном буфере
  • возьмите левый байт семпла и запустите на нем оператор 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;  
}
...