One, foreword

I believe those who have done mobile video development should know that it is not very simple to realize the logic of video playing from ordinary to full screen. For example, in GSYVideoPlayer, a new Surface was used to replace the dynamic full-screen switching effect:

  • Create a brand newSurfaceAnd will be forViewAdded to the top layer of the applicationDecorView;
  • Will be newly created in full screenSurfaceAnd set it to Player Core;
  • Synchronization of twoViewPlay state parameters and rotation system interface;
  • Removed when exiting full screenDecorViewIn theSurface, toggle List ItemSurfaceGive the Player Core, sync the state.

Of course, different playback kernels may need to do some extra work, but this is all very simple with Flutter.

It’s actually quite easy to implement a full screen switch on Flutter, and I’ll explain why this is so easy to implement on Flutter later.

Two, achieve the effect

The following picture shows the full screen effect of Flutter. The key to this effect is to jump the stack! Yes, the Flutter allows seamless full-screen switching by simply hopping pages.

As shown in the following code, first add the VideoPlayer control of the official Video_Player plug-in under the normal play page, and initialize the VideoPlayerController to load and initialize the video to be played. The Hero control is also used to animate the transition to the page.

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(
        'https://res.exexm.com/cw_145225549855002')
      ..initialize().then((_) {
        // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
        setState(() {});
      });
  }
  
 Container(
   height: 200,
   margin: EdgeInsets.only(
       top: MediaQueryData.fromWindow(
               WidgetsBinding.instance.window)
           .padding
           .top),
   color: Colors.black,
   child: _controller.value.initialized
       ? Hero(
           tag: "player",
           child: AspectRatio(
             aspectRatio: _controller.value.aspectRatio,
             child: VideoPlayer(_controller),
           ),
         )
       : Container(
           alignment: Alignment.center,
           child: CircularProgressIndicator(),
         ),
 ))
Copy the code

As shown in the following code, the Hero and VideoPlayer controls are also used for transition animation and video rendering in a full-screen page.

The VideoPlayerController can be passed in via constructors or shared with an InheritedWidget as long as it’s the same controller as the normal playback interface.

Container(
     color: Colors.black,
     child: Stack(
       children: <Widget>[
         Center(
           child: Hero(
             tag: "player", child: AspectRatio( aspectRatio: widget.controller.value.aspectRatio, child: VideoPlayer(widget.controller), ), ), ), Padding( padding: EdgeInsets.only(top: 25, right: 20), child: IconButton( icon: const BackButtonIcon(), color: Colors.white, onPressed: () { Navigator.pop(context); },),)],),)Copy the code

In addition in the Flutter, only need through SystemChrome setPreferredOrientations method can quickly realize somehow screen switching applications.

Finally, as shown in the following code, the seamless switch between full-screen and non-full-screen can be realized only by invoking the page jump through the Navigator.

  Navigator.of(context)
                      .push(MaterialPageRoute(builder: (context) {
                    return VideoFullPage(_controller);
                  }));
Copy the code

Isn’t it easy to quickly switch to full screen playback using just VideoPlayer, Hero and Navigator? Why should Flutter be so easy?

Three, implementation logic

This easy implementation of dynamic full screen effects is mainly due to the video_Player plugin’s implementation on Flutter: the external Texture.

Because the controls in a Flutter are basically platform-independent, and the controls are drawn directly by the Flutter Engine, this simply states: The native platform only provides an Activity/ViewController container, which then provides a Surface for the User of the Flutter Engine to draw.

Therefore, the rendering stack of Flutter controls is independent and cannot be directly mixed with the native platform. In order to be able to insert some of the native platform functions into Flutter, Flutter provides implementation logic such as PlatformView. Texture is also provided as an external Texture support.

As shown above in The complete Description of Flutter, the interface rendering of Flutter needs to go through the process of Widget -> RenderObject -> Layer. When a TextureLayer node appears, the TextureLayer uses the Texture control in the Flutter. The content of the control is provided by the native platform, and managing the Texture is primarily identified by textureId.

For example, in the Android native, the Video_Player uses the ExoPlayer to play the kernel, so as shown in the figure above, the VideoPlayerController will communicate with the native over MethodChannel when initialized. The kernel and Surface are ready to play, and the corresponding textureId is returned to Dart.

So in the previous code, you need to use the same VideoPlayerController for both full-screen and non-full-screen pages, so that they have the same textureId.

After having the same textureId, as long as the native layer does not stop playing, the corresponding native data of textureId will always be updated. At this time, although the routing page is redirected, But the Texture control inside different VideoPlayer uses the same VideoPlayerController, that is, the same textureId, so they all display the same image.

As shown in the figure below, the process can be summarized as follows: Flutter and the native platform interact via PixelBuffer as the medium. The native layer writes data to PixelBuffer. The Flutter is drawn by the Flutter Engine after the PixelBuffer is obtained by the registered textureId.

Finally it is important to note that the implementation on the iOS page rotates, SystemChrome. SetPreferredOrientations method may be invalid, this problem is mentioned in issue # 23913 and # 13238, You may need to implement a native interface for compatibility, but of course third-party libraries such as auto_orientation or Orientation are also compatible in this respect.

In addition, iOS page rotation also determines whether the rotation configuration switch is turned on.

Resources to recommend

  • Demo: Flutter_video_full_controller
  • Making: github.com/CarGuo
  • Open Source Flutter complete project:Github.com/CarGuo/GSYG…
  • Open Source Flutter Multi-case learning project:Github.com/CarGuo/GSYF…
  • Open Source Fluttre Combat Ebook Project:Github.com/CarGuo/GSYF…
  • Open Source React Native project: github.com/CarGuo/GSYG…