Render a user’s video

The Video SDK allows you to render the video of each user who join a session.

  1. Retrieve the IZoomVideoSDKUser object related to each user as they join the session.
  2. Obtain the IZoomVideoSDKRawDataPipe from each user whose stream you’d like to render.
  3. Subscribe to their video pipe.
  4. Listen for frames.

Retrieve user

To be notified when users join a session, you can use onUserJoin within ZoomVideoSDKDelegate:

void CExampleListener::onUserJoin(IZoomVideoSDKUserHelper* pUserHelper, IVideoSDKVector<IZoomVideoSDKUser*>* userList)
{
	CString strInfo;
	IZoomVideoSDKUser* pUser;
	int count = userList->GetCount();

	for (int i = 0; i < count; i++)
	{
		pUser = userList->GetItem(i);
		if (!pUser) continue;

		strInfo.Format(_T("A user joined the session: name=%s"), pUser->getUserName());
	}
}

For more information on implementing this delegate, refer to the listen for callback events guide.

Subscribe to user’s video pipe

Now that you have access to each user represented by a IZoomVideoSDKUser object, you must retrieve the IZoomVideoSDKRawDataPipe of each user whose video you would like to render and to subscribe to that user’s video pipe.

// CExampleRenderer.h
class CExampleRenderer : public IZoomVideoSDKRawDataPipeDelegate
{
    // ...
public: // IZoomVideoSDKRawDataPipeDelegate
	virtual void onRawDataFrameReceived(YUVRawDataI420* data_);
	virtual void onRawDataStatusChanged(RawDataStatus status);
    // ...
}

// CExampleRenderer.cpp
ZoomVideoSDKErrors CExampleRenderer::Subscribe(IZoomVideoSDKUser* pUser, ZoomVideoSDKRawDataType dataType, int size)
{
    // Set the resolution.
    ZoomVideoSDKResolution resolution = ZoomVideoSDKResolution_360P;
	
    // Get the video pipe for the user.
    IZoomVideoSDKRawDataPipe* pPipe = NULL;
	pPipe = pUser->GetVideoPipe();
	if (!pPipe) return;
    
    // Call subscribe.
	err = pPipe->subscribe(resolution, this)
    
    return err;
}

Receive video frames

The class above inherits from IZoomVideoSDKRawDataPipeDelegate, which provides two callbacks. onRawDataFrameReceived(YUVRawDataI420 data_)* provides video data in YUV format. This data parameter YUVRawDataI420 provides everything needed to be able to render the single video frame’s data.

void CExampleRenderer::onRawDataFrameReceived(YUVRawDataI420* data_)
{
    // Get frame data resolution.
  data_->GetStreamWidth();
	data_->GetStreamHeight();
    
    // Get frame buffer.
    data_->GetYBuffer();
    data_->GetUBuffer();
    data_->GetVBuffer();
	
    // Get frame rotation
	data_->GetRotation();
}

onRawDataStatusChanged(RawDataStatus status) is called when there is a change in raw data status.

void CExampleRenderer::onRawDataStatusChanged(RawDataStatus status)
{
	if (status == RawData_On)
	{
        // Now subscribed to user's data.
	}
	else
	{ 
		// No longer subscribed to user's data.
	}
}

Unsubscribe from User’s Video Pipe

To stop rendering a user’s content, you must unsubscribe from the user’s video by calling the unsubscribe():

void CExampleRenderer::unSubscribe(IZoomVideoSDKUser* pUser)
{
    if (pUser->GetVideoPipe())  
		pUser->GetVideoPipe()->unSubscribe(this);	
}

Sending raw video data (optional)

The class above inherits from IZoomVideoSDKRawDataPipeDelegate, which provides two callbacks. onRawDataFrameReceived(YUVRawDataI420 data_)* provides video data in YUV format. This data parameter YUVRawDataI420 provides everything needed to render the single video frame’s data.

// CExampleVideoSource.h
class CExampleVideoSource : public IZoomVideoSDKVideoSource
{
    // ...
public: // IZoomVideoSDKVideoSource
    virtual    void onInitialize(IZoomVideoSDKVideoSender* sender, IVideoSDKVector<VideoSourceCapability >* support_cap_list, VideoSourceCapability& suggest_cap);
    virtual void onPropertyChange(IVideoSDKVector<VideoSourceCapability >* support_cap_list, VideoSourceCapability suggest_cap);
    virtual void onStartSend();
    virtual void onStopSend();
    virtual void onUninitialized();
    // ...
private: 
    IZoomVideoSDKVideoSender* m_pSender;
}

// CExampleVideoSource.cpp

void CExampleVideoSource::onInitialize(IZoomVideoSDKVideoSender* sender, IVideoSDKVector<VideoSourceCapability >* support_cap_list, VideoSourceCapability& suggest_cap)
{
    // Store IZoomVideoSDKVideoSender.
    if (!sender) return;
    m_pSender = sender;

    // Inspect video capabilities. 
    if (!support_cap_list) return;
    unsigned int nCount = support_cap_list->GetCount();    
    for(int i=0; i<nCount; i++)
    {
        VideoSourceCapability& cap_ = support_cap_list->GetItem(i);
    }
}

// Call sendVideoFrame to send a frame buffer of raw data.
char* pFrameData;
int width;
int height;
int frameLength;
int rotation;

m_pSender->sendVideoFrame(pFrameData, width, height, frameLength, rotation);

The support_cap_list parameter provides a vector of current video capabilities for each frame to send. The suggest_cap parameter is the current suggested video capability. The callback onPropertyChange will be called when this changes.

void CExampleVideoSource::onPropertyChange(IVideoSDKVector<VideoSourceCapability >* support_cap_list, VideoSourceCapability suggest_cap)
{
    if (!support_cap_list) return;
    unsigned int nCount = support_cap_list->GetCount();    

    for(int i=0; i<nCount; i++)
    {
        VideoSourceCapability& cap_ = support_cap_list->GetItem(i);
    }

    // Example: Suggested video resolution changed to 1080p.
    if (suggest_cap.width == 1920 && suggest_cap.height == 1080)
    {
    }
}

Raw video data can also be preprocessed using onPreProcessRawData within IZoomVideoSDKVideoSourcePreProcessor.

void CExampleVideoSourcePreProcessor::onPreProcessRawData(YUVProcessDataI420* rawData)
{
    // Use the rawData parameter to perform preprocessing actions.
    unsigned int frameWidth = rawData->GetWidth();
    unsigned int frameHeight = rawData->GetHeight();
    char* yBuffer = rawData->GetYBuffer();
    char* uBuffer = rawData->GetUBuffer();
    char* vBuffer = rawData->GetVBuffer();
}

Camera Controls

Camera functionality can be configured using IZoomVideoSDKVideoHelper. To get the current camera list use getCameraList.

IZoomVideoSDKVideoHelper* pInsVideoHelper = m_pVideoSDK->getVideoHelper();

if (pInsVideoHelper->getNumberOfCameras() > 0) 
	{
		IVideoSDKVector<IZoomVideoSDKCameraDevice*>* pCameraList = pInsVideoHelper->getCameraList();
		for (int i=0; i<pCameraList->GetCount(); i++)
		{
			IZoomVideoSDKCameraDevice* pCamera = m_pCameraList->GetItem(i);

			CString strItem;
			strItem.Format(_T("%s***%s"), pCamera->getDeviceName(), pCamera->getDeviceId());
    }
	}

To select a camera use selectCamera on the IZoomVideoSDKCameraDevice object of the desired camera.

IVideoSDKVector<IZoomVideoSDKCameraDevice*>* pCameraList = pInsVideoHelper->getCameraList();

IZoomVideoSDKCameraDevice* pCamera = m_pCameraList->GetItem(0);
pVideoHelper->selectCamera(pCamera->getDeviceId());

You can also switch to the next available camera with switchCamera.

IZoomVideoSDKVideoHelper* pVideoHelper = m_pVideoSDK->getVideoHelper();
if (!pVideoHelper) return; 

pVideoHelper->switchCamera();