# Render user video

<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

> The code on this page only works with the **custom UI**.

In custom UI mode, the SDK provides multiple options to render user video after a user subscribes to another user's video. After following the steps to render a user's video, each option contains a different type of video stream.

-   **Single attendee** - A single user's video.
-   **Active speaker** - A single user's video that automatically updates when the active speaker changes.
-   **Preview** - A preview of the local user's video.
-   **Share** - The content being shared by another user.

Regardless of which render option you are using, the SDK utilizes four main components.

-   `ZoomSDKNormalVideoElement`, `ZoomSDKActiveVideoElement`, or `ZoomSDKPreViewVideoElement` - Interface for video element rendering in custom UI.
-   `ZoomSDKVideoContainer` - An object that sets up the video view.
-   `ZoomSDKVideoContainerDelegate` - A delegate that indicates if a video's subscription fails and more.

## Subscribe to error data

Before subscribing to the video, conform your class to the `ZoomSDKVideoContainerDelegate` protocol to know when a video subscription fails. To pass it into the SDK, you'll need a reference to the `ZoomSDKVideoContainer` instance being set up.

```swift
// Add delegate first.
if let videoContainer = ZoomSDK.shared().getMeetingService()?.getVideoContainer() {
    videoContainer.delegate = self
}

// Also, conform your class to the ZoomSDKVideoContainerDelegate
extension ViewController: ZoomSDKVideoContainerDelegate
    func onSubscribeUserFail(_ error: ZoomSDKVideoSubscribeFailReason, videoElement element: ZoomSDKVideoElement) {

    }
}
```

```objectivec
// In your .h file, conform to the ZoomSDKVideoContainerDelegate protocol
@interface ZMSDKWindow : NSWindowController <ZoomSDKVideoContainerDelegate> {

}

// In your .m file, add delegate and add onSubscribeUserFail callback
ZoomSDKVideoContainer *videoContainer = [[[ZoomSDK sharedSDK] getMeetingService] getVideoContainer];
if (videoContainer) {
    videoContainer.delegate = self;
}

- (void)onSubscribeUserFail:(ZoomSDKVideoSubscribeFailReason)error videoElement:(ZoomSDKVideoElement *)element {

}
```

When you've finished using the video view, remove the listener to avoid leaks.

```swift
videoContainer.delegate = nil
```

```objectivec
videoContainer.delegate = nil;
```

## Define a video element

The primary user-facing video element is `ZoomSDKVideoElement` and is inherited by the components
`ZoomSDKActiveVideoElement` - for active speaker video,
`ZoomSDKPreViewVideoElement` - for local user preview video, and
`ZoomSDKNormalVideoElement` - for local and remote participant video.

Create a new `ZoomSDKVideoElement` instance based on which video element you need and give it the frame of the `NSView` that you will be using to add the video view to.

```swift
// To create the video element for a local/remote participant video
let yourVideoView:NSView = NSView() // Get your NSView to show a user's video
var normalVideoElement = ZoomSDKNormalVideoElement(frame: yourVideoView.frame)
var videoElement: ZoomSDKVideoElement? = normalVideoElement

// To create the video element for active speaker video
let yourVideoView:NSView = NSView() // Get your NSView to show a user's video
var activeVideoElement = ZoomSDKActiveVideoElement(frame: yourVideoView.frame)
var videoElement: ZoomSDKVideoElement? = normalVideoElement

// To create the video element for local user's preview video
let yourVideoView:NSView = NSView() // Get your NSView to show a user's video
previewVideoElement = ZoomSDKPreViewVideoElement(frame: yourVideoView.frame)
var videoElement: ZoomSDKVideoElement? = normalVideoElement
```

```objectivec
// To create the video element for a local/remote participant video
NSView *yourVideoView = [NSView alloc];
ZoomSDKNormalVideoElement* normalVideoElement = [[ZoomSDKNormalVideoElement alloc] initWithFrame:yourVideoView.frame];

// To create the video element for active speaker video
NSView *yourVideoView = [NSView alloc];
ZoomSDKActiveVideoElement* activeVideoElement = [[ZoomSDKActiveVideoElement alloc] initWithFrame:yourVideoView.frame];

// To create the video element for local user's preview video
NSView *yourVideoView = [NSView alloc];
ZoomSDKPreViewVideoElement* previewVideoElement = [[ZoomSDKPreViewVideoElement alloc] initWithFrame:yourVideoView.frame];
```

## Subscribe to video streams

Each of the `ZoomSDKVideoElement` instance created by the SDK is managed by the `ZoomSDKVideoContainer`. Use these to manage the lifecycle of the video subscription rendered on each video view.

To subscribe to a single attendee's video, you must provide the `userId` of the user whose video is being subscribed to. Access this in `ZoomSDKUserInfo.userID`.

Learn how to retrieve a `userID` on [Access in-meeting user info](/docs/meeting-sdk/android/add-features/in-meeting-user-info/).

```swift
videoContainer.createVideoElement(&videoElement)

// To subscribe a participant view
yourVideoView.addSubview(normalVideoElement.getVideoView())
normalVideoElement.userid = 123456789 // userID of the participant you will like to subscribe to
normalVideoElement.subscribeVideo(true) // or false

// To subscribe to the active speaker view
yourVideoView.addSubview(activeVideoElement.getVideoView())
activeVideoElement.startActiveView(true) // or false

// To subscribe to the local user preview view
yourVideoView.addSubview(previewVideoElement.getVideoView())
previewVideoElement.startPreview(true) // or false
```

```objectivec
// To subscribe a participant view
[videoContainer createVideoElement:&normalVideoElement];
[yourVideoView addSubview:[normalVideoElement getVideoView]];66
normalVideoElement.userid = 123456789 // userID of the participant you will like to subscribe to
[normalVideoElement subscribeVideo:YES]; // or NO

// To subscribe to the active speaker view
[videoContainer createVideoElement:&activeVideoElement];
[yourVideoView addSubview:[activeVideoElement getVideoView]];
[activeVideoElement startActiveView:YES]; // or NO

// To subscribe to the local user preview view
[videoContainer createVideoElement:&previewVideoElement];
[yourVideoView addSubview:[previewVideoElement getVideoView]];
[previewVideoElement startPreview:YES]; // or NO
```

## Manage existing video streams

To resize or set resolution to any of the video element, use the `resize` or `setResolution` method respectively.

```swift
videoElement?.resize(yourNewVideoView.frame)
videoElement?.setResolution(ZoomSDKVideoRenderResolution_360p) // Check out ZoomSDKVideoRenderResolution for all resolution available.
```

```objectivec
[normalVideoElement resize:yourVideoView.frame];
[normalVideoElement setResolution:ZoomSDKVideoRenderResolution_360p];
```

Finally, when a video unit is no longer being used, end the subscription with the `cleanVideoElement` method and remove the video view from its superview.

```swift
videoContainer.clean(normalVideoElement)
normalVideoElement.getVideoView().removeFromSuperview()
```

```objectivec
[videoContainer cleanVideoElement:normalVideoElement];
[[normalVideoElement getVideoView] removeFromSuperview];
```

---
