如何在flutter应用中缓存网络视频?

How to cache network videos in flutter application?

我想了解缓存视频的含义及其工作原理。

我遇到的问题是 flutter /firebase 应用程序中的高带宽。我每天有 19GB 的流量和 10-20 个视频,最多有 10 个用户。所以我无法弄清楚问题是什么。因此我联系了 firebase 支持,他们说

Looking at the graph, the high bandwidth comes from the storage bucket where the videos are stored. Even though it looks like there are few videos, your bandwidth will increase more and more if your application doesn't store the videos in cache.

Try to double check your applications and ensure that these ones download the information only once.

而且我在想 hak 正在聊天吗?以及如何去做? 这是否会解决高带宽问题?

这是我的代码的样子

class Videoplayeritem extends StatefulWidget {
  final bool mute;
  final int pickedvideo;

  final int currentPageIndex;
  final bool isPaused;
  final int pageIndex;
  final String videourl;
  final String thumbnailUrl;

  const Videoplayeritem({
    Key key,
    this.videourl,
    this.currentPageIndex,
    this.isPaused,
    this.pageIndex,
    this.thumbnailUrl,
    this.pickedvideo,
    this.mute,
  }) : super(key: key);

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

class _VideoplayeritemState extends State<Videoplayeritem> {
  VideoPlayerController videoPlayerController;
  bool initialized = false;
  bool stopvideo = false;

  @override
  void initState() {
    super.initState();
    try {
      videoPlayerController = VideoPlayerController.network(
        
        widget.videourl,
        
        videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
       
      )..initialize().then((value) {
          if (this.mounted) setState(() {});
          try {
            videoPlayerController?.play();
            videoPlayerController?.setLooping(true);
            if (widget.mute) {
              videoPlayerController?.setVolume(0);
            } else if (!widget.mute) {
              videoPlayerController?.setVolume(1);
            }
          } catch (e) {
            print('error: $e');
          }
        });
    } catch (e) {
      print('error2: $e');
    }

    print('init');
  }

  @override
  void dispose() {
    try {
      if (videoPlayerController.value.isPlaying) {
        videoPlayerController?.pause();
      }

      videoPlayerController?.setVolume(0);
      videoPlayerController?.dispose();
      videoPlayerController = null;
    } catch (e) {
      print('error3: $e');
    }

    print('dispose');
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (widget.pageIndex == widget.currentPageIndex &&
            !widget.isPaused &&
            !stopvideo ||
        widget.pageIndex == widget.pickedvideo &&
            widget.currentPageIndex == null &&
            !stopvideo) {
      setState(() {
        videoPlayerController?.play();
      });
    } else {
      setState(() {
        videoPlayerController?.pause();
      });
    }
    if (widget.mute) {
      videoPlayerController?.setVolume(0);
    } else if (!widget.mute) {
      videoPlayerController?.setVolume(1);
    }
    return Container(
      color: Colors.black,
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: Center(
          child: videoPlayerController.value.isInitialized
              ? GestureDetector(
                  onTap: () {
                    if (videoPlayerController.value.isPlaying) {
                      if (this.mounted) {
                        setState(() {
                          stopvideo = true;
                          videoPlayerController?.pause();
                        });
                      }
                    } else {
                      if (this.mounted) {
                        setState(() {
                          stopvideo = false;
                          videoPlayerController?.play();
                          videoPlayerController?.setLooping(true);
                        });
                      }
                    }
                  },
                  child: VisibilityDetector(
                    key: Key("unique keys"),
                    onVisibilityChanged: (VisibilityInfo info) {
                      debugPrint(
                          "${info.visibleFraction} of my widget is visible");
                      if (info.visibleFraction == 0) {
                        print("pause");
                        if (stopvideo == false) {
                          if (this.mounted) {
                            setState(() {
                              stopvideo = true;
                            });
                          }
                        }

                        videoPlayerController?.pause();
                      } else if (widget.pageIndex == widget.currentPageIndex ||
                          widget.pageIndex == widget.pickedvideo &&
                              widget.currentPageIndex == null) {
                        if (this.mounted) {
                          if (stopvideo == true) {
                            setState(() {
                              stopvideo = false;
                            });
                          }
                        }

                        videoPlayerController?.play();
                      } else {}
                    },
                    child: Stack(children: [
                      Center(
                        child: AspectRatio(
                          aspectRatio: videoPlayerController.value.aspectRatio,
                          child: VideoPlayer(videoPlayerController),
                        ),
                      ),
                      PlayPauseOverlay(
                        controller: videoPlayerController,
                        stopvideo: stopvideo,
                      )
                    ]),
                  ))
              : Center(
                  child: Container(
                    width: MediaQuery.of(context).size.width,
                    height: MediaQuery.of(context).size.height,
                    child: CachedNetworkImage(
                      errorWidget: (context, url, error) => Icon(Icons.error),
                      imageUrl: widget.thumbnailUrl,
                      fit: BoxFit.cover,
                    ),
                  ),
                )),
    );
  }
}

我的应用程序正在 Preloadpageview 中播放视频,这些视频可以垂直滚动,就像 instagram 中的卷轴一样。视频是从流中加载的。

希望任何人都可以解释一下 chaching 的确切含义以及它将如何影响我的高带宽。还有如何在我的案例中使用它?

The problem that I had was a high bandwidth in my flutter /firebase application . I had like 19gb a day with 10-20 videos and like up to 10 users.

有两层缓存可以解决此问题:初始视频下载和后续视频重播。

对于初始视频下载,一种选择是专用服务器充当中间缓存。它会下载并与当前 videourl 的内容保持同步,然后提供它。然后 videourls 将指向此服务器,以便客户端从中提取视频。
不过,这只会解决问题,而且带宽不是免费的。但是你不一定要托管这个缓存服务器,有公司会收费托管。

缓存有助于后续视频重放的方法是将其保存在视频播放客户端的本地临时存储中,当返回视频时,从本地临时存储中检索并播放 - 从而避免从再次打开服务器。

一个可能的快速解决方案是使用 better_player 库。它允许许多配置,包括使用缓存。你可以找到它here