之前本人写过ffmpeg录制系统声音的博客,但是用到的设备名称叫做virtual-audio-capturer,需要实现安装一个软件,ffmpeg才能找到这个设备,很不方便;
今天用windows api采集声卡声音,进行声卡数据抓取,然后放入ffmpeg进行编码。
关于声卡的数据采集api,可以参看下面博客:
声卡数据采集
本人从声卡中获取到的格式是:
采样率:48000
采样位数:32
通道数:双通道
最终编码时,编码后的的格式为AV_SAMPLE_FMT_FLTP(平面格式),代码如下:
av_opt_set_channel_layout(m_pAudioConvertCtx, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_channel_layout(m_pAudioConvertCtx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(m_pAudioConvertCtx, "in_sample_rate", m_formatex.Format.nSamplesPerSec, 0);
av_opt_set_int(m_pAudioConvertCtx, "out_sample_rate", 48000, 0);
av_opt_set_sample_fmt(m_pAudioConvertCtx, "in_sample_fmt", AV_SAMPLE_FMT_S32, 0);
av_opt_set_sample_fmt(m_pAudioConvertCtx, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
相应的采样转换代码如下:
uint8_t *audio_buf[2] = {
0 };
audio_buf[0] = (uint8_t *)frame_mic_encode->data[0];
audio_buf[1] = (uint8_t *)frame_mic_encode->data[1];
int nb = swr_convert(m_pAudioConvertCtx, audio_buf, num_frames_to_read, (const uint8_t**)&p_audio_data, num_frames_to_read);
其中p_audio_data为从声卡中获取的数据buffer,num_frames_to_read为数据长度(以每个采样为单位)
由于编码格式是平面格式,所以定义了audio_buf[2]。
如果系统未播放任何声音,则num_frames_to_read为0,这种情况,本人尚未处理。本人给出的例子是系统中播放一段音乐时的处理。
main函数如下所示:
#include <iostream>
#include "GetSystemAudio.h"
int main()
{
CGetSystemAudio cCGetSystemAudio;
cCGetSystemAudio.SetSavePath("E:\\learn\\ffmpeg\\FfmpegTest\\x64\\Release");
cCGetSystemAudio.StartCapture();
Sleep(30000);
cCGetSystemAudio.StopCapture();
return 0;
}
可以看出,录了30秒。
GetSystemAudio.h的内容如下:
#pragma once
#include <string>
#include <combaseapi.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avutil.h"
#include "libavutil/fifo.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")
#ifdef __cplusplus
};
#endif
class CGetSystemAudio
{
public:
CGetSystemAudio();
~CGetSystemAudio();
public:
void SetSavePath(std::string strPath);
int StartCapture();
void StopCapture();
int OpenOutPut();
private:
static DWORD WINAPI AudioSystemCaptureProc(LPVOID lpParam);
void AudioSystemCapture();
static DWORD WINAPI AudioSystemWriteProc(LPVOID lpParam);
void AudioSystemWrite();
HRESULT IsFormatSupported(IAudioClient *audioClient);
private:
std::string m_strRecordPath;
bool m_bRecord;
IAudioClient *pAudioClient = nullptr;
IAudioCaptureClient *pAudioCaptureClient = nullptr;
WAVEFORMATEXTENSIBLE m_formatex
Windows API采集声卡声音并使用FFmpeg编码

这篇博客介绍了如何使用Windows API直接从声卡采集声音数据,并结合FFmpeg进行编码。通过创建IAudioClient和IAudioCaptureClient接口实例,实现了音频数据的实时捕获。然后利用Swresample库将原始数据转换为平面格式(AV_SAMPLE_FMT_FLTP),并进行编码。程序在主线程外启动两个线程分别负责音频数据的捕获和编码写入,确保了录音过程的顺畅。
最低0.47元/天 解锁文章
1521





