DEV Community

HarmonyOS
HarmonyOS

Posted on

How to solve the problem that seamless transition cannot be implemented in cross-page video playback scenarios?

Read the original article:How to solve the problem that seamless transition cannot be implemented in cross-page video playback scenarios?

Context

In the scenario of cross-page video playback, after replacing the XComponent, the new surfaceId cannot be bound to the existing AVPlayer instance, resulting in multiple XComponents being unable to share a single AVPlayer for seamless transitions.

Description

AVPlayer integrates streaming media and local resource parsing, media resource demultiplexing, video decoding, and rendering functions, making it suitable for end-to-end playback scenarios of media resources. It can directly play video files in formats such as mp4 and mkv. AVPlayer needs to obtain and set the surfaceId attribute from the XComponent component to set the display screen. The surfaceId attribute can be set in the initialized state and can be reset in the prepared/playing/paused/completed/stopped states. When resetting, ensure that it has been set in the initialized state; otherwise, the reset will fail. After resetting, video playback will be rendered in a new window.

Solution

Seamless transitions for cross-page video playback can be achieved by dynamically switching surfaces. The specific steps are as follows:

1 - On page1, use GlobalContext to place the AVPlayer as a global singleton variable in the Map.

2 - Navigate to page2 via the router, retrieve the singleton AVPlayer from the Map, and set the SurfaceId of the Xcomponent on page2 to the AVPlayer.

import { media } from '@kit.MediaKit';

export class GlobalContext {
    private constructor() {}
    private static instance: GlobalContext;
    private _objects = new Map<string, media.AVPlayer>();

    public static getContext(): GlobalContext {
        if (!GlobalContext.instance) {
            GlobalContext.instance = new GlobalContext();
        }
        return GlobalContext.instance;
    }

    getObject(value: string): media.AVPlayer | undefined {
        return this._objects.get(value);
    }

    setObject(key: string, objectClass: media.AVPlayer): void {
        this._objects.set(key, objectClass);
    }
}

onJumpClick(): void {
    router.replaceUrl({
        url: 'pages/player' // Target URL
    }, (err) => {
        if (err) {
            console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
            return;
        }
        console.info('Invoke pushUrl succeeded.');
    })
}
Enter fullscreen mode Exit fullscreen mode

3 - Place the AVPlayer into a global map, and assign the corresponding component's surfaceId to the AVPlayer to achieve seamless playback switching.

// Place AVPlayer into a global map.
if (this.player) {
    GlobalContext.getContext().setObject('value', this.player);
}

.onLoad(() => {
    this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: this.xComponentWidth, surfaceHeight: this.xComponentHeight });
    this.surfaceID = this.mXComponentController.getXComponentSurfaceId();
    console.info('onLoad ' + this.surfaceID)

    // Retrieve the AVPlayer from the global map.
    avPlayer = GlobalContext.getContext().getObject('value');
    if (avPlayer) {
        avPlayer.surfaceId = this.surfaceID;
    }
})

Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Place AVPlayer as global singleton
  • Dynamically switch the surface

Written by Mehmet Karaaslan

Top comments (0)