【问题标题】:Encoding pcm and decoding opus data using libopus in C在 C 中使用 libopus 编码 pcm 和解码 opus 数据
【发布时间】:2018-10-12 21:57:22
【问题描述】:

我正在尝试使用 libopus 对来自硬件的传入 pcm 数据进行编码,然后使用相同的库对其进行解码,但我得到的结果是 decoded.raw 可以使用 aplay -t raw --rate=48000 --buffer-size=1920 --channels=1 --format=FLOAT_LE decoded.raw 命令播放,但它仍然只是一个白色噪音。 test.raw 文件可以用之前的命令播放就好了,没问题。但是test.opus 文件不能以任何方式播放。不知道我在这里遗漏了什么,数据在test.raw 中写得很好,所以我认为这不是记录策略的问题。

#include <string>
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alext.h>
#include <opus/opus.h>
#include <string.h>

int main() {
    FILE* raw = fopen("test.raw", "w");
    FILE* opus = fopen("test.opus", "w");
    FILE* decoded = fopen("decoded.raw", "w");
    int i = 0;
    size_t capture_frequency = 48000;
    size_t samples_size = capture_frequency/25;
    int channels_length = 1;

    int error;
    OpusEncoder* encoder = opus_encoder_create(capture_frequency, 1, OPUS_APPLICATION_VOIP, &error);

    if(error != OPUS_OK){
        fprintf(stderr, "failed to create codec\n");
    }

    const ALCchar* deviceName = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
    ALCdevice* device = alcCaptureOpenDevice(deviceName, capture_frequency, AL_FORMAT_MONO_FLOAT32, samples_size);

    if(device == NULL) {
        fprintf(stderr, "could not open device\n");
        return -1;
    }

    printf("Opened capture device \"%s\"\n", alcGetString(device, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));

    alcCaptureStart(device);

    OpusDecoder* decoder = opus_decoder_create(capture_frequency, channels_length, &error);

    if(error != OPUS_OK)
        fprintf(stderr, "failed to create decoder\n");

    while(alcGetError(device) == ALC_NO_ERROR && i < 1000){
        ALCint availableSamples = 0;
        alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &availableSamples);

        if(availableSamples < samples_size)
            continue;

        float* buffer = (float*)malloc(samples_size*channels_length*sizeof(float));
        alcCaptureSamples(device, buffer, samples_size);

        printf("got %d samples, we needed %d\n", samples_size, samples_size);

        unsigned char* output = (unsigned char*) malloc(4000);
        int bytes_written = opus_encode_float(encoder, buffer, samples_size, output, 4000);

        if(bytes_written < 0){
            if(bytes_written == OPUS_BAD_ARG)
                fprintf(stderr, "invalid args\n");
            else
                fprintf(stderr, "failed to encode\n");
            continue;
        } else {
            printf("got output from encoder %d\n", bytes_written);
        }
        fwrite(output, bytes_written, 1, opus);

        float* output_pcm = (float*) malloc(samples_size*sizeof(float));
        int decoded_bytes = opus_decode_float(decoder, output, bytes_written, output_pcm, samples_size, 1);

        if(decoded_bytes < 1)
            fprintf(stderr, "failed to decode bytes\n");
        else {
            printf("%d bytes decoded\n", decoded_bytes);
        }

        fwrite(output_pcm, samples_size*sizeof(float), 1, decoded);
        fwrite(buffer, samples_size*sizeof(float), 1, raw);
        i++;
    }

    fclose(opus);
    fclose(raw);
    fclose(decoded);
    alcCaptureStop(device);
    alcCaptureCloseDevice(device);
    opus_decoder_destroy(decoder);
    opus_encoder_destroy(encoder);
}

【问题讨论】:

  • 我很好奇您解码的字节数是否与您记录到原始缓冲区的字节数相同?如果您可以发布指向这两个文件的链接,我愿意看看。

标签: c openal opus


【解决方案1】:

您无法解码 file.opus,因为您需要一些 OPUS 编解码器的容器。这很重要,因为 OPUS 是面向数据包的格式。所以它不能解码字节流。它可以解码数据包流。

当您将数据包一一写入文件时,您会丢失数据包边界并且无法恢复它们。

您可以选择一种可能的格式:

  • ogg
  • 马特罗斯卡

我认为您可以轻松找到方便的库来编写它们。

【讨论】:

    猜你喜欢
    • 2019-01-09
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-04
    • 2020-08-14
    • 2013-05-05
    • 2015-08-07
    • 2018-09-07
    相关资源
    最近更新 更多