5

How video in Flutter 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4' can be dynamically changed using default Video Player implemantation?

void initState() {
    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
    );

    // Initialize the controller and store the Future for later use.
    _initializeVideoPlayerFuture = _controller.initialize();

    // Use the controller to loop the video.
    _controller.setLooping(true);

    super.initState();
  }
gmaster
  • 174
  • 1
  • 15
kaiv
  • 163
  • 1
  • 1
  • 10

3 Answers3

8

This answer was modified for creating this video player in the web.

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

void main() => runApp(VideoPlayerApp());

class VideoPlayerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Player Demo',
      home: Container(
          padding: EdgeInsets.all(100),
          color: Colors.black,
          child: VideoPlayerScreen()),
    );
  }
}

class VideoPlayerScreen extends StatefulWidget {
  VideoPlayerScreen({Key key}) : super(key: key);

  @override
  _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  VideoPlayerController _controller;
  Future<void> _initializeVideoPlayerFuture;
  int _playBackTime;

  //The values that are passed when changing quality
  Duration newCurrentPosition;

  String defaultStream =
      'https://archive.org/download/Damas_BB_28F8B535_D_406/DaMaS.mp4';
  String stream2 = 'https://archive.org/download/cCloud_20151126/cCloud.mp4';
  String stream3 = 'https://archive.org/download/mblbhs/mblbhs.mp4';

  @override
  void initState() {
    _controller = VideoPlayerController.network(defaultStream);
    _controller.addListener(() {
      setState(() {
        _playBackTime = _controller.value.position.inSeconds;
      });
    });
    _initializeVideoPlayerFuture = _controller.initialize();
    super.initState();
  }

  @override
  void dispose() {
    _initializeVideoPlayerFuture = null;
    _controller?.pause()?.then((_) {
      _controller.dispose();
    });
    super.dispose();
  }

  Future<bool> _clearPrevious() async {
    await _controller?.pause();
    return true;
  }

  Future<void> _initializePlay(String videoPath) async {
    _controller = VideoPlayerController.network(videoPath);
    _controller.addListener(() {
      setState(() {
        _playBackTime = _controller.value.position.inSeconds;
      });
    });
    _initializeVideoPlayerFuture = _controller.initialize().then((_) {
      _controller.seekTo(newCurrentPosition);
      _controller.play();
    });
  }

  void _getValuesAndPlay(String videoPath) {
    newCurrentPosition = _controller.value.position;
    _startPlay(videoPath);
    print(newCurrentPosition.toString());
  }

  Future<void> _startPlay(String videoPath) async {
    setState(() {
      _initializeVideoPlayerFuture = null;
    });
    Future.delayed(const Duration(milliseconds: 200), () {
      _clearPrevious().then((_) {
        _initializePlay(videoPath);
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _initializeVideoPlayerFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return Stack(
            children: <Widget>[
              Center(
                child: AspectRatio(
                  aspectRatio: _controller.value.aspectRatio,
                  // Use the VideoPlayer widget to display the video.
                  child: VideoPlayer(_controller),
                ),
              ),
              Align(
                alignment: Alignment.bottomCenter,
                child: Container(
                  color: Colors.black54,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                      Container(
                        child: FloatingActionButton(
                          onPressed: () {
                            // Wrap the play or pause in a call to `setState`. This ensures the
                            // correct icon is shown.
                            setState(() {
                              // If the video is playing, pause it.
                              if (_controller.value.isPlaying) {
                                _controller.pause();
                              } else {
                                // If the video is paused, play it.
                                _controller.play();
                              }
                            });
                          },
                          // Display the correct icon depending on the state of the player.
                          child: Icon(
                            _controller.value.isPlaying
                                ? Icons.pause
                                : Icons.play_arrow,
                          ),
                        ),
                      ),
                      Container(
                        child: Text(
                          _controller.value.position
                              .toString()
                              .split('.')
                              .first
                              .padLeft(8, "0"),
                        ),
                      ),
                      Container(
                        child: FlatButton(
                          color: Colors.yellow,
                          onPressed: () {
                            _getValuesAndPlay(defaultStream);
                          },
                          child: Text('Default Stream'),
                        ),
                      ),
                      Container(
                        child: FlatButton(
                          color: Colors.red,
                          onPressed: () {
                            _getValuesAndPlay(stream2);
                          },
                          child: Text('Video Stream 2'),
                        ),
                      ),
                      Container(
                        child: FlatButton(
                          color: Colors.green,
                          onPressed: () {
                            _getValuesAndPlay(stream3);

                            print('Green Button');
                          },
                          child: Text('Video Stream 3'),
                        ),
                      )
                    ],
                  ),
                ),
              ),
            ],
          );
        } else {
          // If the VideoPlayerController is still initializing, show a
          // loading spinner.
          return Center(child: CircularProgressIndicator());
        }
      },
    );
  }
}
Rohit Singh
  • 208
  • 4
  • 8
  • Thank you very much! Your example work good and your answer helped me to solve my task. – kaiv Apr 25 '20 at 13:58
  • @Rohit must say i love the choice of the video file for the default stream. well played old boy. – Josh Dec 16 '20 at 23:10
  • why do we need a 200ms delay for this to work? is there no other way? – aytunch Feb 19 '21 at 17:22
  • @aytunch You can eliminate the delay, that was put there in order to eliminate any crashes that may occur while switching streams, mainly the dumping of the old controller stream in favor of the new stream. The code is still not perfect but it does the job. – Rohit Singh Feb 21 '21 at 13:28
  • @RohitSingh Is there any way to detect a failed loading of the stream? In case that the stream has an incorrect url for example. – Last Templar May 04 '23 at 18:38
0

Have you tried,

void initState() {
    // Initialize the controller and store the Future for later use.
    _initializeVideoPlayerFuture = _controller.initialize();
setUpVideo('https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');
    super.initState();
  }
setUpVideo(String url){
    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.network(
      url,
    );

    // Use the controller to loop the video.
    _controller.setLooping(true);

}

Now anywhere inside your code call setState,

setState(() {
   setUpVideo('another_url');
});

Ravinder Kumar
  • 7,407
  • 3
  • 28
  • 54
  • Thank you for your answer. I try this, method 'setUpVideo' is executing but video not reloading and same video continue to playing. Only after pressing 'hot restart' button video is changing... – kaiv Nov 25 '19 at 10:29
  • looks like you have to remove the previous video from the controller before passing another url, you can check [this](https://stackoverflow.com/a/55755670/5734205) – Ravinder Kumar Nov 25 '19 at 10:40
0

You have to dispose the old controller right after you assign a new controller with the new source.

  void _initController(String link) {
    _controller = VideoPlayerController.network(link)
      ..initialize().then((_) {
        setState(() {});
        _play();
        seekTo(int.parse(widget.playlist.elements[currentClipIndex].Bal));
        seeking = false;
      });
  }

  Future<void> _startVideoPlayer(String link) async {
    if (_controller == null) {
      // If there was no controller, just create a new one
      _initController(link);
    } else {
      // If there was a controller, we need to dispose of the old one first
      final oldController = _controller;

      WidgetsBinding.instance.addPostFrameCallback((_) async {
        await oldController.dispose();

        // Initing new controller
        _initController(link);
      });

      setState(() {
        _controller = null;
      });

    }
  }
janosdupai
  • 519
  • 1
  • 5
  • 16