FFmpeg4.0笔记:封装ffmpeg的音频重采样功能类CSwr

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);
}
原文地址:https://www.cnblogs.com/gongluck/p/11023760.html