< Resampler.h >
#ifndef __RESAMPLER_H__
#define __RESAMPLER_H__
extern "C" {
#include "libswresample/swresample.h"
#include "libavutil/frame.h"
}
class Resampler
{
public:
Resampler();
virtual ~Resampler();
int open(int in_sample_rate,
int in_channel_count,
uint64_t in_channel_layout,
enum AVSampleFormat in_sample_fmt,
int out_sample_rate,
int out_channel_count,
uint64_t out_channel_layout,
enum AVSampleFormat out_sample_fmt);
void close();
int resample(AVFrame *frame, int inLen);
int checkResampler(int sample_rate, int channel_count, int channel_layout, enum AVSampleFormat sample_fmt);
void moveOutBuffer(int len);
unsigned char* outBuf() { return m_pOutBuf; }
int outBufIndex() { return m_nOutBufIndex; }
void resetOutBufIndex() { m_nOutBufIndex = 0; }
protected:
struct SwrContext* m_pSwrCtx;
int m_nSampleRateIn;
int m_nChannelCountIn;
uint64_t m_nChannelLayoutIn;
enum AVSampleFormat m_nSampleFormatIn;
int m_nSampleRateOut;
int m_nChannelCountOut;
uint64_t m_nChannelLayoutOut;
enum AVSampleFormat m_nSampleFormatOut;
unsigned char* m_pOutBuf;
int m_nOutBufSize;
int m_nOutBufIndex;
FILE* m_pFile;
};
#endif
< Resampler.cpp >
#include "Resampler.h"
#include "GlobalEnv.h"
extern "C" {
#include "libavutil\opt.h"
}
Resampler::Resampler()
{
m_pSwrCtx = NULL;
m_nSampleRateIn = m_nSampleRateOut = 0;
m_nChannelCountIn = m_nChannelCountOut = 0;
m_nChannelLayoutIn = m_nChannelLayoutOut = 0;
m_nSampleFormatIn = m_nSampleFormatOut = AV_SAMPLE_FMT_NONE;
m_pOutBuf = NULL;
m_nOutBufSize = m_nOutBufIndex = 0;
m_pFile = NULL;
}
Resampler::~Resampler()
{
if (m_pOutBuf) {
delete[] m_pOutBuf;
m_pOutBuf = NULL;
}
}
int Resampler::open(int in_sample_rate,
int in_channel_count,
uint64_t in_channel_layout,
enum AVSampleFormat in_sample_fmt,
int out_sample_rate,
int out_channel_count,
uint64_t out_channel_layout,
enum AVSampleFormat out_sample_fmt)
{
int err;
char errbuf[128];
m_pSwrCtx = swr_alloc();
av_opt_set_int(m_pSwrCtx, "in_sample_rate", in_sample_rate, 0);
av_opt_set_int(m_pSwrCtx, "in_channel_count", in_channel_count, 0);
av_opt_set_int(m_pSwrCtx, "in_channel_layout", in_channel_layout, 0);
av_opt_set_sample_fmt(m_pSwrCtx, "in_sample_fmt", in_sample_fmt, 0);
av_opt_set_int(m_pSwrCtx, "out_sample_rate", out_sample_rate, 0);
av_opt_set_int(m_pSwrCtx, "out_channel_count", out_channel_count, 0);
av_opt_set_int(m_pSwrCtx, "out_channel_layout", out_channel_layout, 0);
av_opt_set_sample_fmt(m_pSwrCtx, "out_sample_fmt", out_sample_fmt, 0);
err = swr_init(m_pSwrCtx);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("swr_init failed, err : %d %s\n", err, errbuf);
return err;
}
m_nSampleRateIn = in_sample_rate;
m_nChannelCountIn = in_channel_count;
m_nChannelLayoutIn = in_channel_layout;
m_nSampleFormatIn = in_sample_fmt;
m_nSampleRateOut = out_sample_rate;
m_nChannelCountOut = out_channel_count;
m_nChannelLayoutOut = out_channel_layout;
m_nSampleFormatOut = out_sample_fmt;
m_nOutBufIndex = 0;
DXPRINTF("resampler opened\n");
#if 0
m_pFile = fopen("resample.wav", "wb");
#endif
return 0;
}
void Resampler::close()
{
if (m_pSwrCtx) {
swr_free(&m_pSwrCtx);
m_pSwrCtx = NULL;
}
if (m_pOutBuf) {
delete[] m_pOutBuf;
m_pOutBuf = NULL;
m_nOutBufSize = m_nOutBufIndex = 0;
}
if (m_pFile) {
fclose(m_pFile);
m_pFile = NULL;
}
}
int Resampler::resample(AVFrame *frame, int inLen)
{
int out_size = av_rescale_rnd(inLen, m_nSampleRateOut, m_nSampleRateIn, AV_ROUND_UP);
if (out_size*m_nChannelCountOut > m_nOutBufSize) {
if (m_pOutBuf) delete[] m_pOutBuf;
m_pOutBuf = new unsigned char[out_size*m_nChannelCountOut];
m_nOutBufSize = out_size*m_nChannelCountOut;
}
uint8_t *ptr = &m_pOutBuf[m_nOutBufIndex];
int ret = swr_convert(m_pSwrCtx, &m_pOutBuf, out_size,
(const uint8_t **)frame->extended_data, frame->nb_samples);
int dst_bufsize = av_samples_get_buffer_size(NULL, m_nChannelCountOut, ret, m_nSampleFormatOut, 1);
m_nOutBufIndex += dst_bufsize;
if (m_pFile) fwrite(ptr, dst_bufsize, 1, m_pFile);
return ret;
}
int Resampler::checkResampler(int sample_rate, int channel_count, int channel_layout, enum AVSampleFormat sample_fmt)
{
if (
sample_rate != m_nSampleRateIn ||
channel_count != m_nChannelCountIn ||
channel_layout != m_nChannelLayoutIn ||
sample_fmt != m_nSampleFormatIn
) {
return -1;
}
return 0;
}
void Resampler::moveOutBuffer(int len)
{
if (len > 0) {
memcpy(m_pOutBuf, &m_pOutBuf[m_nOutBufIndex-len], len);
m_nOutBufIndex = len;
}
}
< Resampler 사용 >
Resampler *m_pResampler;
AVCodec* m_pCodec;
AVCodecContext* m_pCodecCtx;
...
avcodec_open2(m_pCodecCtx, m_pCodec, NULL);
m_pResampler = new Resampler();
err = m_pResampler->open(
m_pCodecCtx->sample_rate, m_pCodecCtx->channels, m_pCodecCtx->channel_layout, m_pCodecCtx->sample_fmt,
m_pCodecCtx->sample_rate, m_pCodecCtx->channels, m_pCodecCtx->channel_layout, AV_SAMPLE_FMT_S16);
int retLen = avcodec_decode_audio4(m_pCodecCtx, m_pFrame, &got_frame, &m_avPacket);
if (retLen <= 0) {
DXPRINTF("audio decode error : %d\n", retLen);
return retLen;
}
int out_size = av_samples_get_buffer_size(NULL, m_pCodecCtx->channels, m_pFrame->nb_samples,
m_pCodecCtx->sample_fmt, 1);
if (out_size <= 0) {
return -1;
}
retLen = m_pResampler->resample(m_pFrame, out_size);
out_size = m_pResampler->outBufIndex();
memcpy(m_pOutBuf, m_pResampler->outBuf(), out_size); // now m_pOutBuf has resampled audio data
m_pResampler->resetOutBufIndex();
m_nOutBufSize = out_size;
if (m_pFile) fwrite(m_pOutBuf, m_nOutBufSize, 1, m_pFile);