在视频通话或互动直播中进行屏幕共享,可以将说话人或主播的屏幕内容,以视频的方式分享给其他说话人或观众观看,以提高沟通效率。
屏幕共享在如下场景中应用广泛:
我们在 GitHub 提供一个开源的示例项目。你可以前往下载体验。
在实现屏幕共享前,请确保已在你的项目中实现基本的实时音视频功能。详见开始音视频通话或开始互动直播。
声网在 v2.4.0 对屏幕共享相关接口进行梳理,目前在 Windows 平台上支持:
startScreenCaptureByDisplayId
通过 Display ID 开启屏幕共享,不要使用 startScreenCaptureByScreenRect
通过相对位置开启屏幕共享。调用 getScreenCaptureSources
并从返回的 sourceId
中获取待共享屏幕的 Display ID。Display ID 可标识每个屏幕。
SIZE size;
size.cx = 100;
size.cy = 100;
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
int count = 0;
for (size_t i = 0; i < infos->getCount(); i++) {
ScreenCaptureSourceInfo info = infos->getSourceInfo(i);
if (info.type == ScreenCaptureSourceType_Screen) {
m_cmbScreenRegion.InsertString(i, utf82cs(info.sourceName));
count++;
}
}
调用 startScreenCaptureByDisplayId
,传入 Display ID,设置屏幕共享配置,以开启屏幕共享。
IScreenCaptureSourceList* infos = m_rtcEngine->getScreenCaptureSources(size, size, true);
ScreenCaptureSourceInfo info = infos->getSourceInfo(sel);
ScreenCaptureParameters capParam;
m_rtcEngine->startScreenCaptureByDisplayId((int)info.sourceId, regionRect, capParam);
在 Windows 系统中,每个显示器的屏幕都位于同一个虚拟屏幕上。为了共享指定屏幕区域,你必须获取以下参数:
具体实现步骤如下:
获取显示器屏幕信息列表。
// 获取显示器屏幕信息列表
void CAgoraScreenCapture::InitMonitorInfos()
{
// m_monitors 是 CMonitors 类的实例。CMonitors 类的具体实现参考示例项目。
// m_monitors 调用 EnumMonitor 获取显示器屏幕信息列表。EnumMonitor 方法的具体实现参考示例项目。
m_monitors.EnumMonitor();
// 定义 infos 向量,用于存储显示器屏幕信息列表。
std::vector<CMonitors::MonitorInformation> infos = m_monitors.GetMonitors();
CString str = _T("");
// 获取每个显示器屏幕在虚拟屏幕上的 Rectangle 坐标
for (size_t i = 0; i < infos.size(); i++) {
RECT rcMonitor = infos[i].monitorInfo.rcMonitor;
CString strInfo;
strInfo.Format(_T("Screen%d: rect = {%d, %d, %d, %d} ")
, i + 1, rcMonitor.left, rcMonitor.top, rcMonitor.right, rcMonitor.bottom);
}
str += strInfo;
m_cmbScreenRegion.InsertString(i, utf82cs(infos[i].monitorName));
}
m_cmbScreenRegion.InsertString(infos.size(), _T("Select Window Hwnd Rect Area"));
m_staScreenInfo.SetWindowText(str);
m_cmbScreenRegion.SetCurSel(0);
}
通过待共享的显示器屏幕在虚拟屏幕上的 Rectangle 坐标以及待共享区域在显示器屏幕上的 Rectangle 坐标实现屏幕共享。
void CAgoraScreenCapture::OnBnClickedButtonStartShareScreen()
{
m_screenShare = !m_screenShare;
if (m_screenShare) {
// 获取选择的显示器屏幕
int sel = m_cmbScreenRegion.GetCurSel();
agora::rtc::Rectangle regionRect = { 0,0,0,0 }, screenRegion = {0,0,0,0};
// 获取指定的待共享区域在整个显示器屏幕中的 Rectangle 坐标。
// GetMonitorRectangle 方法的具体实现详见示例项目。
regionRect = m_monitors.GetMonitorRectangle(sel);
// 获取显示器屏幕在虚拟屏幕中的 Rectangle 坐标。GetScreenRect 方法的实现详见示例项目。
screenRegion = m_monitors.GetScreenRect();
m_monitors.GetScreenRect();
// 屏幕共享的编码参数配置
ScreenCaptureParameters capParam;
// 开始屏幕共享
m_rtcEngine->startScreenCaptureByScreenRect(screenRegion, regionRect, capParam);
m_btnShareScreen.SetWindowText(screenShareCtrlStopShare);
m_btnStartCap.EnableWindow(FALSE);
}
else {
// 停止屏幕共享
m_rtcEngine->stopScreenCapture();
m_btnShareScreen.SetWindowText(screenShareCtrlShareSCreen);
m_btnStartCap.EnableWindow(TRUE);
}
}
Windows 系统为每个窗口分配一个 Window ID,数据类型为 HWND。该 ID 对应唯一的 Windows 窗口。为了兼容 x86 和 x64 系统,API 参数使用 view_t
类型。
通过获取该 Window ID,我们可以按如下步骤在 Windows 平台上实现窗口共享:
获取所有顶层窗口的 Window ID 列表。
// 获取所有最新顶层窗口的 HWND 并储存在 m_listWnd 中
int CAgoraScreenCapture::RefreshWndInfo()
{
m_listWnd.RemoveAll();
::EnumWindows(&CAgoraScreenCapture::WndEnumProc, (LPARAM)&m_listWnd);
return static_cast<int>(m_listWnd.GetCount());
}
通过指定窗口的 Window ID 共享窗口。
void CAgoraScreenCapture::OnBnClickedButtonStartShare()
{
if (!m_rtcEngine || !m_initialize)
return;
HWND hWnd = NULL;
// 需要共享的 Window ID
hWnd = m_listWnd.GetAt(m_listWnd.FindIndex(m_cmbScreenCap.GetCurSel()));
int ret = 0;
m_windowShare = !m_windowShare;
if (m_windowShare)
{
// 设置 captureParameters
ScreenCaptureParameters capParam;
GetCaptureParameterFromCtrl(capParam);
// 设置 regionRect
CRect rcWnd = { 0 };
::GetClientRect(hWnd, &rcWnd);
agora::rtc::Rectangle rcCapWnd = { rcWnd.left, rcWnd.top, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top };
// 开始屏幕共享
ret = m_rtcEngine->startScreenCaptureByWindowId(hWnd, rcCapWnd, capParam);
if (ret == 0)
m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("Succees!"));
else
m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("Failed!"));
m_btnStartCap.SetWindowText(screenShareCtrlEndCap);
m_btnShareScreen.EnableWindow(FALSE);
}
else {
// 停止屏幕共享
ret = m_rtcEngine->stopScreenCapture();
if (ret == 0)
m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("Success!"));
else
m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("Failed!"));
m_btnStartCap.SetWindowText(screenShareCtrlStartCap);
m_btnShareScreen.EnableWindow(TRUE);
}
}
getScreenCaptureSources
startScreenCaptureByDisplayId
startScreenCaptureByWindowId
startScreenCaptureByScreenRect
updateScreenCaptureParameters
setScreenCaptureContentHint
updateScreenCaptureRegion
stopScreenCapture
我们在 GitHub 提供一个实现同时发布屏幕共享流和用户视频流功能的开源示例项目。你可以前往 Agora-Screen-Sharing-Windows 下载体验。
SDK 在 v2.4.0 版本中废弃了原有的 startScreenCapture
方法。你可以继续使用,但声网不再推荐。
视频共享编码属性 ScreenCaptureParameters
类中各参数的设置可能会影响计费。从 v2.4.1 版本起,如果你将 dimensions
参数设为默认值,则声网使用 1920 x 1080 进行计费。
在 Windows 平台上进行屏幕共享时,如果共享的是 QQ 聊天窗口会导致共享窗口黑屏。
共享游戏画面时,声网推荐你根据下表设置 ScreenCaptureParameters
中的 dimensions
、frameRate
、bitrate
。
分辨率 | 帧率(fps) | 码率(Kbps) |
---|---|---|
160 × 120 | 15 | 130 |
120 × 120 | 15 | 100 |
320 × 180 | 15 | 280 |
180 × 180 | 15 | 200 |
240 × 180 | 15 | 240 |
320 × 240 | 15 | 400 |
240 × 240 | 15 | 280 |
424 × 240 | 15 | 440 |
640 × 360 | 15 | 800 |
360 × 360 | 15 | 520 |
640 × 360 | 30 | 1200 |
360 × 360 | 30 | 800 |
480 × 360 | 15 | 640 |
480 × 360 | 30 | 980 |
640 × 480 | 15 | 1000 |
480 × 480 | 15 | 800 |
640 × 480 | 30 | 1500 |
480 × 480 | 30 | 1200 |
848 × 480 | 15 | 1220 |
848 × 480 | 30 | 1860 |
640 × 480 | 10 | 800 |
1280 × 720 | 15 | 2260 |
1280 × 720 | 30 | 3420 |
960 × 720 | 15 | 1820 |
960 × 720 | 30 | 2760 |
1920 × 1080 | 15 | 4160 |
1920 × 1080 | 30 | 6300 |
1920 × 1080 | 60 | 6500 |