FaceAccess/Record/FFmpegResample.cpp

62 lines
2.3 KiB
C++
Raw Normal View History

2024-06-18 14:27:48 +08:00
#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;
}