0

I am trying Flutter video_player with chewie. I have tried both examples provided in:

Both work fine. Yet, even when the user does not tap on the screen, the video URL is immediately fetched and downloaded.

How can I postpone the video download until the user’s action?

Miguel Gamboa
  • 8,855
  • 7
  • 47
  • 94

1 Answers1

1

Modifiying the example from the chewie package and putting it inside of a StatefulWidget, we get:

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';

class ExampleWidget extends StatefulWidget {
  const ExampleWidget({super.key});

  @override
  State<ExampleWidget> createState() => _ExampleWidgetState();
}

final VideoPlayerController videoPlayerController = VideoPlayerController.networkUrl(
    Uri.parse('https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4'));

class _ExampleWidgetState extends State<ExampleWidget> {
  late final ChewieController chewieController;
  bool _initialized = false;

  @override
  void initState() {
    chewieController = ChewieController(
        videoPlayerController: videoPlayerController, autoPlay: false, looping: true, autoInitialize: false);
  }

  @override
  void dispose() {
    videoPlayerController.dispose();
    chewieController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Expanded(
          child: Chewie(controller: chewieController),
        ),
        ElevatedButton(
          onPressed: () async {
            if (!_initialized) {
              await videoPlayerController.initialize();
            }
            _initialized = true;
            await chewieController.play();
          },
          child: const Text("Play"),
        ),
      ],
    );
  }
}

void main() => runApp(MaterialApp(
    home: Scaffold(
        backgroundColor: Colors.green,
        appBar: AppBar(),
        body: Builder(builder: (BuildContext context) => _build(context)))));

Widget _build(BuildContext context) {
  return const ExampleWidget();
}

By setting the autoPlay from the ChewieController to false, the video will not automatically play and by using the chewieController.play(), you can then start the video on pressing a button.

To also prevent the controller from preloading the video, only initialize the videoPlayerController in the callback method once instead of inside of the initState method.

This will load the video the first time the Play button is pressed (But remember that in this example clicking inside of the video itself would show the error symbol). Instead you could also display some kind of loading Widget instead while the initialized bool is false and only show the Video Player otherwise. Or set the param showControlsto false inside of the ChewieController.

Niko
  • 550
  • 1
  • 6
  • The problem is not with auto play. The problem is with pre downloading. – Miguel Gamboa Jul 10 '23 at 14:33
  • uhm, i'm sorry, i don't know how i misread that. one minute, i'll adjust my answer. – Niko Jul 10 '23 at 14:42
  • updated my answer now to also include pre downloading – Niko Jul 10 '23 at 14:55
  • The key insight is in the `autoInitialize`. It solves the problem. Also your sample is much clear than former example from chewie repo. I felt awkward with those void functions initialisers with side effects on former example. I like that you prefer `final` fields and avoid `Nullable` where is possible.Thanks – Miguel Gamboa Jul 10 '23 at 15:32
  • BTW now that we delay initialisation. Is there any way of presenting a thumbnail from an Image? – Miguel Gamboa Jul 10 '23 at 15:38
  • No Problem. Just one more thing: the `autoInitialize` would only automatically call the `videoPlayerController.initialize`, but it is also false by default. I only included it for clarity. And you could also use the bool `videoPlayerController.value.isInitialized` instead of the separate `_initialized` bool inside of the state. – Niko Jul 10 '23 at 16:20
  • As for a custom thumbnail image, you could display a stack with an Image widget that covers everything depending on the initialized bool. – Niko Jul 10 '23 at 16:21