Search code examples
flutterfirebasedartfirebase-storagevideo-player

How to play video from firebase Storage using video_player flutter


I have a video_player which played a video from network(VideoPlayerController.network( https://...mp4)) and It’s working fine. But I want to take it to another step by playing a video that I get from a snapShot (StreamBuilder) as a video file(ex. 8296971978270266602.mp4) and download it by storage.ref('videos/$videoFile').getDownloadURL(); For me to get a link Url of course. Then I want to put the Url that I get from DownloadURL in the VideoPlayer so I can play the video. Please take a look at the code then you’ll understand on what I am trying to achieve.

code:

final FirebaseStorage storage = FirebaseStorage.instance;
late Future<void> initializeVideoPlayerFuture;
VideoPlayerController? _videoPlayerController;

 @override
  void initState() {
    super.initState();
    _videoPlayerController = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
    );
    initializeVideoPlayerFuture = _videoPlayerController!.initialize();
  }

  @override
  void dispose() {
    _videoPlayerController!.dispose();

    super.dispose();
  }

             //My StreamBuilder to get snapShot from FB fireStore
             StreamBuilder(
              stream: FirebaseFirestore.instance
                  .collection("groups")
                  .doc(groupId)
                  .snapshots(),
              builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {                
              var videoFile = snapshot.data?["videoFile"];

//ListView that I want to display all the video
  ListView.builder(
       itemCount: videoFile.length,
       shrinkWrap: true,
       itemBuilder: (context, index) {
       
        return FutureBuilder(
                future: initializeVideoPlayerFuture,
                builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.done) {
                    return AspectRatio(aspectRatio: _videoPlayerController!
                            .value.aspectRatio,
                       child: VideoPlayer(_videoPlayerController!
                          ),
                       );
                      } else {
                return const Center(
                              child: CircularProgressIndicator(),
                             );
                           }},
                        );

//Download the videoFile from Fb storage(Get the url and play it in the video_player)
  Future<String> downloadVideoURL(String videoFile) async {
    try {
      String downloadURL =
          await storage.ref('videos/$videoFile').getDownloadURL();
      setState(() {
        videoUrl = downloadURL;
      });
      // ignore: avoid_print
      print(downloadURL);
      return downloadURL;
    } on FirebaseException catch (e) {
      // ignore: avoid_print
      print(e);
    }
    return downloadURL(videoFile);
  }

Images:

enter image description here

enter image description here

To summary: As you can see in the code I only play a video by manually putting the Link to that video. But what I want is to put the videoUrl link that I get from downloadVideoUrl. And display all the video as a ListView. How can I do that?


Solution

  • You can make a separate widget for video player and call that widget inside your stream builder as following.

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:flutter/material.dart';
    import 'package:video_player/video_player.dart';
    
    class VideoPage extends StatefulWidget {
      const VideoPage({Key? key}) : super(key: key);
    
      @override
      State<VideoPage> createState() => _VideoPageState();
    }
    
    class _VideoPageState extends State<VideoPage> {
      @override
      Widget build(BuildContext context) {
        return StreamBuilder(
          stream: FirebaseFirestore.instance
              .collection("groups")
              .doc('groupId')
              .snapshots(),
          builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
            /// Your code to show the error or loading according to snapshot state
            var videoFile = snapshot.data?["videoFile"];
            return ListView.builder(
              itemCount: videoFile.length,
              shrinkWrap: true,
              itemBuilder: (ctx, index) {
                return VideoPlayerWidget(name: videoFile[index]);
              },
            );
          },
        );
      }
    }
    
    class VideoPlayerWidget extends StatefulWidget {
      const VideoPlayerWidget({
        Key? key,
        required this.name,
      }) : super(key: key);
    
      final String name;
    
      @override
      State<VideoPlayerWidget> createState() => _VideoPlayerWidgetState();
    }
    
      class _VideoPlayerWidgetState extends State<VideoPlayerWidget> {
      VideoPlayerController? _videoPlayerController;
      var _isLoading = true;
    late Future<void> initializeVideoPlayerFuture;
    
      @override
      void initState() {
        super.initState();
        _initPlayer();
      }
    
      void _initPlayer() async {
        final _url = await downloadVideoURL(widget.name);
        _videoPlayerController = VideoPlayerController.network(_url);
        initializeVideoPlayerFuture = _videoPlayerController!.initialize();
        _isLoading = false;
        setState(() {});
      }
    
      Future<String> downloadVideoURL(String videoFile) async {
        try {
          String downloadURL =
              await storage.ref('videos/$videoFile').getDownloadURL();
          // ignore: avoid_print
          print(downloadURL);
          return downloadURL;
        } on FirebaseException catch (e) {
          // ignore: avoid_print
          print(e);
        }
        return '';
      }
    
      @override
      Widget build(BuildContext context) {
        if(_isLoading) {
          return CircularProgressIndicator();
        }
        return FutureBuilder(
          future: initializeVideoPlayerFuture,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              return AspectRatio(
                aspectRatio: _videoPlayerController!.value.aspectRatio,
                child: VideoPlayer(_videoPlayerController!),
              );
            } else {
              return const Center(
                child: CircularProgressIndicator(),
              );
            }
          },
        );
      }
    }