FFMPEG录屏(3)----捕获系统声音和麦克风

系统声音捕获方式同样有很多手段,老一点的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持续更新地址

你可能感兴趣的:(录屏软件)