1# Taking Over the Media Playback on Web Pages
2
3The **Web** component provides the capability for applications to take over web media player, so that applications can better enhance web media playback capabilities (for example, image quality).
4
5## When to Use
6
7There are unsatisfactory scenarios when media is played on a web page, such as unclear video quality, overly simplistic and feature-lacking web player interface, or even videos that cannot be played. 
8
9In this case, if you want to improve the web media playback experience by taking over web media playback with your own or third-party players, you can utilize this functionality.
10
11## Implementation Principle
12
13### Framework for the ArkWeb Kernel to Play Media
14
15When this functionality is disabled, the playback architecture of the ArkWeb kernel is as follows:
16
17  ![arkweb media pipeline](figures/arkweb_media_pipeline.png)
18
19  > **NOTE**
20  > - In the preceding figure, step 1 indicates that the ArkWeb kernel creates a **WebMdiaPlayer** to play media resources on web pages.
21  > - Step 2 indicates that the **WebMdiaPlayer** uses the system decoder to render media data.
22
23When this functionality is enabled, the playback architecture of the ArkWeb kernel is as follows:
24
25  ![arkweb native media player](figures/arkweb_native_media_player.png)
26
27  > **NOTE**
28  > - In the preceding figure, step 1 indicates that the ArkWeb kernel creates a **WebMdiaPlayer** to play media resources on web pages.
29  > - Step 2 indicates that the **WebMdiaPlayer** uses the **NativeMediaPlayer** provided by the application to render media data.
30
31
32### Interactions Between the ArkWeb Kernel and Application
33
34  ![interactions between arkweb and native media player](figures/interactions_between_arkweb_and_native_media_player.png)
35
36  > **NOTE**
37  > - For details about step 1 in the preceding figure, see [Enabling Web Media Playback Takeover](#enabling-web-media-playback-takeover).
38  > - For details about step 2, see [Creating a Native Media Player](#creating-a-native-media-player).
39  > - For details about step 3, see [Drawing Native Media Player Components](#drawing-native-media-player-components).
40  > - For details about step 4, see [Executing Playback Control Commands Sent by ArkWeb Kernel to the Native Media Player](#executing-playback-control-commands-sent-by-arkweb-kernel-to-the-native-media-player).
41  > - For details about step 5, see [Notifying the State Information of Native Media Player to the ArkWeb Kernel](#notifying-the-state-information-of-native-media-player-to-the-arkweb-kernel).
42
43## How to Develop
44
45### Enabling Web Media Playback Takeover
46
47To take over web media playback, you need to enable this functionality 
48
49using [enableNativeMediaPlayer](../reference/apis-arkweb/ts-basic-components-web.md#enablenativemediaplayer12).
50
51  ```ts
52  // xxx.ets
53  import { webview } from '@kit.ArkWeb';
54
55  @Entry
56  @Component
57  struct WebComponent {
58    controller: webview.WebviewController = new webview.WebviewController();
59
60    build() {
61      Column() {
62        Web({ src: 'www.example.com', controller: this.controller })
63          .enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
64      }
65    }
66  }
67  ```
68
69For details about the API and parameters, see [enableNativeMediaPlayer](../reference/apis-arkweb/ts-basic-components-web.md#enablenativemediaplayer12).
70
71### Creating a Native Media Player
72
73Once this functionality is enabled, the ArkWeb kernel triggers the callback function registered by [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12) each time a media file needs to be played on a web page.
74
75You need to register a callback function for creating a native media player by invoking **onCreateNativeMediaPlayer**.
76
77The callback function determines whether to create a native media player to take over the web page media resources based on the media information.
78
79  * If the application does not take over the web page media resource, **null** is returned in the callback function.
80  * If the application takes over the web page media resource, a native media player instance is returned in the callback function.
81
82The native media player needs to implement the [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12) API so that the ArkWeb kernel can control the playback on the native media player.
83
84  ```ts
85  // xxx.ets
86  import { webview } from '@kit.ArkWeb';
87
88  // Implement the webview.NativeMediaPlayerBridge API.
89  // The ArkWeb kernel calls the APIs to control playback on NativeMediaPlayer.
90  class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge {
91    // ...Implement the APIs in NativeMediaPlayerBridge...
92    constructor(handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {}
93    updateRect(x: number, y: number, width: number, height: number) {}
94    play() {}
95    pause() {}
96    seek(targetTime: number) {}
97    release() {}
98    setVolume(volume: number) {}
99    setMuted(muted: boolean) {}
100    setPlaybackRate(playbackRate: number) {}
101    enterFullscreen() {}
102    exitFullscreen() {}
103  }
104
105  @Entry
106  @Component
107  struct WebComponent {
108    controller: webview.WebviewController = new webview.WebviewController();
109
110    build() {
111      Column() {
112        Web({ src: 'www.example.com', controller: this.controller })
113          .enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
114          .onPageBegin((event) => {
115            this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
116              // Determine whether to take over the media.
117              if (!shouldHandle(mediaInfo)) {
118                // The native media player does not take over the media.
119                // Return null. The ArkWeb kernel will play the media with the web media player.
120                return null;
121              }
122              // Take over the web media.
123              // Return a native media player instance to the ArkWeb kernel.
124              let nativePlayer: webview.NativeMediaPlayerBridge = new NativeMediaPlayerImpl(handler, mediaInfo);
125              return nativePlayer;
126            });
127          })
128      }
129    }
130  }
131
132  // stub
133  function shouldHandle(mediaInfo: webview.MediaInfo) {
134    return true;
135  }
136  ```
137
138For details about the APIs and parameters, see [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12).
139
140### Drawing Native Media Player Components
141
142When the application takes over the media of the web page, you need to draw the native media player components and video images on the surface provided by the ArkWeb kernel.
143
144Then the ArkWeb kernel combines the surface with the web page and displays the web page on the screen.
145
146This process is the same as that of [Rendering and Drawing XComponent+AVPlayer and Button Components at the Same Layer](web-same-layer.md#)
147
148
1491. Save the **UIContext** when the application is started, which will be used in the subsequent rendering and drawing at the same layer.
150
151   ```ts
152   // xxxAbility.ets
153
154   import { UIAbility } from '@kit.AbilityKit';
155   import { window } from '@kit.ArkUI';
156
157   export default class EntryAbility extends UIAbility {
158     onWindowStageCreate(windowStage: window.WindowStage): void {
159       windowStage.loadContent('pages/Index', (err, data) => {
160         if (err.code) {
161           return;
162         }
163         // Save the UIContext, which will be used in subsequent rendering and drawing at the same layer.
164         AppStorage.setOrCreate<UIContext>("UIContext", windowStage.getMainWindowSync().getUIContext());
165       });
166     }
167
168     // ...Other APIs that need to be overridden...
169   }
170   ```
171
1722. Use the surface created by the ArkWeb kernel is for rendering and drawing at the same layer.
173
174   ```ts
175   // xxx.ets
176   import { webview } from '@kit.ArkWeb';
177   import { BuilderNode, FrameNode, NodeController, NodeRenderType } from '@kit.ArkUI';
178
179   interface ComponentParams {}
180
181   class MyNodeController extends NodeController {
182     private rootNode: BuilderNode<[ComponentParams]> | undefined;
183
184     constructor(surfaceId: string, renderType: NodeRenderType) {
185       super();
186
187       // Obtain the saved UIContext.
188       let uiContext = AppStorage.get<UIContext>("UIContext");
189       this.rootNode = new BuilderNode(uiContext as UIContext, { surfaceId: surfaceId, type: renderType });
190     }
191
192     makeNode(uiContext: UIContext): FrameNode | null {
193       if (this.rootNode) {
194         return this.rootNode.getFrameNode() as FrameNode;
195       }
196       return null;
197     }
198
199     build() {
200       // Construct the native media player component.
201     }
202   }
203
204   @Entry
205   @Component
206   struct WebComponent {
207     node_controller?: MyNodeController;
208     controller: webview.WebviewController = new webview.WebviewController();
209     @State show_native_media_player: boolean = false;
210
211     build() {
212       Column() {
213         Stack({ alignContent: Alignment.TopStart }) {
214           if (this.show_native_media_player) {
215             NodeContainer(this.node_controller)
216               .width(300)
217               .height(150)
218               .backgroundColor(Color.Transparent)
219               .border({ width: 2, color: Color.Orange })
220           }
221           Web({ src: 'www.example.com', controller: this.controller })
222             .enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
223             .onPageBegin((event) => {
224               this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo:    webview.MediaInfo) => {
225                 // Take over the web media.
226
227                 // Use the surface provided by the rendering at the same layer to construct a native media player component.
228                 this.node_controller = new MyNodeController(mediaInfo..surfaceInfo.id, NodeRenderType.  RENDER_TYPE_TEXTURE);
229                 this.node_controller.build();
230
231                 // Show the native media player component.
232                 this.show_native_media_player = true;
233
234                 // Return a native media player instance to the ArkWeb kernel.
235                 return null;
236               });
237             })
238         }
239       }
240     }
241   }
242   ```
243
244For details about how to dynamically create components and draw them on the surface, see [Rendering and Drawing XComponent+AVPlayer and Button Components at the Same Layer](web-same-layer.md#).
245
246### Executing Playback Control Commands Sent by ArkWeb Kernel to the Native Media Player
247
248To facilitate the control over native media player by the ArkWeb kernel, you need to implement the [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12) API on the native media player and perform operations on the native media player based on the functionality of each API.
249
250  ```ts
251  // xxx.ets
252  import { webview } from '@kit.ArkWeb';
253
254  class ActualNativeMediaPlayerListener {
255    constructor(handler: webview.NativeMediaPlayerHandler) {}
256  }
257
258  class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge {
259    constructor(handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {
260      // 1. Create a listener for the native media player.
261      let listener: ActualNativeMediaPlayerListener = new ActualNativeMediaPlayerListener(handler);
262      // 2. Create a native media player.
263      // 3. Listen for the local player.
264      // ...
265    }
266
267    updateRect(x: number, y: number, width: number, height: number) {
268      // The position and size of the <video> tag are changed.
269      // Make changes based on the information change.
270    }
271
272    play() {
273      // Starts the native media player for playback.
274    }
275
276    pause() {
277      // Pause the playback.
278    }
279
280    seek(targetTime: number) {
281      // The native media player seeks to the target playback time.
282    }
283
284    release() {
285      // Destroy the native media player.
286    }
287
288    setVolume(volume: number) {
289      // The ArkWeb kernel adjusts the volume of the native media player.
290      // Set the volume of the native media player.
291    }
292
293    setMuted(muted: boolean) {
294      // Mute or unmute the native media player.
295    }
296
297    setPlaybackRate(playbackRate: number) {
298      // Set the playback rate of the native media player.
299    }
300
301    enterFullscreen() {
302      // Enter the full-screen mode.
303    }
304
305    exitFullscreen() {
306      // Exit the full-screen mode.
307    }
308  }
309  ```
310
311For details about the APIs, see [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12).
312
313### Notifying the State Information of Native Media Player to the ArkWeb Kernel
314
315The ArkWeb kernel requires the state information of the local player to update to the web page, such as the width and height of the video, playback time, and cache time. You need to notify the ArkWeb kernel of the state information of the native media player.
316
317Through the [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12) API, the Ark Web kernel passes a [NativeMediaPlayerHandler](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerhandler12) object to the application.
318
319You need to use this object to notify the ArkWeb kernel of the latest state information of the native media player.
320
321  ```ts
322  // xxx.ets
323  import { webview } from '@kit.ArkWeb';
324
325  class ActualNativeMediaPlayerListener {
326    handler: webview.NativeMediaPlayerHandler;
327
328    constructor(handler: webview.NativeMediaPlayerHandler) {
329      this.handler = handler;
330    }
331
332    onPlaying() {
333      // The native media player starts playback.
334      this.handler.handleStatusChanged(webview.PlaybackStatus.PLAYING);
335    }
336    onPaused() {
337      // The native media player pauses the playback.
338      this.handler.handleStatusChanged(webview.PlaybackStatus.PAUSED);
339    }
340    onSeeking() {
341      // The native media player starts to seek the target time point.
342      this.handler.handleSeeking();
343    }
344    onSeekDone() {
345      // The target time point is sought.
346      this.handler.handleSeekFinished();
347    }
348    onEnded() {
349      // The playback on the native media player is ended.
350      this.handler.handleEnded();
351    }
352    onVolumeChanged() {
353      // Obtain the volume of the native media player.
354      let volume: number = getVolume();
355      this.handler.handleVolumeChanged(volume);
356    }
357    onCurrentPlayingTimeUpdate() {
358      // Update the playback time.
359      let currentTime: number = getCurrentPlayingTime();
360      // Convert the time unit to second.
361      let currentTimeInSeconds = convertToSeconds(currentTime);
362      this.handler.handleTimeUpdate(currentTimeInSeconds);
363    }
364    onBufferedChanged() {
365      // The buffer is changed.
366      // Obtain the cache duration of the native media player.
367      let bufferedEndTime: number = getCurrentBufferedTime();
368      // Convert the time unit to second.
369      let bufferedEndTimeInSeconds = convertToSeconds(bufferedEndTime);
370      this.handler.handleBufferedEndTimeChanged(bufferedEndTimeInSeconds);
371
372      // Check the cache state.
373      // If the cache state changes, notify the ArkWeb kernel.
374      let lastReadyState: webview.ReadyState = getLastReadyState();
375      let currentReadyState: webview.ReadyState = getCurrentReadyState();
376      if (lastReadyState != currentReadyState) {
377        this.handler.handleReadyStateChanged(currentReadyState);
378      }
379    }
380    onEnterFullscreen() {
381      // The native media player enters the full-screen mode.
382      let isFullscreen: boolean = true;
383      this.handler.handleFullscreenChanged(isFullscreen);
384    }
385    onExitFullscreen() {
386      // The native media player exits the full-screen mode.
387      let isFullscreen: boolean = false;
388      this.handler.handleFullscreenChanged(isFullscreen);
389    }
390    onUpdateVideoSize(width: number, height: number) {
391      // Notify the ArkWeb kernel when the local player parses the video width and height.
392      this.handler.handleVideoSizeChanged(width, height);
393    }
394
395    // ...Listen for other state of the native media player.
396  }
397  @Entry
398  @Component
399  struct WebComponent {
400    controller: webview.WebviewController = new webview.WebviewController();
401    @State show_native_media_player: boolean = false;
402
403    build() {
404      Column() {
405        Web({ src: 'www.example.com', controller: this.controller })
406          .enableNativeMediaPlayer({enable: true, shouldOverlay: false})
407          .onPageBegin((event) => {
408            this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
409              // Take over the web media.
410
411              // Create a native media player instance.
412              // let nativePlayer: NativeMediaPlayerImpl = new NativeMediaPlayerImpl(handler, mediaInfo);
413
414              // Create a listener for the native media player state. 
415              let nativeMediaPlayerListener: ActualNativeMediaPlayerListener = new ActualNativeMediaPlayerListener(handler);
416              // Listen for the native media player state.
417              // nativePlayer.setListener(nativeMediaPlayerListener);
418
419              // Return the native media player instance to the ArkWeb kernel.
420              return null;
421            });
422          })
423      }
424    }
425  }
426
427  // stub
428  function getVolume() {
429    return 1;
430  }
431  function getCurrentPlayingTime() {
432    return 1;
433  }
434  function getCurrentBufferedTime() {
435    return 1;
436  }
437  function convertToSeconds(input: number) {
438    return input;
439  }
440  function getLastReadyState() {
441    return webview.ReadyState.HAVE_NOTHING;
442  }
443  function getCurrentReadyState() {
444    return webview.ReadyState.HAVE_NOTHING;
445  }
446  ```
447
448
449For details about the APIs, see [NativeMediaPlayerHandler](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerhandler12).
450
451
452## Sample Code
453
454- Add the following permissions to **module.json5** before using it:
455
456  ```ts
457  "ohos.permission.INTERNET"
458  ```
459
460- Example of saving **UIContext** during application startup on the application side:
461
462  ```ts
463  // xxxAbility.ets
464
465  import { UIAbility } from '@kit.AbilityKit';
466  import { window } from '@kit.ArkUI';
467
468  export default class EntryAbility extends UIAbility {
469    onWindowStageCreate(windowStage: window.WindowStage): void {
470      windowStage.loadContent('pages/Index', (err, data) => {
471        if (err.code) {
472          return;
473        }
474        // Save the UIContext, which will be used in subsequent rendering and drawing at the same layer.
475        AppStorage.setOrCreate<UIContext>("UIContext", windowStage.getMainWindowSync().getUIContext());
476      });
477    }
478
479    // ...Other APIs that need to be overridden...
480  }
481  ```
482
483- Example of web media playback takeover:
484
485  ```ts
486  import { webview } from '@kit.ArkWeb';
487  import { BuilderNode, FrameNode, NodeController, NodeRenderType, UIContext } from '@kit.ArkUI';
488  import { AVPlayerDemo, AVPlayerListener } from './PlayerDemo';
489
490  // Implement the webview.NativeMediaPlayerBridge API.
491  // The ArkWeb kernel calls the APIs to control playback on NativeMediaPlayer.
492  class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge {
493    private surfaceId: string;
494    mediaSource: string;
495    private mediaHandler: webview.NativeMediaPlayerHandler;
496    web: WebComponent;
497    nativePlayer?: AVPlayerDemo;
498
499    constructor(web: WebComponent, handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {
500      console.log('NativeMediaPlayerImpl.constructor, surface_id[' + mediaInfo.surfaceInfo.id + ']');
501      this.web = web;
502      this.mediaHandler = handler;
503      this.surfaceId = mediaInfo.surfaceInfo.id;
504      this.mediaSource = mediaInfo.mediaSrcList[0].source;
505
506      // Use the rendering function at the same layer to draw the video and its playback control components to the web page.
507      this.web.node_controller = new MyNodeController(
508          this.web, this.surfaceId, this.mediaHandler, this, NodeRenderType.RENDER_TYPE_TEXTURE)
509      this.web.node_controller.build()
510      this.web.show_native_media_player = true;
511
512      console.log('NativeMediaPlayerImpl.mediaSource : ' + this.mediaSource);
513    }
514
515    setNativePlayer(nativePlayer: AVPlayerDemo) {
516      this.nativePlayer = nativePlayer;
517    }
518
519    updateRect(x: number, y: number, width: number, height: number): void {
520      this.web.node_width = width
521      this.web.node_height = height
522    }
523
524    play() {
525      this.nativePlayer?.play();
526    }
527    pause() {
528      this.nativePlayer?.pause();
529    }
530    seek(targetTime: number) {
531    }
532    setVolume(volume: number) {
533    }
534    setMuted(muted: boolean) {
535    }
536    setPlaybackRate(playbackRate: number) {
537    }
538    release() {
539      this.nativePlayer?.release();
540      this.web.show_native_media_player = false;
541    }
542    enterFullscreen() {
543    }
544    exitFullscreen() {
545    }
546  }
547
548  // Listen for the NativeMediaPlayer state and report the state to the ArkWeb kernel using webview.NativeMediaPlayerHandler.
549  class AVPlayerListenerImpl implements AVPlayerListener {
550    handler: webview.NativeMediaPlayerHandler;
551    component: NativePlayerComponent;
552
553    constructor(handler: webview.NativeMediaPlayerHandler, component: NativePlayerComponent) {
554      this.handler = handler;
555      this.component = component;
556    }
557    onPlaying() {
558      this.handler.handleStatusChanged(webview.PlaybackStatus.PLAYING);
559    }
560    onPaused() {
561      this.handler.handleStatusChanged(webview.PlaybackStatus.PAUSED);
562    }
563    onDurationChanged(duration: number) {
564      this.handler.handleDurationChanged(duration);
565    }
566    onBufferedTimeChanged(buffered: number) {
567      this.handler.handleBufferedEndTimeChanged(buffered);
568    }
569    onTimeUpdate(time: number) {
570      this.handler.handleTimeUpdate(time);
571    }
572    onEnded() {
573      this.handler.handleEnded();
574    }
575    onError() {
576      this.handler.handleError(1, "Oops!");
577    }
578    onVideoSizeChanged(width: number, height: number) {
579      this.handler.handleVideoSizeChanged(width, height);
580      this.component.onSizeChanged(width, height);
581    }
582  }
583
584  interface Params {
585    text: string
586    text2: string
587    web_tab: WebComponent
588    handler: webview.NativeMediaPlayerHandler
589    player: NativeMediaPlayerImpl
590  }
591
592  // Define the player components.
593  @Component
594  struct NativePlayerComponent {
595    params?: Params
596    @State bkColor: Color = Color.Red
597    mXComponentController: XComponentController = new XComponentController();
598    @State player_changed: boolean = false;
599
600    videoController: VideoController = new VideoController();
601    player?: AVPlayerDemo
602    offset_x: number = 0
603    offset_y: number = 0
604    @State video_width_percent: number = 100;
605    @State video_height_percent: number = 100;
606    view_width: number = 0;
607    view_height: number = 0;
608    video_width: number = 0;
609    video_height: number = 0;
610
611    fullscreen: boolean = false;
612
613    onSizeChanged(width: number, height: number) {
614      this.video_width = width;
615      this.video_height = height;
616      let scale: number = this.view_width / width;
617      let scaled_video_height: number = scale * height;
618      this.video_height_percent = scaled_video_height / this.view_height * 100;
619    }
620
621    build() {
622      Column() {
623        Stack() {
624          XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController })
625            .width(this.video_width_percent + '%')
626            .height(this.video_height_percent + '%')
627            .border({ width: 1, color: Color.Red })
628            .onLoad(()=>{
629              if (!this.params) {
630                console.log('this.params is null');
631                return;
632              }
633              this.player = new AVPlayerDemo();
634              this.params.player?.setNativePlayer(this.player);
635              this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId());
636              this.player_changed = !this.player_changed;
637
638              this.player.avPlayerLiveDemo(
639                this.params.player.mediaSource,
640                new AVPlayerListenerImpl(this.params.handler, this));
641            })
642          Column() {
643            Row() {
644              Button(this.params?.text)
645                .height(50)
646                .border({ width: 2, color: Color.Red })
647                .backgroundColor(this.bkColor)
648                .onClick(()=>{
649                  console.log('[BrowserShell] Button[' + this.params?.text + '] is clicked');
650                  this.player?.play();
651                })
652                .onTouch((event: TouchEvent) => {
653                  event.stopPropagation();
654                })
655              Button(this.params?.text2)
656                .height(50)
657                .border({ width: 2, color: Color.Red })
658                .onClick(()=>{
659                  console.log('[BrowserShell] Button[' + this.params?.text2 + '] is clicked');
660                  this.player?.pause();
661                })
662                .onTouch((event: TouchEvent) => {
663                  event.stopPropagation();
664                })
665            }
666            .width('100%')
667            .justifyContent(FlexAlign.SpaceEvenly)
668          }
669        }
670      }
671      .width('100%')
672      .height('100%')
673      .onTouchIntercept((event : TouchEvent) => {
674        return HitTestMode.None
675      })
676      .onAreaChange((oldValue: Area, newValue: Area) => {
677        this.view_width = new Number(newValue.width).valueOf()
678        this.view_height = new Number(newValue.height).valueOf()
679
680        this.onSizeChanged(this.video_width, this.video_height);
681      })
682    }
683  }
684
685  @Builder
686  function NativePlayerComponentBuilder(params: Params) {
687    NativePlayerComponent({ params: params })
688      .backgroundColor(Color.Green)
689      .border({ width: 1, color: Color.Brown })
690      .width('100%')
691      .height('100%')
692  }
693
694  // Use NodeController to dynamically create a player component and draw the component content on the surface specified by surfaceId.
695  class MyNodeController extends NodeController {
696    private rootNode: BuilderNode<[Params]> | undefined;
697    private isRemove = false;
698    web_tab: WebComponent
699    listener: webview.NativeMediaPlayerHandler
700    player: NativeMediaPlayerImpl
701
702    constructor(web_tab: WebComponent, surfaceId: string,  listener: webview.NativeMediaPlayerHandler, player: NativeMediaPlayerImpl, renderType: NodeRenderType) {
703      super()
704      this.web_tab = web_tab;
705      this.listener = listener;
706      this.player = player;
707      let uiContext = AppStorage.get<UIContext>("UIContext");
708      this.rootNode = new BuilderNode(uiContext as UIContext, { surfaceId: surfaceId, type: renderType });
709    }
710
711    makeNode(uiContext: UIContext): FrameNode | null {
712      if (this.rootNode) {
713        return this.rootNode.getFrameNode() as FrameNode;
714      }
715      return null;
716    }
717
718    build() {
719      if (this.rootNode) {
720        this.rootNode.build(wrapBuilder(NativePlayerComponentBuilder),
721          { "text": "play", "text2": "pause", web_tab: this.web_tab, handler: this.listener, player: this.player})
722      }
723    }
724  }
725
726  interface PageBeginParam {
727    url: string
728  }
729
730  @Entry
731  @Component
732  struct WebComponent {
733    controller: WebviewController = new webview.WebviewController()
734    nativePlayer? : webview.NativeMediaPlayerBridge
735    page_url: Resource = $rawfile('main.html')
736    node_controller?: MyNodeController
737    @State show_native_media_player: boolean = false;
738    @State node_width : number = 300;
739    @State node_height : number = 150;
740    area?: Area
741
742    build() {
743      Column() {
744        Stack({alignContent: Alignment.TopStart}) {
745          if (this.show_native_media_player) {
746            NodeContainer(this.node_controller)
747              .width(this.node_width + 'px')
748              .height(this.node_height + 'px')
749              .backgroundColor(Color.Transparent)
750              .border({ width: 2, color: Color.Orange })
751          }
752          Web({ src: this.page_url, controller: this.controller })
753            .enableNativeMediaPlayer({ enable: true, shouldOverlay: true })
754            .onPageBegin((event: PageBeginParam) => {
755              this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
756                console.error('onCreateNativeMediaPlayer(' + JSON.stringify(mediaInfo) + ')');
757                this.nativePlayer = new NativeMediaPlayerImpl(this, handler, mediaInfo);
758                return this.nativePlayer;
759              });
760            })
761            .width('100%')
762            .height('100%')
763            .onAreaChange((oldValue: Area, newValue: Area) => {
764              oldValue;
765              this.area = newValue;
766            })
767        }
768      }
769    }
770  }
771  ```
772
773- Example of using video playback on the application side:
774
775  ```ts
776  import { media } from '@kit.MediaKit';
777  import { common } from '@kit.AbilityKit';
778  import { BusinessError } from '@kit.BasicServicesKit';
779
780  export interface AVPlayerListener {
781    onPlaying() : void
782    onPaused() : void
783    onDurationChanged(duration: number) : void
784    onBufferedTimeChanged(buffered: number) : void
785    onTimeUpdate(time: number) : void
786    onEnded() : void
787    onError() : void
788    onVideoSizeChanged(width: number, height: number): void
789  }
790
791  export class AVPlayerDemo {
792    private surfaceID: string = ''; // The surfaceID parameter specifies the window used to display the video. Its value is obtained through the XComponent.
793    private isSeek: boolean = true; // Specify whether the seek operation is supported.
794    private fileSize: number = -1;
795    private fd: number = 0;
796
797    avPlayer?: media.AVPlayer;
798
799    setSurfaceID(surface_id: string) {
800      console.log('setSurfaceID : ' + surface_id)
801      this.surfaceID = surface_id;
802    }
803    // Set AVPlayer callback functions.
804    setAVPlayerCallback(avPlayer: media.AVPlayer, listener?: AVPlayerListener) {
805      // Callback function for the seek operation.
806      avPlayer.on('seekDone', (seekDoneTime: number) => {
807        console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
808      })
809      // Callback function for errors. If an error occurs during the operation on the AVPlayer, reset() is called to reset the AVPlayer.
810      avPlayer.on('error', (err: BusinessError) => {
811        console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
812        listener?.onError();
813        avPlayer.reset(); // Call reset() to reset the AVPlayer, which enters the idle state.
814      })
815      // Callback function for state changes.
816      avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
817        switch (state) {
818          case 'idle': // This state is reported upon a successful callback of reset().
819            console.info('AVPlayer state idle called.');
820            avPlayer.release(); // Call release() to release the instance.
821            break;
822          case 'initialized': // This state is reported when the AVPlayer sets the playback source.
823            console.info('AVPlayer state initialized called.');
824            avPlayer.surfaceId = this.surfaceID; // Set the window to display the video. This setting is not required when a pure audio asset is to be played.
825            avPlayer.prepare();
826            break;
827          case 'prepared': // This state is reported upon a successful callback of prepare().
828            console.info('AVPlayer state prepared called.');
829            //avPlayer.play();
830            break;
831          case 'playing': // This state is reported upon a successful callback of play().
832            console.info('AVPlayer state playing called.');
833            listener?.onPlaying();
834            break;
835          case 'paused': // This state is reported upon a successful callback of pause().
836            console.info('AVPlayer state paused called.');
837            listener?.onPaused();
838            break;
839          case 'completed': // This state is reported upon the completion of the playback.
840            console.info('AVPlayer state completed called.');
841            avPlayer.stop(); // Call stop() to stop the playback.
842            //avPlayer.seek(0);
843            //avPlayer.play();
844            break;
845          case 'stopped': // This state is reported upon a successful callback of stop().
846            console.info('AVPlayer state stopped called.');
847            listener?.onEnded();
848            avPlayer.reset(); // Call reset() to reset the AVPlayer.
849            break;
850          case 'released':
851            console.info('AVPlayer state released called.');
852            break;
853          default:
854            console.info('AVPlayer state unknown called.');
855            break;
856        }
857      })
858      avPlayer.on('durationUpdate', (duration: number) => {
859        console.info('AVPlayer state durationUpdate success,new duration is :' + duration)
860        listener?.onDurationChanged(duration/1000);
861      })
862      avPlayer.on('timeUpdate', (time:number) => {
863        listener?.onTimeUpdate(time/1000);
864      })
865      avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => {
866        console.info('AVPlayer state bufferingUpdate success,and infoType value is:' + infoType + ', value is :' + value)
867        if (infoType == media.BufferingInfoType.BUFFERING_PERCENT) {
868        }
869        listener?.onBufferedTimeChanged(value);
870      })
871      avPlayer.on('videoSizeChange', (width: number, height: number) => {
872        console.info('AVPlayer state videoSizeChange success,and width is:' + width + ', height is :' + height)
873        listener?.onVideoSizeChanged(width, height);
874      })
875    }
876
877    // The following demo shows how to play live streams by setting the network address through the URL.
878    async avPlayerLiveDemo(url: string, listener?: AVPlayerListener) {
879      // Create an AVPlayer instance.
880      this.avPlayer = await media.createAVPlayer();
881      // Set a callback function for state changes.
882      this.setAVPlayerCallback(this.avPlayer, listener);
883      this.isSeek = false; // The seek operation is not supported.
884      this.avPlayer.url = url;
885    }
886
887    play() {
888      console.info('AVPlayer.play()');
889      this.avPlayer?.play()
890    }
891    pause() {
892      console.info('AVPlayer.pause()');
893      this.avPlayer?.pause()
894    }
895    release() {
896      console.info('AVPlayer.release()');
897      this.avPlayer?.release();
898    }
899    seek(time: number) {
900      console.info('AVPlayer.seek(' + time + ')');
901      this.avPlayer?.seek(time * 1000);
902    }
903  }
904  ```
905
906- Frontend page example.
907
908  ```html
909  <html>
910  <head>
911      <title>Video Hosting Test html</title>
912      <meta name="viewport" content="width=device-width">
913  </head>
914  <body>
915  <div>
916    <video src='https://media.w3.org/2010/05/sintel/trailer.mp4'></video>
917  </div>
918  </body>
919  </html>
920  ```
921