【音视频】使用ffmpeg gdigrab采集桌面和程序窗口(4-1)

本文详细介绍了如何使用ffmpeg的gdigrab模块采集桌面和程序窗口,包括初始化采集器、开启采集线程、处理窗口变化以及适配视频转换器。尽管存在帧率限制和窗口采集问题,但gdigrab对于基本的桌面和部分窗口采集仍是一个可行的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在研究程序窗口截流,因为之前用过ffmpeg的gdigrab,所以知道gdigrab也可以截取窗口图片,但实际上没用过。经过研究,通过将avformat_open_input中url设置为“title={程序名}"获取format context从而得到图片。

1、初始化gdigrab采集器

int GdigrabCaptor::init(const std::string& deviceId, const int fps)
{
   
	int err = ERROR_CODE_OK;
	if (m_inited) {
   
		return err;
	}

	do {
   
		if (deviceId.empty()) {
   
			err = ERROR_CODE_PARAMS_ERROR;
			break;
		}

		m_deviceId = deviceId;

		RECT rect = {
   };
		err = initDevice(m_deviceId, m_deviceName, rect);
		HCMDR_ERROR_CODE_BREAK(err);

		avdevice_register_all();
		avformat_network_init();
		m_inputFmt = av_find_input_format("gdigrab");
		if (m_inputFmt == nullptr) {
   
			err = ERROR_CODE_FFMPEG_FIND_INPUT_FORMAT_FAILED;
			break;
		}

		m_rect = rect;
		m_fps = fps;
		if (m_fps < 0) {
   
			m_fps = GDIGRAB_CAPTOR_MIN_FRAMERATE;
		}
		else if (m_fps > GDIGRAB_CAPTOR_MAX_FRAMERATE) {
   
			m_fps = GDIGRAB_CAPTOR_MAX_FRAMERATE;
		}
		err = initGdigrab(m_deviceName, m_rect, m_fps);
		HCMDR_ERROR_CODE_BREAK(err);

		m_pixelFmt = AV_PIX_FMT_BGRA;
		m_timebase = {
    1, AV_TIME_BASE };

		m_inited = true;
	} while (0);

	if (err != ERROR_CODE_OK) {
   
		LOGGER::Logger::log(LOGGER::LOG_TYPE_ERROR, "[%s] init camera captor error: %s, last error: %lu",
			__FUNCTION__, HCMDR_GET_ERROR_DESC(err), GetLastError());
		cleanup();
	}

	return err;
}

其中initDevice中,根据deviceId获取HMONITOR或者HWND,然后获取显示器或者窗口大小、名称。需要注意的是,采集窗口时发现窗口最小化了,先将其显示出来,再获取其大小,也便于采集编码。

int GdigrabCaptor::initDevice(const std::string& deviceId, std::string& deviceName, RECT& deviceRect)
{
   
	int err = ERROR_CODE_OK;

	do {
   
		long handle = atol(deviceId.c_str());
		HMONITOR monitor = reinterpret_cast<HMONITOR>(handle);
		HWND hwnd = reinterpret_cast<HWND>(handle);
		MONITORINFO mi;
		mi.cbSize = sizeof(mi);
		if (GetMonitorInfo(monitor, &mi)) {
   					
			deviceName = "desktop";
			deviceRect = mi.rcMonitor;
			m_isDesktop = true;
		}
		else {
   
			TCHAR title[_MAX_FNAME] = {
    0 };
			RECT rect = {
   };
			// 将最小化窗口显示出来
			if (::IsIconic(hwnd)) {
   
				::ShowWindow(hwnd, SW_SHOWNOACTIVATE);
			}
			BOOL ret = GetWindowText(hwnd, title, sizeof(title)) && GetClientRect(hwnd, &rect);
			if (!ret) {
   
				err = ERROR_CODE_DEVICE_GET_MONITOR_FAILED;
				break;
			}
#ifdef UNICODE
			deviceName = HELPER::StringConverter::convertUnicodeToAscii(title);
#else
			deviceName = title;
#endif // UNICODE
			deviceRect = rect;
			m_isDesktop = false;
		}
	
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值