62 lines
2.3 KiB
C++
62 lines
2.3 KiB
C++
|
#include "FFmpegResample.h"
|
||
|
#include "BoostLog.h"
|
||
|
#include "FFmpegResample.h"
|
||
|
|
||
|
extern "C" {
|
||
|
#include <libavcodec/avcodec.h>
|
||
|
#include <libswresample/swresample.h>
|
||
|
}
|
||
|
|
||
|
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::milliseconds>(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;
|
||
|
}
|