Custom Plugins Access

1. Plugin Specifications

Plugins offer extensive permissions, but they can also introduce unexpected issues. To mitigate potential problems, it is essential to adhere to the following principles:

  • Ensure that the external methods are uniformly mounted on the outer player instance.

2. Player Object Model

Before developing a plugin, understanding the player object model is extremely beneficial and can significantly aid in the plugin development process:

  1. Live View
┌─renderer # The core module of the player.
│ ├─wrapper # The outermost DOM of the player. It is the parent node of the container.
│ ├─container # The mount node of the player (usually also used for plugin DOM mounting). It is the parent node of the rendering DOM.
│ ├─dom # The video rendering DOM (canvas | video).
│ └─decoder # The decoder module.
 └─renderer # The rendering manager.
 ├─decodeType # The renderer type.
 ├─decodeType # The current play time of the renderer.
 └─vm # The renderer (MSE renderer | WebGL renderer).
├─session # The play session returned by the s17 interface.
├─streamType # The stream type.
└─volume # The volume.
  1. Playback
┌─channelPlayers[] # The list of channel players (added in v1.1). It replaces mediaElements in v1.0.
│ ├─renderer # The player rendering module.
│ │ ├─wrapper # The outermost DOM of the player. It is the parent node of the container.
│ │ ├─container # The mount node of the player (usually also used for plugin DOM mounting). It is the parent node of the rendering DOM.
│ │ ├─dom # The video rendering DOM (canvas | video).
│ │ └─decoder # The decoder module.
│ ├─session # The play session returned by the s17 interface.
│ ├─channel # The channel number.
│ ├─devId # The device number.
│ ├─streamType # The stream type.
│ ├─currentTime # The current time (UTC), in seconds.
│ └─volume # The volume.
├─streamType # The stream type.
├─currentTime # The current time (UTC), in seconds.
├─volume # The volume.
├─status # The status.
└─requestParams # s17 interface request parameters.

3. Custom Plugins Creating

3.1. Introduction

Creating a plugin is straightforward and involves just two steps:

  1. Create a function that accepts a hooks parameter.
export function customPlugin(hooks) {
    // do something ...
}

Tips: The plugin itself is a method, not a constructor, so it does not have an instance.

  1. Register the plugin with the player:
player.plugin.use(customPlugin);

What a surprise! The real focus is on the main body of the plugin. Let's dive deeper into plugins with a step-by-step guide using a fullscreen plugin as an example.

3.2. Fullscreen Plugin Implementation

The plugin function accepts hooks parameters, which provides an entry point for interacting with various player lifecycle stages (hooks).

  1. Requirement analysis: The fullscreen plugin needs to extend the player with two methods—one for entering fullscreen mode and another for exiting it.

  2. Determine extension timing: These two methods need to be added early in the player's lifecycle so they can be called as soon as possible. We chose the afterPlayerInit hook from the available hooks, which allows us to intervene right after the player is initialized.

  3. Extend methods: The afterPlayerInit hook injects two parameters: player and config. Here, we only need to use player, which represents the current player instance. We can add our methods or properties directly to it:

export function fullscreen(hooks) {
    hooks.afterPlayerInit.tap('install-fullscreen', (player) => {
        player.fullscreen = function () {
            // ...
        };
        player.cancelFullscreen = function () {
            // ...
        };
    });
}

Tips: Each hook callback has specific parameters injected. For details, see hooks. Tips: The tap method is provided by tapable.

  1. Implement the Fullscreen function.
function fullscreen() {
    let canFullScreen = true;
    var mediaElement = this.renderer.container;
    if (mediaElement.RequestFullScreen) {
        mediaElement.RequestFullScreen();
    } else if (mediaElement.webkitRequestFullScreen) {
        mediaElement.webkitRequestFullScreen();
    } else if (mediaElement.mozRequestFullScreen) {
        mediaElement.mozRequestFullScreen();
    } else if (mediaElement.msRequestFullscreen) {
        mediaElement.msRequestFullscreen();
    } else {
        canFullScreen = false;
        alert("This browser doesn't supporter fullscreen");
    }
}
  1. Implement the cancelFullscreen function.
function cancelFullscreen() {
    let canFullScreen = true;
    if (document.exitFullscreen) {
        document.exitFullscreen();
    } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen();
    } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
    } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
    } else {
        canFullScreen = false;
        alert("Exit fullscreen doesn't work");
    }
}
  1. The last step is to register the plugin.
player.plugin.use(fullscreen);

And that’s it! You’ve now implemented a complete fullscreen plugin.

3.3. Magnifier Plugin Implementation

  1. Requirement analysis: We need some DOM elements and corresponding interactions to select a specific area. Additionally, we need to modify the renderer's behavior to apply the selected area to the video, zooming in on it.

  2. Determine when to add DOM and corresponding interactions: The necessary DOM elements should be added before the video is rendered, but after or during the player's initialization (whichever is reasonable). Here, we again choose the afterPlayerInit hook:

hooks.afterPlayerInit.tap('install-magnifier-dom', (player) => {
    // Install related DOM and interaction.
    player.magnifier = new Magnifier(player);
});

Tips: The tap method is provided by tapable.

Overview of the Magnifier class:

export class Magnifier { ... constructor(player) { const { canvas, renderer } = player; const container = canvas.parentNode;
 canvas.addEventListener('mousedown', (e) => { ... this.rect = new zoomRect(container, x, y); }); canvas.addEventListener('mousemove', (e) => { ... }) canvas.addEventListener('mouseup', (e) => { ... }) ... } ...}
  1. Determine when to intervene with the renderer: Since we need to modify the renderer's behavior, we must intervene during the rendering phase—either when rendering starts or after the renderer has finished initializing (whichever is reasonable). Here, we chose the afterRendererInit hook.

  2. Extend the renderer with a zoomIn Method: After the user selects an area in the video, the area’s data is passed as a parameter to the zoomIn method, which processes zooming in on the selected area:

export function magnifier(hooks) {
    hooks.afterPlayerInit.tap('install-magnifier-dom', (player) => {
        // Install related DOM and interaction.
        // Here, the player is passed as a parameter into the Magnifier, allowing it to access the zoomIn method (Renderer is a sub-property of the player.).
        player.magnifier = new Magnifier(player);
    });
    hooks.afterRendererInit.tap('install-renderer-magnifier', (renderer) => {
        // Modify the renderer's behavior to extend a zoomIn method for it.
        renderer.zoomIn = MagnifierForGlRenderer;
        // The implementation of MagnifierForGlRenderer is temporarily omitted. It requires a certain understanding of the player's WebGL.
        // If you need to customize the video rendering layer, you can consult the SDK development team for further information.
    });
}

With that, you’ve implemented a magnifier plugin. Finally, apply it to the player to activate it:

player.plugin.use(magnifier);

Tips: The magnifier plugin is quite hardcore. This explanation covers the key steps for implementing the plugin. For most business scenarios, customizations at the rendering layer are typically not necessary.