FFmpeg - преобразованный звук с большим шумом - PullRequest
1 голос
/ 28 марта 2019

Я не знаком с повторной выборкой auido. Я попытался пересмотреть потоки auido из двух видео. Выход первого был близок к оригиналу, но с шумом, другой был почти полон шума.

Информация для первого

128 кбит / с, 48,0 кГц, 2 канала, AACLC

Информация для второго

384 кбит / с, 48,0 кГц, 6 каналов, AACLC

Я обнаружил, что, когда я установил размер выборки 16 , первый работал неплохо, но все еще с шумом. Другой работал слишком плохо, но все еще имел звук. Что и как определить размер выходной выборки? Хотя я использовал channels * av_get_bytes_per_sample((AVSampleFormat)output_fmt) в качестве размера выходного сэмпла, потому что хотел, чтобы он был таким же, как оригинал, у него не было звука вообще.

MyResampling.cpp

bool MyResample::open(AVCodecParameters* par) {
    if (!par) {
        std::cout << "par is null" << std::endl;
        return false;
    }   
    audio_context = swr_alloc_set_opts(
        audio_context, av_get_default_channel_layout(2), (AVSampleFormat)output_fmt,
        par->sample_rate, av_get_default_channel_layout(par->channels), (AVSampleFormat)par->format, par->sample_rate,
        0, 0);

    avcodec_parameters_free(&par);
    int ret = swr_init(audio_context);
    if (ret != 0) {
        std::cout << "failed to open audio codec" << std::endl;
    }
    return true;
}

int MyResample::resample(AVFrame* frame, unsigned char* output)
{
    if (!frame)
        return 0;
    if (!output)
        av_frame_free(&frame);

    uint8_t* data[2] = { 0 };
    data[0] = output;
    int ret = swr_convert(audio_context, data, frame->nb_samples, (const uint8_t**)frame->data, frame->nb_samples);
    //int size =  ret * frame->channels * av_get_bytes_per_sample((AVSampleFormat)output_fmt);
    int size = av_samples_get_buffer_size(nullptr, frame->channels, frame->nb_samples, (AVSampleFormat)output_fmt, 1);
    if (ret < 0)
        return ret;
    return size;
}

MyAudioPlayer.cpp

bool open()
{
    close();
    QAudioFormat fmt;
    fmt.setSampleRate(sample_rate); // from audioStream->codecpar->sample_rate
    fmt.setSampleSize(16); //
    fmt.setChannelCount(channels); // from audioStream->codecpar->channels
    fmt.setCodec("audio/pcm");
    fmt.setByteOrder(QAudioFormat::LittleEndian);
    fmt.setSampleType(QAudioFormat::UnSignedInt);
    output = new QAudioOutput(fmt);
    io = output->start();
    if (io)
        return true;
    return false;
}

bool write(const unsigned char* data, int data_size)
{
    if (!data || data_size <= 0)
        return false;
    if (!output || !io)
    {
        return false;
    }
    int size = io->write((char*)data, data_size);
    if (data_size != size)
        return false;
    return true;
}

main.cpp

MyAudioPlayer::open();
unsigned char* pcm = new unsigned char[1024 * 1024];
if (demux.get_media_type() == 1) { // audio 
    audio_decode.sendPacket(pkt);
    AVFrame* frame = audio_decode.receiveFrame();
    int len = resample.resample(frame, pcm);
    while (len > 0) {
        if (MyAudioPlayer::check_space() >= len) {
            MyAudioPlayer::write(pcm, len);
            break;
        }
        msleep(1);
    }               
}

1 Ответ

0 голосов
/ 28 марта 2019

Если у вас проблемы с конечным качеством и шумом, возможно, вы неправильно понимаете, как правильно выполнить повторную выборку, или в вашей конфигурации есть ошибка.

Взгляните на этот пример: libswresample-example .

Я не знаком с API FFmpeg, потому что для повторной выборки я склонен использовать libsamplerate .

Что касается старого примера, то это шагичтобы выполнить базовую повторную выборку с помощью FFMPEG:

  1. Начните с настройки контекста повторной выборки:
//Set up resampling context
SwrContext *swr = swr_alloc();
av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "in_sample_rate", 44100, 0);
av_opt_set_int(swr, "out_sample_rate", 22050, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
swr_init(swr);

В зависимости от типов входных данных и формата, который вы ожидаете получить в качестве выходных данных., вам нужно будет указать правильный формат.Это эквивалент в C ++ стандарте :

----------------------------------------
| *AV_SAMPLE_FMT_S16* | `std::int16_t` |
| *AV_SAMPLE_FMT_S32* | `std::int32_t` |
| *AV_SAMPLE_FMT_FLT* | `float`        |
| *AV_SAMPLE_FMT_DBL  | `double`       |
| *AV_SAMPLE_FMT_U8P* | `std::uint8_t` |
| ...                 |                |
Получите ваши данные из любого места в нужном формате и оцените количество выборок.

После этого вы можете выполнить повторную выборку за несколько шагов:

Оценить количество выходных выборок
uint8_t* out_samples;
int out_num_samples = av_rescale_rnd(swr_get_delay(swr, in_samplerate) + in_num_samples, out_samplerate, in_samplerate, AV_ROUND_UP);
Выделите память для выходного файла
av_samples_alloc(&out_samples, NULL, out_num_channels, out_num_samples, AV_SAMPLE_FMT_FLT, 0);
Преобразование входных данных в ожидаемый выходной формат
out_num_samples = swr_convert(swr, &out_samples, out_num_samples, &in_samples, in_num_samples);
Не забудьте освободить память
av_freep(&out_samples);
swr_free(&swr);

Если у вас есть шумы, возможно, форматы входного и выходного форматов неправильные или качество повторной выборки низкое.

Например, не паникуйте, если вы получаете меньше образцов, чем вы ожидали.Это обычное поведение из-за того, как работает фильтрация.Чтобы получить оставшийся трейлинг, вы можете выполнить шаг 5 с NULL в качестве входных данных, чтобы очистить внутренние данные.

...