Windows端实现屏幕共享

本文将为您介绍Windows端如何实现屏幕共享。

功能介绍

屏幕共享功能允许用户在视频通话、直播过程中将自己的屏幕内容实时分享给频道内的其他用户,实现信息的即时共享与可视化交流。

前提条件

在实现屏幕共享前,请确保达成以下条件:

实现屏幕共享

image
说明

1. 配置屏幕共享编码参数

如果需要自定义屏幕共享视频流的编码属性,可以调用setScreenShareEncoderConfiguration接口进行配置,包含分辨率、帧率、码率、GOP、视频旋转方向。

说明
  • 该接口在加入频道前后均可配置,如果每次入会只需要设置一次屏幕流视频编码属性,建议在入会前调用。

  • 如果需要更新配置,可以多次调用该接口。

相关配置如下:

参数名

参数说明

默认值

dimensions

视频分辨率。

0x0,表示推流分辨率跟随屏幕采集的分辨率。最大取值为3840x2160。

frameRate

视频帧率。

默认帧率为 5,最大取值为 30。

bitrate

视频编码码率(Kbps)。

说明

码率设置根据分辨率和帧率有对应的合理范围,该值设置在合理范围内有效,否则SDK会自动调节码率到有效值。

512

keyFrameInterval

关键帧间隔,GOP。单位为毫秒(ms)。

默认值0,表示SDK内部控制关键帧间隔。

forceStrictKeyFrameInterval

是否强制编码器严格按照设置的关键帧间隔产生关键帧。

默认值为 false。

  • false表示编码器会响应他人入会等关键帧请求,关键帧间隔和设置的值不严格匹配。

  • true表示编码器不响应其他关键帧请求,严格按照设置的值产生关键帧。可能会造成订阅者首帧变慢。

rotationMode

推流旋转。

默认值为 AliEngineRotationMode_0。可选择 0、90、180、270 四个角度。

/* 
  config 为客户定义的配置结构体 
*/

AliEngineScreenShareEncoderConfiguration encoderConfig;

encoderConfig.dimensions = AliEngineVideoDimensions(config.dimensions.width, config.dimensions.height);
encoderConfig.frameRate = (AliEngineFrameRate)config.frameRate;
encoderConfig.bitrate = (int)config.bitrate;
encoderConfig.rotationMode = (AliEngineRotationMode)config.rotationMode;
encoderConfig.keyFrameInterval = (int)config.keyFrameInterval;
encoderConfig.forceStrictKeyFrameInterval = config.forceStrictKeyFrameInterval;
   
mpEngine->setScreenShareEncoderConfiguration(canvas, AliEngineVideoTrackScreen);

2. 设置屏幕共享画面预览

如果需要预览屏幕共享画面,请调用SetLocalViewConfig为屏幕共享流(AliEngineVideoTrackScreen)配置显示视图。

AliEngineVideoCanvas canvas;
canvas.renderMode = AliEngineRenderModeFill;
/* 配置好显示的窗口句柄 */
canvas.displayView = (void*)hWnd;
canvas.scaleMode = AliEngineVideoScale_16_9;

mpEngine->SetLocalViewConfig(canvas, AliEngineVideoTrackScreen);

3. (远端)观看屏幕共享

如果需要观看远端用户的屏幕共享画面,可以在OnRemoteTrackAvailableNotify回调中为屏幕共享画面SetRemoteViewConfig设置显示视图。

void ARTCEventListernerImpl::OnRemoteTrackAvailableNotify(const char *uid,
	AliEngineAudioTrack audioTrack,
	AliEngineVideoTrack videoTrack) {

	char logBuffer[MAX_LOG_STRING_SIZE];
	snprintf(logBuffer, USE_LOG_STRING_SIZE, "user %s push video=%d audio=%d", uid, videoTrack, audioTrack);
	SendMessageA(this->mLogHandle, LB_ADDSTRING, WPARAM(), (LPARAM)logBuffer);

	mDlg->HandleTrackChangeEvent(uid, audioTrack, videoTrack);

}

void CARTCExampleDlg::HandleTrackChangeEvent(const char *uid,
	AliEngineAudioTrack audioTrack,
	AliEngineVideoTrack videoTrack) {

	if ((videoTrack & AliEngineVideoTrackScreen) > 0) {

		if ((videoTrack & AliEngineVideoTrackCamera) == 0) {

			AliEngineVideoCanvas canvas;
			canvas.displayView = nullptr;

			mEngine->SetRemoteViewConfig(canvas, uid, AliEngineVideoTrackCamera);
		}


		{
			AliEngineVideoCanvas canvas;
			canvas.displayView = mRemoteView.GetSafeHwnd();

			mEngine->SetRemoteViewConfig(canvas, uid, AliEngineVideoTrackScreen);
		}

		return;
	}

	if ( (videoTrack & AliEngineVideoTrackCamera) > 0) {

		AliEngineVideoCanvas canvas;
		canvas.displayView = mRemoteView.GetSafeHwnd();

		mEngine->SetRemoteViewConfig(canvas, uid, AliEngineVideoTrackCamera );
	}
}

4. 开启屏幕共享

调用 StartScreenShareByScreenRegion开启屏幕共享。

说明

需要配置 mScreenConfig.isPushStream

/*
* 共享屏幕局部
*/
  RECT rc;
  ::GetWindowRect(::GetDesktopWindow(), &rc);

  AliEngineScreenShareRegion screenRegion;
  screenRegion.originX = (float)rc.left;
  screenRegion.originY = (float)rc.top;
  screenRegion.width = (float)(rc.right - rc.left);
  screenRegion.height = (float)(rc.bottom - rc.top);

  AliEngineScreenShareConfig mScreenConfig;
  mScreenConfig.isShareByRegion = false;
  mScreenConfig.shareRegion = screenRegion;
  /* 
    如果不推流,只预览,可以设置为FALSE,
    如果预览的同时推流,则设置为TRUE,可以跳过步骤5(更新配置)直接推流。
  */        
  mScreenConfig.isPushStream = FALSE ; 
  
  mpEngine->StartScreenShareByScreenRegion(screenRegion, mScreenConfig);

5. (可选)更新配置

如果需要更新屏幕共享的配置,可以调用UpdateScreenShareConfig进行。

/* 设置为屏幕共享推流 */
mScreenConfig.isPushStream = TRUE ;

/* 如果想共享局部  */
mScreenConfig.isShareByRegion = true ;

screenRegion.originX = (float)rc.left;
screenRegion.originY = (float)rc.top;
screenRegion.width = (float)(rc.right - rc.left);
screenRegion.height = (float)(rc.bottom - rc.top);

mScreenConfig.isShareByRegion = true;
mScreenConfig.shareRegion = screenRegion;
      
mpEngine->UpdateScreenShareConfig(mScreenConfig);

6. 停止屏幕共享

mpEngine->StopScreenShare();

多窗口共享

配置预览窗口、预览和推流这些基本逻辑和上面的屏幕共享一致,这里就不单独列出代码;

1. 枚举所有可共享的窗口或桌面

调用GetScreenShareSourceInfo获取可共享的窗口或桌面列表。

/*
 1,根据需要设置枚举的类型
*/
mScreenShareType = AliEngineScreenShareDesktop ; 
mScreenShareType = AliEngineScreenShareWindow ; 

/*
 2,下面代码是填充一个comboBox列表
*/
CComboBox *listBox = (CComboBox *)GetDlgItem(IDC_COMBO_SCREEN_SOURCE_LIST);
listBox->ResetContent();

AliEngineScreenSourceList* mCurrentSourceList = mEngine->GetScreenShareSourceInfo(mScreenShareType);

  if (nullptr != mCurrentSourceList)
  {
      for (size_t i = 0; i < mCurrentSourceList->GetCount(); i++) {
      
        AliEngineScreenSourcInfo info = mCurrentSourceList->GetSourceInfo(i);

        /*
        * 如果不希望共享APP自身的窗口,可以通过sourceIsSelf来区分
        */
        if ( info.sourceIsSelf ) {
           continue ;
        }
        
        CString s = AliStringToCString(info.sourceName);
        listBox->AddString(s)
      }    
      
  }

  /*
  3,选中项之后记录ID和Title
  */
  int idx = listBox->GetCurSel();
  
  if (mCurrentSourceList && idx < mCurrentSourceList->GetCount())
  {
    AliEngineScreenSourcInfo info = mCurrentSourceList->GetSourceInfo(idx);
    mSourceId = info.sourceId;
    mSourceTitle = info.sourceName;
  }

2. 共享对应窗口或桌面

根据业务需求,选择调用StartScreenShareByWindowId或者startScreenShareByDesktopId来共享对应窗口或者桌面。

msSourceId是共享桌面的ID,可以通过上文的枚举接口获取;
screenShareSource是配置;

AliEngineScreenShareRegion  shareRegion ;
shareRegion.originX = 0.f;
shareRegion.originY = 0.f;
shareRegion.width = 640.f;
shareRegion.height = 480.f;
            
screenShareSource.isShareByRegion = true ;
screenShareSource.shareRegion =  shareRegion;

  /*
  * 如果想只预览不推流,请参考屏幕共享的介绍,设置isPushStream=FALSE
  */


/*
* 根据产品需求,调用对应的接口进行共享桌面或者窗口
* 共享桌面
*/
mpEngine->StartScreenShareByDesktopId(atol(msSourceId.c_str()), screenShareSource);

/*
* 或者共享窗口
*/
mpEngine->StartScreenShareByWindowId(atol(msSourceId.c_str()), screenShareSource);

/*
* 可以显示获取共享窗口的显示范围和标题
*/
AliEngineScreenShareRegion region;
		mEngine->GetDesktopRegion(mSourceId, mSourceTitle, region);
		CString resolutionMsg;
		resolutionMsg.Format(_T("Resolution: %d x %d"), region.width, region.height);
		((CStatic*)GetDlgItem(IDC_STATIC_SCREEN_SOURCE_RESOLUTION))->SetWindowTextW(resolutionMsg);
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_X))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.originX).c_str());
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_Y))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.originY).c_str());
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_X2))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.width).c_str());
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_Y2))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.height).c_str());
	}
  

3. 停止共享对应窗口或者桌面

mpEngine->StopScreenShare();