Custom Player View

Purpose

The custom player view encapsulates the video display surface, subtitle rendering, and user interaction controls into a single reusable component. It addresses the need for a flexible, adaptable media playback UI that integrates tightly with ExoPlayer, supporting a consistent playback experience across different devices including TVs. This view simplifies the management of video surface types, subtitle styling, and control overlays that are essential for rich media playback but are not covered in the generic parent topic of media playback and UI controls.

Functionality

Key Workflows and Methods

Integration with Parent Topic and Other Subtopics

This custom player view complements the broader media playback and UI controls by acting as the unified container that hosts video output, subtitles, and user interaction elements. While the parent topic covers general playback and control logic, this view concretely implements the display layer and visual integration:

This subtopic introduces a reusable, self-contained view component that encapsulates multiple playback UI concerns, providing a consistent foundation for building rich media players across the app.


Code Snippets Illustrating Key Interactions

Attaching the Player and Setting Surfaces

public void setPlayer(SimpleExoPlayer player, @NonNull PlaybackActionCallback callback) {
    if (this.player != null) {
        this.player.removeListener(componentListener);
        this.player.clearTextOutput(componentListener);
        this.player.clearVideoListener(componentListener);
        if (surfaceView instanceof TextureView) {
            this.player.clearVideoTextureView((TextureView) surfaceView);
        } else if (surfaceView instanceof SurfaceView) {
            this.player.clearVideoSurfaceView((SurfaceView) surfaceView);
        }
    }
    this.player = player;

    if (userController != null) {
        userController.setPlayer(player, callback, this);
    }

    if (player != null) {
        if (surfaceView instanceof TextureView) {
            player.setVideoTextureView((TextureView) surfaceView);
        } else if (surfaceView instanceof SurfaceView) {
            player.setVideoSurfaceView((SurfaceView) surfaceView);
        }
        player.setVideoListener(componentListener);
        player.setTextOutput(componentListener);
        player.addListener(componentListener);
    }
}

Handling Video Size Changes to Adjust Aspect Ratio

@Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
        float pixelWidthHeightRatio) {
    if (contentFrame != null) {
        float aspectRatio = height == 0 ? 1 : (width * pixelWidthHeightRatio) / height;
        contentFrame.setAspectRatio(aspectRatio);
    }
}

Receiving Subtitle Cues for Display

@Override
public void onCues(List<Cue> cues) {
    if (subtitleView != null) {
        subtitleView.onCues(cues);
    }
}

Diagram

classDiagram
    class TubiExoPlayerView {
        -AspectRatioFrameLayout contentFrame
        -View shutterView
        -View surfaceView
        -SubtitleView subtitleView
        -View mUserInteractionView
        -SimpleExoPlayer player
        -UserController userController
        +setPlayer(player, callback)
        +addUserInteractionView(view)
        +setMediaModel(mediaModel)
        +getSubtitleView()
    }
    TubiExoPlayerView o-- "1" SimpleExoPlayer : attaches
    TubiExoPlayerView o-- "1" AspectRatioFrameLayout : manages layout
    TubiExoPlayerView o-- "1" SubtitleView : displays subtitles
    TubiExoPlayerView o-- "0..1" View : user interaction controls
    TubiExoPlayerView --> UserController : binds media state and controls

This class diagram visualizes the main structural elements of the custom player view and its relationships to ExoPlayer, subtitle rendering, user controls, and layout management. It highlights the view’s role as an integration point for video playback surfaces and interactive UI components.