声卡&麦克风实时采集并重采样

上篇文章讲了如何用最新的技术采集声卡和麦克风,但是在工作中通常需要进行重采样为(44100、FLTP),再进行推流,所以本篇是在上次的基础上完成了重采样,重采样的核心代码如下:

// audiocap.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "AudioCapT.h"
#include <conio.h>

extern "C"
{
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
}

#include <iostream>
using namespace std;
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")
#pragma comment(lib,"swresample.lib")

bool FillFltpSample(double *dst, int nb_samples, int nb_channels, char * pPcmBuffer, int nPcmBufLen)
{
	int nTotal = nb_samples*nb_channels * 4;

	if (!dst || !pPcmBuffer)
		return false;

	memset(dst, 0, nb_samples*nb_channels * 4);

	int nTmp = 0;

	if (nTotal >= nPcmBufLen)
	{
		nTmp = nPcmBufLen;
	}
	else
	{
		nTmp = nTotal;
	}

	memcpy(dst, pPcmBuffer, nTmp);

	return true;
}


int _tmain(int argc, _TCHAR* argv[])
{
	int64_t src_ch_layout = av_get_default_channel_layout(2), dst_ch_layout = AV_CH_LAYOUT_STEREO;
	int src_rate = 48000, dst_rate = 44100;
	uint8_t **src_data = NULL, **dst_data = NULL;
	int src_nb_channels = 0, dst_nb_channels = 0;
	int src_linesize, dst_linesize;
	int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples;
	enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_FLT, dst_sample_fmt = AV_SAMPLE_FMT_S16;
	const char * pszDstFileName = "D:\\test44100.pcm";
	FILE * fDstFile = NULL;
	int nDstBufSize = 0;
	const char * strFmt = NULL;
	struct SwrContext * swr_ctx = NULL;
	int nRet = 0;

	CAudioCapT ac;

	CoInitialize(NULL);

	av_register_all();

	avcodec_register_all();

	fDstFile = fopen(pszDstFileName, "wb");
	if (!fDstFile) {
		printf("open file failed.\n");
		return -1;
	}

	//创建重采样上下文

	swr_ctx = swr_alloc();
	if (!swr_ctx) 
	{
		printf("swr_alloc failed.\n");
		goto end;
	}

	av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);
	av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0);
	av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0);
	av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);
	av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0);
	av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);


	if ((nRet = swr_init(swr_ctx)) < 0)
	{
		printf("Failed to initialize the resampling context\n");
		goto end;
	}

	src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);

	nRet = av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels,
		src_nb_samples, src_sample_fmt, 0);

	if (nRet < 0)
	{
		printf("Could not allocate source samples\n");
		goto end;
	}

	max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
	dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
	nRet = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
		dst_nb_samples, dst_sample_fmt, 0);

	if (nRet < 0) 
	{
		printf("Could not allocate destination samples\n");
		goto end;
	}
	
	int nReadSize = src_nb_samples * src_nb_channels * 4;

	char * pPcmBuffer = new char[nReadSize];

	if (!pPcmBuffer)
	{
		printf("Pcm Buffer failed.\n");
		goto end;
	}

	ZeroMemory(pPcmBuffer, nReadSize);

	ac.SetDeiveType(CAudioCapT::MICPHONE);
	ac.Init();
	ac.Start();

	Audio_Data * pAudio = NULL;

	int nAudioLeftLen = 0;

	int nPcmBufferLen = 0;

	int nLen = 0;

	bool bFirst = true;

	while (1)
	{
		if (_kbhit())
		{
			ac.Stop();
			break;
		}

		//缓冲区是否已经满了
		while (nPcmBufferLen != nReadSize)
		{
			if (pAudio == NULL)
			{
				pAudio = ac.GetAudio();
				if (pAudio)
					nAudioLeftLen = pAudio->iDataLen;
				continue;
			}
			else
			{
				nLen = nReadSize - nPcmBufferLen;
				if (nLen >= nAudioLeftLen)
				{
					memcpy(pPcmBuffer + nPcmBufferLen, pAudio->pData + (pAudio->iDataLen - nAudioLeftLen), nAudioLeftLen);
					nPcmBufferLen += nAudioLeftLen;
					nAudioLeftLen -= nAudioLeftLen;
					delete [] pAudio->pData;
					pAudio->pData = NULL;
					delete pAudio;
					pAudio = NULL;	
					continue;
				}
				else
				{
					memcpy(pPcmBuffer + nPcmBufferLen, pAudio->pData + (pAudio->iDataLen - nAudioLeftLen), nLen);
					nPcmBufferLen += nLen;
					nAudioLeftLen -= nLen;
				}
			}
		}

		FillFltpSample((double *)src_data[0], src_nb_samples, src_nb_channels, pPcmBuffer, nPcmBufferLen);

		dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

		if (dst_nb_samples > max_dst_nb_samples)
		{
			av_freep(&dst_data[0]);
			nRet = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
				dst_nb_samples, dst_sample_fmt, 1);
			if (nRet < 0)
				break;
			max_dst_nb_samples = dst_nb_samples;
		}
	
		nRet = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)src_data, src_nb_samples);

		if (nRet < 0)
		{
			printf("Error while converting\n");
			goto end;
		}

		nDstBufSize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, nRet, dst_sample_fmt, 1);
		if (nDstBufSize < 0)
		{
			printf("Could not get sample buffer size\n");
			goto end;
		}
		//printf("t:%f in:%d out:%d\n", t, src_nb_samples, ret);
		fwrite(dst_data[0], 1, nDstBufSize, fDstFile);
		printf("+");
		nPcmBufferLen = 0;
	}

end:
	if (pPcmBuffer)
	{
		delete[] pPcmBuffer;
		pPcmBuffer = NULL;
	}

	if (fDstFile)
	{
		fclose(fDstFile);
		fDstFile = NULL;
	}

	if (src_data)
		av_freep(&src_data[0]);

	av_freep(&src_data);

	if (dst_data)
		av_freep(&dst_data[0]);

	av_freep(&dst_data);

	swr_free(&swr_ctx);

	::CoUninitialize();

	printf("\n\n");

	printf("program exit!\n");

	return 0;
}

需要的小伙伴可以从下面下载:

https://download.csdn.net/download/u011711997/10539607

猜你喜欢

转载自blog.csdn.net/u011711997/article/details/81031816