cached_video_player_plus icon indicating copy to clipboard operation
cached_video_player_plus copied to clipboard

[Bug]: Takes too much time to cache/initialize videos

Open eqrakhattak opened this issue 4 months ago • 1 comments

Is there an existing issue for this?

  • [x] I have searched the existing issues

Bug Description

I open the screen to play video and the loader keeps loading. The logs say "Cached video of ... " after a long time. But even then it doesn't load the video.

Steps to Reproduce

Open full screen video

Expected Behavior

As soon as I open the video, it should be able to load with in seconds

Actual Behavior

I keep seeing the loader and the video doesn't load

Package Version

4.0.4

Platform(s)

iOS

Flutter Channel

stable

Flutter Doctor Output

[✓] Flutter (Channel stable, 3.35.3, on macOS 15.6 24G84 darwin-arm64, locale en-PK) [586ms]
    • Flutter version 3.35.3 on channel stable at /Users/eqrakhattak/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision a402d9a437 (6 days ago), 2025-09-03 14:54:31 -0700
    • Engine revision ddf47dd3ff
    • Dart version 3.9.2
    • DevTools version 2.48.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-lldb-debugging

[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0-rc3) [4.1s]
    • Android SDK at /Users/eqrakhattak/Library/Android/sdk
    • Emulator version 35.3.11.0 (build_id 12836668) (CL:N/A)
    • Platform android-36, build-tools 36.0.0-rc3
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
      This is the JDK bundled with the latest Android Studio installation on this machine.
      To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment (build 21.0.5+-13047016-b750.29)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 16.4) [1,477ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 16F6
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [7ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2024.2) [7ms]
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 21.0.5+-13047016-b750.29)

[✓] VS Code (version 1.98.2) [6ms]
    • VS Code at /Users/eqrakhattak/Downloads/Visual Studio Code.app/Contents
    • Flutter extension version 3.112.0

[✓] Connected device (4 available) [8.7s]
    • SM S911B (mobile)                • RFCW9195Q7B               • android-arm64  • Android 15 (API 35)
    • iPhone13 Pro (wireless) (mobile) • 00008110-00162D523C46801E • ios            • iOS 18.6.2 22G100
    • macOS (desktop)                  • macos                     • darwin-arm64   • macOS 15.6 24G84 darwin-arm64
    • Chrome (web)                     • chrome                    • web-javascript • Google Chrome 137.0.7151.120
    ! Error: Browsing on the local area network for iPhone. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for Hanza’s iphone. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for iPhone. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)

[✓] Network resources [1,201ms]
    • All expected network resources are available.

• No issues found!

Minimal Reproduction Code

import 'dart:io';

import 'package:adjust_sdk/adjust.dart';
import 'package:adjust_sdk/adjust_event.dart';
import 'package:askautobee_customer/utils/size_config.dart';
import 'package:askautobee_customer/widgets/custom_loading_indicator.dart';
import 'package:cached_video_player_plus/cached_video_player_plus.dart';

import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:video_player/video_player.dart';

import '../../../../res/app_assets.dart';
import '../../../../res/app_colors.dart';

class FullScreenMessageVideo extends StatefulWidget {

  final File? file;
  final String? videoUrl;
  final String? carId;

  const FullScreenMessageVideo({
    Key? key,
    required this.file,
    required this.videoUrl,
    this.carId,
  }) : super(key: key);

  @override
  State<FullScreenMessageVideo> createState() => _FullScreenMessageVideoState();
}

class _FullScreenMessageVideoState extends State<FullScreenMessageVideo> {
  late CachedVideoPlayerPlus videoPlayer;
  bool isPlay = false;
  bool _eventLogged = false;


  @override
  void initState() {
    super.initState();
    initializePlayer();
  }

  initializePlayer() async {
      if(widget.file!=null){
        videoPlayer = CachedVideoPlayerPlus.file(widget.file!);
        await videoPlayer.initialize();
      } else {
        videoPlayer = CachedVideoPlayerPlus.networkUrl(
          Uri.parse(widget.videoUrl!),
          videoPlayerOptions: VideoPlayerOptions(
            mixWithOthers: false,
            allowBackgroundPlayback: false,
          ),
        );

        await videoPlayer.initialize();
      }

      if (!mounted) return;
      videoPlayer.controller.addListener(_videoListener);

      if(mounted){
        setState(() {
          videoPlayer.controller.play();
          isPlay = true;
        });
      }
  }

  void _videoListener() {
    if (!mounted) return;

    try {
      if (videoPlayer.isInitialized && videoPlayer.controller.value.isBuffering) {
        if(mounted){
          setState(() {
            isPlay = false;
          });
        }
      } else {
        if(mounted){
          setState(() {
            isPlay = true;
          });
        }
      }

      if (videoPlayer.isInitialized && videoPlayer.controller.value.hasError) {
        debugPrint("Video error: ${videoPlayer.controller.value.errorDescription}");
      }

      if (videoPlayer.controller.value.position == videoPlayer.controller.value.duration ) {

        ///log video_view_completed event at Adjust
        AdjustEvent videoViewCompletedAdjustEvent = AdjustEvent('20iwmj');
        videoViewCompletedAdjustEvent.addCallbackParameter('car_id', widget.carId != null ? widget.carId! : '');
        Adjust.trackEvent(videoViewCompletedAdjustEvent);
        // debugPrint("🎯 Adjust event logged: video_view_completed for car ${widget.carId}");
      }

      if (!_eventLogged &&
          videoPlayer.controller.value.isPlaying &&
          videoPlayer.controller.value.position >= const Duration(seconds: 2)) {

        ///log video_view_started event at Adjust
        final AdjustEvent videoViewAdjustEvent = AdjustEvent('mc2fjk');
        videoViewAdjustEvent.addCallbackParameter('car_id', widget.carId!);
        Adjust.trackEvent(videoViewAdjustEvent);
        // debugPrint("🎯 Adjust event logged: video_view_started for car ${widget.carId}");

        _eventLogged = true;
      }

    } catch (e) {
      debugPrint("Video listener error: $e");
    }
  }

  @override
  void dispose() {
    super.dispose();
    if(videoPlayer.isInitialized)
      videoPlayer.controller.pause();

    videoPlayer.dispose();
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black12,
      // appBar: customAppBarWithCenterTitle(context: context, title: "",backButtonColor: AppColors.appBlack),
      body: GestureDetector(
        onTap: (){
          if (videoPlayer.isInitialized && isPlay) {
            videoPlayer.controller.pause();
          } else {
            if(videoPlayer.isInitialized)
              videoPlayer.controller.play();
          }
          setState(() {
            isPlay = !isPlay;
          });
        },
        child: Stack(
        children: [
          videoPlayer.isInitialized ? Center(
            child: AspectRatio(
                aspectRatio: videoPlayer.controller.value.aspectRatio,
                child: VideoPlayer(videoPlayer.controller)),
          ) : Center(
            child: Container(
              height: 80.h,
              width: 80.w,
              color: Colors.transparent,
              child: CustomLoadingIndicator(color: AppColors.white),
            ),
          ),
          videoPlayer.isInitialized ? Align(
              alignment: Alignment.bottomCenter,
              child: VideoProgressIndicator(
                  videoPlayer.controller,
                  colors: VideoProgressColors(playedColor: AppColors.appYellow, backgroundColor: AppColors.appWhite.withOpacity(0.8)),
                  allowScrubbing: true,
              ),
          ) : SizedBox.shrink(),
          Visibility(
            visible: !isPlay,
              child:
          Align(
            alignment: Alignment.center,
            child: Container(
              height: 58.h,
              width: 58.h,
              decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: AppColors.black.withOpacity(0.4)),
              child: Center(
                child: Icon(
                  isPlay ? Icons.pause : Icons.play_arrow,
                  color: Colors.white,
                ),
              ),
            ),
          )),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 40.h,horizontal: 12.w),
            child: GestureDetector(
              onTap: () => context.pop(),
              child: SvgPicture.asset(
                AppAssets.back_arrow_svg,
                color: AppColors.appWhite,
                //style: AppTextStyles.kworkSans400_16.copyWith(color: AppColors.appWhite),
              ),
            ),
          ),
        ],
                ),
      ),
    );
  }
}

Relevant Log Output

flutter: Cached video of [https://carrbee.s3.ap-southeast-2.amazonaws.com/blurred_videos/68622afff54905bfa4363f20_protected.mp4] is: /var/mobile/Containers/Data/Application/68AA1E17-0E21-4124-A635-A3601AA37F9B/Library/Caches/libCachedVideoPlayerPlusData/4d069c40-8e1d-11f0-9006-d78e575e43c7.octet-stream
flutter: Cache for [https://carrbee.s3.ap-southeast-2.amazonaws.com/blurred_videos/68622afff54905bfa4363f20_protected.mp4] valid till: 2025-11-18 13:08:27.820
[Instabug - APM] APM is disabled, skipping starting the UI trace for screen: /videoFullScreenView.
Please refer to the documentation for how to enable APM on your app: https://docs.instabug.com/docs/react-native-apm-disabling-enabling
[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: PlatformException(VideoError, Failed to load video: Cannot Open: This media format is not supported.: The operation couldn’t be completed. (OSStatus error -12847.), null, null)

Device Information

iPhone 13 Pro

Additional Context

No response

Would you like to work on this issue?

  • [ ] I'm interested in working on this issue

eqrakhattak avatar Sep 10 '25 08:09 eqrakhattak

Does this happen on the first run (before video is cached) or in subsequent runs (when video is played from cache)? According to your logs, the video seems to not be getting cached as server is sending a Content-Type: application/octet-stream. Refer Solution for Video saved as .bin file and this comment.

Try with this video and see if the issue is still reproducible: https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4

OutdatedGuy avatar Sep 13 '25 13:09 OutdatedGuy

Closing as stale

OutdatedGuy avatar Dec 05 '25 09:12 OutdatedGuy