11

Does anyone know how to do Flutter Video Caching in List for 4 to 6 seconds? (For next 5 videos) like Instagram reels.

Is there any way to do it?

I had taken PageView.builder to show a video with a full page.

I have tried one cached_video_player but it's loading full video.

Here is what I have done.

VideoWidget:

typedef OnVideoCompleted = void Function();

class VideoWidget extends StatefulWidget {
  //final bool? play;
  final bool? isDuetVideo;
  final String? url;
  final OnVideoCompleted? onVideoCompleted;
  final HomeWidgetBloc? homeWidgetBloc;

  const VideoWidget(
      {Key? key,
      this.onVideoCompleted,
      required this.url,
      required this.homeWidgetBloc,
      required this.isDuetVideo})
      : super(key: key);

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

class _VideoWidgetState extends State<VideoWidget> {
  late VideoPlayerController videoPlayerController;
  late Future<void> _initializeVideoPlayerFuture;
  final _controllerStateStream = BehaviorSubject<int>.seeded(0);
  VoidCallback? _listener;
  StreamSubscription? _playPauseSubscription;

  @override
  void initState() {
    super.initState();
    videoPlayerController = new VideoPlayerController.network(widget.url!);
    videoPlayerController.initialize().then((_) {
      //       Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
      _controllerStateStream.add(1);
      _observeForPlayPause();
      _observerForSeekDuration();
      _listener = () {
        final value =
            widget.homeWidgetBloc?.videoEndedStream.valueWrapper?.value;
        print('duration -----value--- ${value}');
        if (videoPlayerController.value.duration.inSeconds > 0 &&
            videoPlayerController.value.position.inMilliseconds ==
                videoPlayerController.value.duration.inMilliseconds &&
            (videoPlayerController.value.position.inMilliseconds ==
                videoPlayerController.value.duration.inMilliseconds)) {
          // FOR AUTO PLAY NEXT VIDEO...
          widget.onVideoCompleted?.call();
          print(
              'duration -----addListener--- ${videoPlayerController.value.duration}');
        }
      };
      videoPlayerController.addListener(_listener!);
    });
  } // This closing tag was missing

  @override
  void dispose() {
    super.dispose();
    _controllerStateStream.close();
    _playPauseSubscription?.cancel();
    try {
      if (_listener != null) {
        videoPlayerController.removeListener(_listener!);
      }
      videoPlayerController.dispose();
    } catch (e) {
      print(e.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<int>(
      stream: _controllerStateStream,
      builder: (context, snapshot) {
        final isReady = (snapshot.data ?? 0) == 1;

        if (!isReady) {
          return _progressWidget();
        }

        return new Stack(children: <Widget>[
          Container(
            child: Center(
              child: (widget.isDuetVideo! ||
                      videoPlayerController.value.size.width >
                          videoPlayerController.value.size.height)
                  ? AspectRatio(
                      child: VideoPlayer(
                        videoPlayerController,
                      ),
                      aspectRatio: videoPlayerController.value.aspectRatio,
                    )
                  : VideoPlayer(
                      videoPlayerController,
                    ),
              widthFactor: double.maxFinite,
              heightFactor: double.maxFinite,
            ),
          ),
          Visibility(
            visible: !widget.isDuetVideo!,
            child: VideoPlayerCustomControlsWidget(
              controller: videoPlayerController,
            ),
          ),
        ]);
      },
    );
  }

  Center _progressWidget() {
    return Center(
      child: CircularProgressIndicator(
        color: AppStyles.primary500Color,
      ),
    );
  }

  void _observeForPlayPause() {
    _playPauseSubscription =
        widget.homeWidgetBloc?.videoPlayPauseStream.listen((value) {
      if (value == PLAY)
        videoPlayerController.play();
      else
        videoPlayerController.pause();
    });
  }

  void _observerForSeekDuration() {
    _playPauseSubscription =
        widget.homeWidgetBloc?.duetVideoSeekDurationZeroStream.listen((value) {
      if (value == true) videoPlayerController.seekTo(Duration.zero);
      widget.homeWidgetBloc?.duetVideoSeekDurationZeroStream.add(false);
    });
  }
}

Update:

I found many answers (like this) but that all answers are only for caching the current video, not the next/prev videos from the list. I want it, especially for the list.

Pratik Butani
  • 60,504
  • 58
  • 273
  • 437

1 Answers1

2

this is what I used in my app, preload_page_view, it preloads a specific count of pre/next pages:

  @override
  Widget build(BuildContext context) {
    return new PreloadPageView.builder(
      itemCount: ...,
      itemBuilder: ...,
      onPageChanged: (int position) {...},
      .....
      preloadPagesCount: 3,
      controller: PreloadPageController(),
    );
  }
Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Jim
  • 6,928
  • 1
  • 7
  • 18
  • Thanks for the answer, As I am moving to the next video automatically after the current video get completed. Maybe your way will not work to load the next video for some seconds only. – Pratik Butani Sep 22 '21 at 06:08
  • once the video is pre loaded, can you replay the current video to achieve what you want? – Jim Sep 22 '21 at 06:12
  • I am managing the video state to play/pause from anywhere using stream. I don't know what will happen. I need to verify. – Pratik Butani Sep 22 '21 at 06:41
  • yeh, no problem, hope you sort it out, just an idea that you can seekTo the beginning of current video while switching pages – Jim Sep 22 '21 at 06:48
  • Can you please give me an example, I couldn't able to achieve what I want. – Pratik Butani Sep 28 '21 at 06:55
  • try to make your page view current index a global variable or put it in state, pass to video widget, fire the event once the current index == video index, _controller.play – Jim Sep 28 '21 at 07:13