FFmpeg使用AVFilter音频重采样

使用ffmpeg录音或者转换视频格式时,有时需要对音频进行重新采样,这里使用AVFilter过滤器重采样,非常方便

.h文件

#pragma once
/*
*  使用过滤器对音频重新采样 
*  本类使用4.13版本ffmpeg
*  2019-6-27
*/
#include <windows.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavfilter\buffersrc.h>
#include <libavfilter\buffersink.h>
#include <libavutil\opt.h>
#include "libavformat/avformat.h"
#include "libavutil/audio_fifo.h"

#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avformat.lib")
#ifdef __cplusplus
};
#endif


class CAudioResample
{
public:
	CAudioResample();
	~CAudioResample();

public:
	AVFilterContext* GetBuffersinkPtr();
	AVFilterContext* GetBuffersrcoPtr();

	bool InitFilter(AVCodecContext* dec_ctx,AVCodecContext* en_ctx);
	int AudioResample_Frame(AVFrame* srcFrame, int flags, AVFrame* destFrame);

private:
	AVFilterContext* buffersink_ctx;
	AVFilterContext* buffersrc_ctx;
	AVFilterGraph* filter_graph;
};

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

.cpp文件

#include "stdafx.h"
#include "AudioResample.h"

CAudioResample::CAudioResample()
{
}

CAudioResample::~CAudioResample()
{
	avfilter_graph_free(&filter_graph);
	filter_graph = nullptr;
	buffersrc_ctx = nullptr;
	buffersink_ctx = nullptr;
}

AVFilterContext* CAudioResample::GetBuffersinkPtr()
{
	return buffersink_ctx;
}

AVFilterContext* CAudioResample::GetBuffersrcoPtr()
{
	return buffersrc_ctx;
}

bool CAudioResample::InitFilter(AVCodecContext* dec_ctx, AVCodecContext* enc_ctx)
{
	if (!dec_ctx || !enc_ctx)
		return false;

	if (dec_ctx->codec_type != AVMEDIA_TYPE_AUDIO)
		return false;

	AVFilterInOut* inputs = avfilter_inout_alloc();
	AVFilterInOut* outputs = avfilter_inout_alloc();
	filter_graph = avfilter_graph_alloc();
	const AVFilter* buffersrc = nullptr;
	const AVFilter* buffersink = nullptr;
	buffersrc_ctx = nullptr;
	buffersink_ctx = nullptr;
	bool result = true;
	char args[512];
	char args2[512];

	if (!inputs || !outputs || !filter_graph)
	{
		result = false;
		goto End;
	}
	buffersrc = avfilter_get_by_name("abuffer");
	buffersink = avfilter_get_by_name("abuffersink");
	if (!buffersrc || !buffersink)
	{
		result = false;
		goto End;
	}
	_snprintf(args, sizeof(args),
		"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
		dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate,
		av_get_sample_fmt_name(dec_ctx->sample_fmt),
		dec_ctx->channel_layout);
	if (avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph) < 0)
	{
		result = false;
		goto End;
	}
	if (avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph)  < 0)
	{
		result = false;
		goto End;
	}

	if (av_opt_set_bin(buffersink_ctx, "sample_fmts", (uint8_t*)&enc_ctx->sample_fmt,
		sizeof(enc_ctx->sample_fmt), AV_OPT_SEARCH_CHILDREN) < 0)
	{
		result = false;
		goto End;
	}
	if (av_opt_set_bin(buffersink_ctx, "sample_rates", (uint8_t*)&enc_ctx->sample_rate,
		sizeof(enc_ctx->sample_rate), AV_OPT_SEARCH_CHILDREN) < 0)
	{
		result = false;
		goto End;
	}
	if (av_opt_set_bin(buffersink_ctx, "channel_layouts", (uint8_t*)&enc_ctx->channel_layout,
		sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN) < 0)
	{
		result = false;
		goto End;
	}
	inputs->name = av_strdup("out");
	inputs->filter_ctx = buffersink_ctx;
	inputs->pad_idx = 0;
	inputs->next = NULL;
	outputs->name = av_strdup("in");
	outputs->filter_ctx = buffersrc_ctx;
	outputs->pad_idx = 0;
	outputs->next = NULL;
	if (!inputs->name || !outputs->name)
	{
		result = false;
		goto End;
	}
	if (avfilter_graph_parse_ptr(filter_graph, "anull", &inputs, &outputs, NULL) < 0)
	{
		result = false;
		goto End;
	}
	if (avfilter_graph_config(filter_graph, NULL) < 0)
	{
		result = false;
		goto End;
	}
End:
	avfilter_inout_free(&inputs);
	avfilter_inout_free(&outputs);
    
	return result;
}

int CAudioResample::AudioResample_Frame(AVFrame* srcFrame, int flags, AVFrame* destFrame)
{
	if (!srcFrame || !destFrame)
		return -1;

	if (av_buffersrc_add_frame_flags(buffersrc_ctx, srcFrame, flags) < 0)
		return -1;

	if (av_buffersink_get_frame(buffersink_ctx, destFrame) < 0)
		return -1;

	return 0;
}

调用:【pInputCodecCtx为音频输入解码器,pOutputCodecCtx音频输出编码器】

CAudioResample* audioresample = new CAudioResample();
if (!audioresample->InitFilter(pInputCodecCtx, pOutputCodecCtx))
{
	return -1;
}
AVFrame *filter_frame = av_frame_alloc();
//frame为解码后的帧,filter_frame为重采样后的帧
ret = audioresample->AudioResample_Frame(frame, 0, filter_frame);
if(ret < 0)
{
   return -1;
}

 如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_60259116/article/details/127494372