前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FFmpeg4.0笔记:封装ffmpeg的音频重采样功能类CSwr

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

作者头像
gongluck
发布2019-06-15 21:33:03
8520
发布2019-06-15 21:33:03
举报
文章被收录于专栏:C++C++

Github

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

CSwr.h

代码语言:javascript
复制
#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:
    ~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);
    // 转换
    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

代码语言:javascript
复制
#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);
    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);
    dst_layout_ = layout;
    dst_rate_ = rate;
    dst_sam_fmt_ = fmt;
    return true;
}

bool CSwr::lock_opt(std::string& err)
{
    LOCK();
    CHECKSTOP(err);
    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(swrctx_, dst_layout_, dst_sam_fmt_, dst_rate_, src_layout_, src_sam_fmt_, src_rate_, 0, nullptr) return nullptr.";
        return false;
    }
    int ret = swr_init(swrctx_);
    CHECKFFRET(ret);
    status_ = LOCKED;
    return true;
}

bool CSwr::unlock_opt(std::string& err)
{
    LOCK();
    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);
    int ret = swr_convert(swrctx_, out, out_count, in, in_count);
    CHECKFFRET(ret);
    return ret;
}

测试

代码语言:javascript
复制
#include "CDecode.h"
#include "CSws.h"
#include "CSwr.h"
#include <iostream>
#include <fstream>

CSws g_sws;
uint8_t* g_pointers[4] = { 0 };
int g_linesizes[4] = { 0 };

CSwr g_swr;
uint8_t** g_data = nullptr;
int g_linesize = 0;
int64_t g_layout = AV_CH_LAYOUT_STEREO;
int g_rate = 44100;
enum AVSampleFormat g_fmt = AV_SAMPLE_FMT_DBLP;


void DecStatusCB(CDecode::STATUS status, std::string err, void* param)
{
    std::cout << std::this_thread::get_id() << " got a status " << status << std::endl;
}

void DecFrameCB(const AVFrame* frame, CDecode::FRAMETYPE frametype, void* param)
{
    //std::cout << std::this_thread::get_id() << " got a frame." << frametype << std::endl;
    if (frametype == CDecode::FRAMETYPE::VIDEO)
    {
        if (frame->format == AV_PIX_FMT_YUV420P)
        {
            static std::ofstream video("out.rgb", std::ios::binary | std::ios::trunc);
            static int i = 0;
            if (++i > 9)
                return; 

            /*
            video.write(reinterpret_cast<const char*>(frame->data[0]), frame->linesize[0] * frame->height);
            video.write(reinterpret_cast<const char*>(frame->data[1]), frame->linesize[1] * frame->height / 2);
            video.write(reinterpret_cast<const char*>(frame->data[2]), frame->linesize[2] * frame->height / 2);
            */

            std::string err;
            // 将输出翻转
            g_pointers[0] += g_linesizes[0] * (240 - 1);
            g_linesizes[0] *= -1;
            // 转换
            g_sws.scale(frame->data, frame->linesize, 0, frame->height, g_pointers, g_linesizes, err);
            // 还原指针,以便拷贝数据
            g_linesizes[0] *= -1;
            g_pointers[0] -= g_linesizes[0] * (240 - 1);
            video.write(reinterpret_cast<const char*>(g_pointers[0]), g_linesizes[0] * 240);
        }
    }
    else if (frametype == CDecode::FRAMETYPE::AUDIO)
    {
        if (frame->format == AV_SAMPLE_FMT_FLTP)
        {
            static std::ofstream audio("out.pcm", std::ios::binary | std::ios::trunc);
            std::string err;
            int ret = g_swr.convert(g_data, g_linesize, (const uint8_t * *)frame->data, frame->nb_samples, err);
            auto size = av_get_bytes_per_sample(g_fmt);
            for (int i = 0; i < ret; ++i)
            {
                for (int j = 0; j < av_get_channel_layout_nb_channels(g_layout); ++j)
                {
                    audio.write(reinterpret_cast<const char*>(g_data[j] + size * i), size);
                }
            }
        }
    }
}

int main(int argc, char* argv[])
{
    std::string err;
    bool ret = false;

    ret = g_sws.set_src_opt(AV_PIX_FMT_YUV420P, 576, 432, err);
    ret = g_sws.set_dst_opt(AV_PIX_FMT_RGB24, 320, 240, err);
    ret = g_sws.lock_opt(err);
    int size = av_image_alloc(g_pointers, g_linesizes, 320, 240, AV_PIX_FMT_RGB24, 1);

    ret = g_swr.set_src_opt(AV_CH_LAYOUT_STEREO, 48000, AV_SAMPLE_FMT_FLTP, err);
    ret = g_swr.set_dst_opt(g_layout, g_rate, g_fmt, err);
    ret = g_swr.lock_opt(err);
    size = av_samples_alloc_array_and_samples(&g_data, &g_linesize, av_get_channel_layout_nb_channels(g_layout), g_rate, g_fmt, 0);

    CDecode decode;
    ret = decode.set_input("in.flv", err);
    ret = decode.set_dec_callback(DecFrameCB, nullptr, err);
    ret = decode.set_dec_status_callback(DecStatusCB, nullptr, err);

    int i = 0;
    while (i++ < 1)
    {
        ret = decode.begindecode(err);

        std::cout << "input to stop decoding." << std::endl;
        getchar();

        ret = decode.stopdecode(err);
    }

    ret = g_sws.unlock_opt(err);
    av_freep(&g_pointers[0]);

    ret = g_swr.unlock_opt(err);
    if (g_data)
        av_freep(&g_data[0]);
    av_freep(&g_data);

    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-06-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Github
  • CSwr.h
  • CSwr.cpp
  • 测试
相关产品与服务
腾讯云服务器利旧
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档