系统声音捕获方式同样有很多手段,老一点的WAVEAPI,WASAPI,portaudio等等,这里我们通过ffmpeg对virtual-audio-capturer进行捕获。
首先安装,screen-capture,他会同时为你添加两个DSHOW设备,screen-capture-recorder和virtual-audio-capturer,其中前者是用于屏幕捕获,在第一篇中,将设备名直接修改即可进行屏幕捕获。
同桌面图像捕获一样,首先初始化FFMPEG,对一些类库资源进行注册。
av_register_all();
avdevice_register_all();
创建一个AVFormatContext句柄
AVFormatContext *_fmt_ctx = avformat_alloc_context();
打开音频设备,可以是virtual-audio-capturer或具体麦克风设备
AVInputFormat *_input_fmt = av_find_input_format("dshow");
avformat_open_input(&_fmt_ctx, "audio=virtual-audio-capturer", _input_fmt, NULL);
获取音频流信息
avformat_find_stream_info(_fmt_ctx, NULL);
int stream_index = -1;
for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
break;
}
}
为声音流查找并打开解码器
AVCodecContext *_codec_ctx = _fmt_ctx->streams[stream_index]->codec;
AVCodec *_codec = avcodec_find_decoder(_codec_ctx->codec_id);
avcodec_open2(_codec_ctx, _codec, NULL);
为音频数据创建对应的AVFrame和AVPacket结构体
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
定义一个解码函数,这里与之前一篇捕获桌面图像中不同,采用新版FFMpeg接口
int decode(AVFrame * frame, AVPacket * packet)
{
int ret = avcodec_send_packet(_codec_ctx, packet);
if (ret < 0) {
return -1;
}
while (ret >= 0)
{
ret = avcodec_receive_frame(_codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
if (ret < 0) {
return -1;
}
if (ret == 0 && _on_data){
//do something here with frame_rgba
}
av_frame_unref(frame);
}
return 0;
}
随后在捕获线程或循环中进行音频数据的捕获以及解码
void record_loop()
{
int ret = 0;
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
while (_running == true) {
av_init_packet(packet);
ret = av_read_frame(_fmt_ctx, packet);
if (ret < 0) {
if (_on_error) _on_error(AE_FFMPEG_READ_FRAME_FAILED, _cb_extra_index);
al_fatal("read frame failed:%d %ld", );
break;
}
if (packet->stream_index == _stream_index) {
ret = decode(frame, packet);
if (ret != AE_NO) {
if (_on_error) _on_error(AE_FFMPEG_DECODE_FRAME_FAILED, _cb_extra_index);
al_fatal("decode pcm packet failed:%d", ret);
break;
}
}
av_packet_unref(packet);
}
//flush packet left in decoder
decode(frame, NULL);
av_packet_free(&packet);
av_frame_free(&frame);
}
以上就是通过ffmpeg dshow方式对扬声器和麦克风数据进行捕获的全部流程
CSDN源码下载
GitHub持续更新地址