2014-08-24 3 views
2

Привет, я пытаюсь взять звук из открытого потока PortAudio, закодировать его с помощью opus, декодировать и снова воспроизвести с помощью portaudio.Присоединение к Portaudio и Opus

Im, делаю это как прототип, чтобы просто попытаться понять механику этих систем, так что нет реального интереса к этому конкретному потоку.

Thing is, portaudio дает буферы, где OPUS нужны фреймы. Ми думал не приведет меня к этому в Portaudio стороне:

err = (Pa_ReadStream(stream, readBuffer, FRAMES_PER_BUFFER)); 
     if (err = paNoError){ 
      qDebug()<<"Fail read"; 
      qDebug()<<Pa_GetErrorText(err); 
      // blockingRecord = false; 
     } 
     while (pos<FRAMES_PER_BUFFER){ 
      memcpy(frameBuffer,readBuffer+(pos*FRAME_SIZE*NUM_CHANNELS),FRAME_SIZE*CHANNELS); 
      compressedSound = om.encodeOpus(frameBuffer); 
      unCompressedSound = om.decodeOpus(compressedSound); 
      memcpy(readBuffer+(pos*FRAME_SIZE*NUM_CHANNELS),unCompressedSound,FRAME_SIZE*CHANNELS); 
      pos++; 
     } 
     pos = 0; 
     err = (Pa_WriteStream(stream, readBuffer, FRAMES_PER_BUFFER)); 
     if (err != paNoError) 
     { 
      qDebug() << "FAIL WRITE"; 
      qDebug()<<Pa_GetErrorText(err); 
      //blockingRecord = false; 
     } 

И это на стороне OPUS:

unsigned char * OpusManager::encodeOpus(unsigned char *frame){ 
    memcpy(encoded, frame, FRAME_SIZE*CHANNELS); 
    int ret = opus_encode(enc, encoded, FRAME_SIZE, compressed_buffer, encoded_data_size); 
    if (ret<0){ 
     qDebug()<<"Failure while compressing sound"; 
     return NULL; 
    } 
    return (compressed_buffer); 
} 

unsigned char * OpusManager::decodeOpus(unsigned char *frame){ 
    int ret= opus_decode(dec, frame, encoded_data_size, decoded, FRAME_SIZE, 0); 
    if (ret<0){ 
     qDebug()<<"Failure while decompressing sound"; 
     return NULL; 
    } 
    memcpy(uncompressed_buffer, decoded, FRAME_SIZE*CHANNELS); 
    return (uncompressed_buffer); 
} 

Нет ошибок без encocing и совершенной СОУД. С кодированием я не получаю ошибок до вызова PA_Writestream, где я получаю «Выходной поток» PaError. Я предполагаю, что способ захвата кадров, которые должны быть реализованы, должен быть ошибочным, но не может найти информацию, чтобы помочь мне в этом.

ответ

2

Похоже, ваша интерпретация параметров frame_size Opus для opus_encode и opus_decode неверна. Если я правильно понял ваш код, вы записываете пакет с размерами кадров FRAMES_PER_BUFFER и затем пытаетесь превратить его в N пакетов размера FRAME_SIZE. Вместо этого мне кажется, что Opus хочет превратить ваш пакет FRAMES_PER_BUFFER в другой пакет равного количества кадров, и при этом используется только параметр FRAME_SIZE как некоторый параметр контроля качества для процесса кодирования. Ниже вы найдете полный образец, который, я считаю, делает то, что вы хотите. Играйте с магическим числом «480» в кодировке()/декодировании() и слышите изменение качества звука.

int opusErr; 
PaError paErr; 
std::string s; 

int const channels = 2; 
int const bufferSize = 480; 
int const sampleRate = 48000; 
int const durationSeconds = 5; 

opus_int32 enc_bytes; 
opus_int32 dec_bytes; 
int framesProcessed = 0; 

std::vector<unsigned short> captured(bufferSize * channels); 
std::vector<unsigned short> decoded(bufferSize * channels); 
// * 2: byte count, 16 bit samples 
std::vector<unsigned char> encoded(bufferSize * channels * 2); 

// initialize opus 
OpusEncoder* enc = opus_encoder_create(
    sampleRate, channels, OPUS_APPLICATION_AUDIO, &opusErr); 
if (opusErr != OPUS_OK) 
{ 
    std::cout << "opus_encoder_create failed: " << opusErr << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

OpusDecoder* dec = opus_decoder_create(
    sampleRate, channels, &opusErr); 
if (opusErr != OPUS_OK) 
{ 
    std::cout << "opus_decoder_create failed: " << opusErr << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

// initialize portaudio 
if ((paErr = Pa_Initialize()) != paNoError) 
{ 
    std::cout << "Pa_Initialize failed: " << Pa_GetErrorText(paErr) << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

PaStream* stream = nullptr; 
if ((paErr = Pa_OpenDefaultStream(&stream, 
     channels, channels, paInt16, sampleRate, 
     bufferSize, nullptr, nullptr)) != paNoError) 
{ 
    std::cout << "Pa_OpenDefaultStream failed: " << Pa_GetErrorText(paErr) << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

// start stream 
if ((paErr = Pa_StartStream(stream)) != paNoError) 
{ 
    std::cout << "Pa_StartStream failed: " << Pa_GetErrorText(paErr) << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

// capture, encode, decode & render durationSeconds of audio 
while (framesProcessed < sampleRate * durationSeconds) 
{ 
    if ((paErr = Pa_ReadStream(stream, 
     captured.data(), bufferSize)) != paNoError) 
    { 
     std::cout << "Pa_ReadStream failed: " << Pa_GetErrorText(paErr) << "\n"; 
     std::getline(std::cin, s); 
     return 1; 
    } 

    if ((enc_bytes = opus_encode(enc, reinterpret_cast<opus_int16 const*>(
     captured.data()), 480, encoded.data(), encoded.size())) < 0) 
    { 
     std::cout << "opus_encode failed: " << enc_bytes << "\n"; 
     std::getline(std::cin, s); 
     return 1; 
    } 

    if ((dec_bytes = opus_decode(dec, encoded.data(), enc_bytes, 
     reinterpret_cast<opus_int16*>(decoded.data()), 480, 0)) < 0) 
    { 
     std::cout << "opus_decode failed: " << dec_bytes << "\n"; 
     std::getline(std::cin, s); 
     return 1; 
    } 

    if ((paErr = Pa_WriteStream(stream, decoded.data(), bufferSize)) != paNoError) 
    { 
     std::cout << "Pa_WriteStream failed: " << Pa_GetErrorText(paErr) << "\n"; 
     std::getline(std::cin, s); 
     return 1; 
    } 

    framesProcessed += bufferSize; 
} 

// stop stream 
if ((paErr = Pa_StopStream(stream)) != paNoError) 
{ 
    std::cout << "Pa_StopStream failed: " << Pa_GetErrorText(paErr) << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

// cleanup portaudio 
if ((paErr = Pa_CloseStream(stream)) != paNoError) 
{ 
    std::cout << "Pa_CloseStream failed: " << Pa_GetErrorText(paErr) << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

if ((paErr = Pa_Terminate()) != paNoError) 
{ 
    std::cout << "Pa_Terminate failed: " << Pa_GetErrorText(paErr) << "\n"; 
    std::getline(std::cin, s); 
    return 1; 
} 

// cleanup opus 
opus_decoder_destroy(dec); 
opus_encoder_destroy(enc); 
+0

thnks dude, который решил проблему. Как я сказал, я пропустил концепцию frame/buffer в opus ^^ – Xeyos