#include "FFmpegResample.h" #include "BoostLog.h" #include "FFmpegResample.h" extern "C" { #include #include } FFmpegResample::~FFmpegResample() { if (m_buffer != nullptr) { delete[] m_buffer; } } void FFmpegResample::initialize(int32_t sampleRateIn, int32_t channelIn, int32_t sampleRateOut, int32_t channelOut, int32_t period) { m_sampleRateOut = sampleRateOut; m_channelOut = channelOut; m_sampleRateIn = sampleRateIn; m_channelIn = channelIn; int64_t outChLayout = channelOut == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; int64_t inChLayout = channelIn == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; m_swrContext = swr_alloc_set_opts(nullptr, outChLayout, AV_SAMPLE_FMT_S16, sampleRateOut, inChLayout, AV_SAMPLE_FMT_S16, sampleRateIn, 0, nullptr); if (m_swrContext == nullptr) { LOG(error) << "swr_alloc_set_opts() failed."; } m_buffer = new uint8_t[sampleRateOut / 1000 * period * channelOut * sizeof(int16_t)]; int status = swr_init(m_swrContext); if (status < 0) { LOG(error) << "swr_init() failed."; } } FFmpegResample::Frame FFmpegResample::resample(const uint8_t *pcm, int32_t size) { auto begin = std::chrono::system_clock::now(); FFmpegResample::Frame ret; // 1. 输入进来的是 1channel 16khz 16bit pcm // 2. 重采样为 2channel 48khz 16bit pcm // 3. 编码为 opus int32_t inSamples = size / m_channelIn / sizeof(int16_t); int32_t outSamples = inSamples * m_sampleRateOut / m_sampleRateIn; uint8_t *outBuffer = buffer.data(); int samples = swr_convert(m_swrContext, &outBuffer, outSamples, &pcm, inSamples); if (samples < 0) { char buffer[512] = {0}; LOG(error) << "avcodec_receive_frame() failed, error: " << av_make_error_string(buffer, sizeof(buffer), samples); return ret; } auto elapsed = std::chrono::duration_cast(std::chrono::system_clock::now() - begin); ret.data = outBuffer; ret.byteSize = samples * m_channelOut * sizeof(int16_t); // LOG(info) << "inSamples: " << inSamples << ", samples: " << samples << ", elapsed: " << elapsed.count(); return ret; }