Как поместить аудиоданные в AVFrame для кодирования - PullRequest
0 голосов
/ 15 апреля 2020

Я пытаюсь кодировать необработанный звук PCM в G711A и G711U, а затем декодировать его, с этими кодеками все работает нормально, потому что я могу выбрать любое значение для AVCodecContext frame_size для кодирования, но в случае кода Opus c AVCodecContext frame_size является равно 120, поэтому, если я правильно понял, если размер моего массива входных данных больше 120, тогда мне нужно сделать какую-то буферизацию и разделить мои входные данные на несколько частей, а затем последовательно поместить их в AVFrame-> data и передать AVFrame в кодировку.

В результате я получаю очень плохой звук, и я получаю этот результат не только при использовании кода Opus c, но и в G711, если я установил для AVCodecContext frame_size какое-то значение, которое будет меньше размер моих входных данных.

Итак, мой вопрос: каков правильный способ кодирования входных данных, если их размер больше, чем AVCodecContext frame_size? Нужно ли разбивать входные данные на несколько частей, которые <= AVCodecContext frame_size, если да, то как мне это сделать? </p>

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

void encode(uint8_t *data, unsigned int length)
{
    int rawOffset = 0;
    int rawDelta = 0;
    int rawSamplesCount = frameEncode->nb_samples <= length ? frameEncode->nb_samples : length;

    while (rawSamplesCount > 0)
    {
        memcpy(frameEncode->data[0], &data[rawOffset], sizeof(uint8_t) * rawSamplesCount);

        encodeFrame();

        rawOffset += rawSamplesCount;
        rawDelta = length - rawOffset;
        rawSamplesCount = rawDelta > frameEncode->nb_samples ? frameEncode->nb_samples : rawDelta;
    }

    av_frame_unref(frameEncode);
}

void encodeFrame()
{
    /* send the frame for encoding */
    int ret = avcodec_send_frame(contextEncoder, frameEncode);
    if (ret < 0)
    {
        LOGE(TAG, "[encodeFrame] avcodec_send_frame error: %s", av_err2str(ret));
        return;
    }

    /* read all the available output packets (in general there may be any number of them) */
    while (ret >= 0)
    {
        ret = avcodec_receive_packet(contextEncoder, packetEncode);
        if (ret < 0 && ret != AVERROR(EAGAIN)) LOGE(TAG, "[encodeFrame] error in avcodec_receive_packet: %s", av_err2str(ret));
        if (ret < 0) break;
        std::pair<uint8_t*, unsigned int> p = std::pair<uint8_t*, unsigned int>();
        p.first = (uint8_t *)(malloc(sizeof(uint8_t) * packetEncode->size));
        memcpy(p.first, packetEncode->data, (size_t)packetEncode->size);
        p.second = (unsigned int)(packetEncode->size);

        listEncode.push_back(p); // place encoded data into list to finally create one array of encoded data from it
    }
    av_packet_unref(packetEncode);
}

Вы можете вижу, что я делю свои входные данные на несколько частей, затем помещаю их в frame-> data и затем передаю кадр в кодировку, но я не уверен, что это правильный путь.

UPD: я заметил, что когда я использую G711, если я установил AVCodecContext frame_size на 160, а размер моих входных данных равен 160 или 320, все работает нормально, но если размер входных данных равен 640, тогда я получаю плохой жужжащий звук.

1 Ответ

0 голосов
/ 17 апреля 2020

Вы сказали все это, ", поэтому, если я правильно понял, если размер моего массива входных данных больше 120, тогда мне нужно сделать какую-то буферизацию и разделить мои входные данные на несколько частей, а затем последовательно поместить их в AVFrame-> data и передайте AVFrame в кодировку. "

Это то, что вам нужно. Буфер сэмплов и каждый раз отправляйте фиксированную сумму для кодирования.

...