Github

https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff

CSwr.h

/*******************************************************************
* Copyright(c) 2019
* All rights reserved.
*
* 文件名称: CSwr.h
* 简要描述: 重采样
*
* 作者: gongluck
* 说明:
*
*******************************************************************/ #ifndef __CSWR_H__
#define __CSWR_H__ #ifdef __cplusplus
extern "C"
{
#endif #include <libswresample/swresample.h> #ifdef __cplusplus
}
#endif #include <string>
#include <mutex> class CSwr
{
public:
virtual ~CSwr(); // 状态
enum STATUS { STOP, LOCKED };
// 设置源参数
bool set_src_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err);
// 设置目标参数
bool set_dst_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err);
// 锁定设置
bool lock_opt(std::string& err);
// 解除锁定
bool unlock_opt(std::string& err);
// 转换(out_count,in_count is per channel's samples)
int convert(uint8_t** out, int out_count, const uint8_t** in, int in_count, std::string& err); private:
STATUS status_ = STOP;
std::recursive_mutex mutex_; SwrContext* swrctx_ = nullptr; AVSampleFormat src_sam_fmt_ = AV_SAMPLE_FMT_NONE;
AVSampleFormat dst_sam_fmt_ = AV_SAMPLE_FMT_NONE;
int64_t src_layout_ = AV_CH_LAYOUT_MONO;
int64_t dst_layout_ = AV_CH_LAYOUT_MONO;
int src_rate_ = 0;
int dst_rate_ = 0;
}; #endif//__CSWR_H__

CSwr.cpp

/*******************************************************************
* Copyright(c) 2019
* All rights reserved.
*
* 文件名称: CSwr.cpp
* 简要描述: 重采样
*
* 作者: gongluck
* 说明:
*
*******************************************************************/ #include "common.h"
#include "CSwr.h" CSwr::~CSwr()
{
std::string err;
unlock_opt(err);
} bool CSwr::set_src_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err)
{
LOCK();
CHECKSTOP(err);
err = "opt succeed."; src_layout_ = layout;
src_rate_ = rate;
src_sam_fmt_ = fmt; return true;
} bool CSwr::set_dst_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err)
{
LOCK();
CHECKSTOP(err);
err = "opt succeed."; dst_layout_ = layout;
dst_rate_ = rate;
dst_sam_fmt_ = fmt; return true;
} bool CSwr::lock_opt(std::string& err)
{
LOCK();
CHECKSTOP(err);
err = "opt succeed."; swrctx_ = swr_alloc_set_opts(swrctx_, dst_layout_, dst_sam_fmt_, dst_rate_, src_layout_, src_sam_fmt_, src_rate_, 0, nullptr);
if (swrctx_ == nullptr)
{
err = "swr_alloc_set_opts return nullptr.";
return false;
} int ret = swr_init(swrctx_);
CHECKFFRET(ret);
status_ = LOCKED; return true;
} bool CSwr::unlock_opt(std::string& err)
{
LOCK();
err = "opt succeed."; swr_free(&swrctx_);
status_ = STOP;
src_sam_fmt_ = AV_SAMPLE_FMT_NONE;
dst_sam_fmt_ = AV_SAMPLE_FMT_NONE;
src_layout_ = AV_CH_LAYOUT_MONO;
dst_layout_ = AV_CH_LAYOUT_MONO;
src_rate_ = 0;
dst_rate_ = 0; return true;
} int CSwr::convert(uint8_t** out, int out_count, const uint8_t** in, int in_count, std::string& err)
{
LOCK();
CHECKNOTSTOP(err);
err = "opt succeed."; int ret = swr_convert(swrctx_, out, out_count, in, in_count);
CHECKFFRET(ret); return ret;
}

测试

// 音频重采样
void test_swr()
{
bool ret = false;
std::string err;
std::ifstream pcm("in.pcm", std::ios::binary);
CSwr swr; // 分配音频数据内存
uint8_t** src = nullptr;
int srclinesize = 0;
uint8_t** dst = nullptr;
int dstlinesize = 0; // 分配音频数据内存
int srcsize = av_samples_alloc_array_and_samples(&src, &srclinesize, 2, 44100, AV_SAMPLE_FMT_S16, 1);
int dstsize = av_samples_alloc_array_and_samples(&dst, &dstlinesize, 2, 48000, AV_SAMPLE_FMT_S16P, 1);
// 获取样本格式对应的每个样本大小(Byte)
int persize = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16P);
// 获取布局对应的通道数
int channel = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO); ret = swr.set_src_opt(AV_CH_LAYOUT_STEREO, 44100, AV_SAMPLE_FMT_S16, err);
TESTCHECKRET(ret);
ret = swr.set_dst_opt(AV_CH_LAYOUT_STEREO, 48000, AV_SAMPLE_FMT_S16P, err);
TESTCHECKRET(ret);
ret = swr.lock_opt(err);
TESTCHECKRET(ret); std::ofstream outpcm("out.pcm", std::ios::binary);
while (!pcm.eof())
{
pcm.read(reinterpret_cast<char*>(src[0]), srcsize);
int size = swr.convert(dst, dstlinesize, (const uint8_t**)(src), 44100, err);
// 拷贝音频数据
for (int i = 0; i < size; ++i) // 每个样本
{
for (int j = 0; j < channel; ++j) // 每个通道
{
outpcm.write(reinterpret_cast<const char*>(dst[j] + persize * i), persize);
}
}
} ret = swr.unlock_opt(err);
TESTCHECKRET(ret); // 清理
if (src != nullptr)
{
av_freep(&src[0]);
}
av_freep(&src);
if (dst != nullptr)
{
av_freep(&dst[0]);
}
av_freep(&dst);
}
05-17 15:10