Container view

The OpenTV Player SDK for FPS provides OTVContainerView, which manages the necessary view hierarchy for a standard playback scenario.

This example builds upon the process for basic playback, which you should already be familiar with from either the Integration Guide or the basic playback example code.

After the setup for basic playback, you can swap out the PlayerView and AVPlayerLayer references for an OTVContainerView. To do this, change the class type of your playerView IBOutlet to OTVContainerView (and also the class type of that view in your storyboard). You can now remove the PlayerView class from your code.

Optional extras

Applying a logo to a corner of the stream

OTVContainerView has a customOverlayView property, which is a UIView to which you can add any additional views you want to appear on top of the stream and subtitles but below the optional OTVWatermark. Examples that you may want to add include a logo or your player controls, such as a seek bar and track selection menus.

Views can be added directly to the customOverlayView with auto layout constraints, auto resizing masks or laid out manually. Alternatively views can be added to OTVContainerView in storyboard or interface builder and will automatically be moved onto the customOverlayView at runtime.

Below is an example of how to add a view to the customOverlayView and keep it aligned to the bottom right corner of the video. This code can be added to your viewDidLoad method.

    // Create a view and add it to the customOverlayView
    let label = UILabel()
    label.text = "This is a custom view added in code"
    label.textColor = .white
    label.textAlignment = .center
    label.numberOfLines = 0
    label.font = UIFont.boldSystemFont(ofSize: 26)
    label.backgroundColor =
    label.frame = CGRect(x: 0, y: 0, width: 200, height: 93.5)

    // Listen out for the AVPlayerLayer's videoRect changing.
    playerLayerObserver = containerView.playerLayer.observe(\AVPlayerLayer.videoRect) { playerLayer, _ in
      DispatchQueue.main.async {
        // Update our view to be in the bottom right of the video
        // Dispatched to the main thread as this is called on a background thread
        // and UI-related code needs to be on the main thread
        var frame = label.frame
        frame.origin.x = (playerLayer.videoRect.origin.x + playerLayer.videoRect.size.width) - frame.size.width
        frame.origin.y = (playerLayer.videoRect.origin.y + playerLayer.videoRect.size.height) - frame.size.height
        label.frame = frame

Non-native subtitle formats

If you have a stream with ID3 SMPTE-TT/PNG subtitles they will be rendered by the OTVContainerView, once selected, without any additional setup required. SRT subtitles will similarly be rendered if provided to the player via the addSubtitleWithUrl(subtitleURL: mimeType: language:) function.


If you are using Nexguard QuickMark (forensic watermarking) to secure your streams you can use the bindWatermark function of OTVContainerView to insert an OTVWatermark in the correct place of the view hierarchy.