media-kit / media-kit

A cross-platform video player & audio player for Flutter & Dart.
https://github.com/media-kit/media-kit
MIT License
1k stars 158 forks source link

Desktop App stuck #660

Open ubaidakmal opened 6 months ago

ubaidakmal commented 6 months ago

I created a Flutter desktop app in which I have a playlist of 10 videoswith duration of 10,10 sec each and I'm using media kit package for it and after 3 to 4 iteration app stuck and not work until I close the app and restart it.

waulite-786 commented 6 months ago

share you code please

ubaidakmal commented 6 months ago

share you code please import 'dart:async'; import 'dart:io'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:flutter/material.dart'; import 'package:desktop_webview_window/desktop_webview_window.dart' as LinuxWebView;

void main() { MediaKit.ensureInitialized(); runApp(const MyApp()); }

class MyApp extends StatelessWidget { const MyApp({super.key});

// This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyWidget(), ); } }

class MediaItem { final MediaType type; final String data;

MediaItem(this.type, this.data); }

enum MediaType { Video }

class MyWidget extends StatefulWidget { const MyWidget({Key? key}) : super(key: key);

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

class _MyWidgetState extends State { late Timer _timer; int _currentIndex = 0; bool shouldDisplayNextAdWebView = false; late final Player player; late final controller = VideoController(player, configuration: const VideoControllerConfiguration( enableHardwareAcceleration: true, )); final List mediaList = [ MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/C9PJJVFD0YPcgEhPPCRug_c2Qck1wzSiO28wdjYWT-Q=_skoop_media_6b7caebb3d91155b37a5fb5ebafcada8_278742315.mp4', ), MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/AX49jeJ6vo2sbOHBcHuUbEyOE54gIe3sFLP7zKsatDI=_skoop_media_ea3097636b49a79ab89ea87bf88bc93e_866131036.mp4', ), MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/tro1HCX2Uzp9Xf57QOk62wasE67MMJIaiCwgoOMAhB8=_skoop_media_8911cbf28c2d542a68da6ed4f693511d_413337684.mp4', ), MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/J6fyjWFWLdcdSLVZt0110qDHPQi9djoTkLb_QkfVwDk=_skoop_media_a3f17832747c62adc5800c40eb486cf5_976001660.mp4', ), MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/kX9kxpALx_Y2gxgmVM1F7gNins0Jx2q2grSf1sy22YY=_skoop_media_aa36974c0311bd86bcbac4df35dc1aee_499298982.mp4', ), MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/pPQTaOGiWOXHWlZ6XQvj75l6SCiy_4zwRsjVp_uvoMs=_skoop_media_b5cb0d99f79d428f08fb0fa071113a9a_787246526.mp4', ), MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/6Wd9lOXb_tGhAVz4C4Dz6HZ5bf3f8RKZBPCQHmSbPys=_skoop_media_10e59ce2b4c6e3a0fec175072fad308a_114780478.mp4', ), MediaItem( MediaType.Video, 'https://skoop-signage-storage-v2-staging.s3.amazonaws.com/aRItcZvgDVZXVU2w4zhnlH7JHq3pn79MRd9vj0yVmu0=_skoop_media_dfaab16e558e6df92d4d4443afc0f205_133380773.mp4', ), // Add more media items as needed ];

@override void initState() { super.initState(); print('initState calls continuously'); _startTimer(); if (Platform.isWindows) { player = Player( configuration: PlayerConfiguration( ready: () { print('The initialization is complete.'); player.setVolume(0); player.open( Media(mediaList[_currentIndex].data), play: true, ); }, ), ); } }

void _startTimer() { _timer = Timer.periodic(const Duration(seconds: 5), (timer) { setState(() { _currentIndex = (_currentIndex + 1) % mediaList.length; print('Player dispose after every video 1'); player.open( Media(mediaList[_currentIndex].data), play: true, ); }); }); }

@override void dispose() { _timer.cancel(); print('Player dispose after every video 1'); player.dispose(); super.dispose(); }

@override Widget build(BuildContext context) { final currentMedia = mediaList[_currentIndex]; return Scaffold( appBar: AppBar(title: const Text('Media Player')), body: Center( child: Video( controller: controller!, controls: null, )), ); } }

i created a demo app to test but somehow there also app got stuck and it using a lot of Ram usage in 30 mints it use almost 1GB

waulite-786 commented 6 months ago

send crash log

Regards, Abdul Majid Khan Senior Software Developer Mob: 8369691917 Waulite Technologies Pvt. Ltd. F-11, Shanti Nagar Industrial estate, Vakola, Santacruz East, Mumbai, Maharashtra 400055

On Tue, Jan 9, 2024 at 12:35 PM Ubaid Akmal @.***> wrote:

share you code please import 'dart:async'; import 'dart:io'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:flutter/material.dart'; import 'package:desktop_webview_window/desktop_webview_window.dart' as LinuxWebView;

void main() { MediaKit.ensureInitialized(); runApp(const MyApp()); }

class MyApp extends StatelessWidget { const MyApp({super.key});

// This widget is the root of your application. @OverRide https://github.com/OverRide Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyWidget(), ); } }

class MediaItem { final MediaType type; final String data;

MediaItem(this.type, this.data); }

enum MediaType { Video }

class MyWidget extends StatefulWidget { const MyWidget({Key? key}) : super(key: key);

@OverRide https://github.com/OverRide _MyWidgetState createState() => _MyWidgetState(); }

class _MyWidgetState extends State { late Timer _timer; int _currentIndex = 0; bool shouldDisplayNextAdWebView = false; late final Player player; late final controller = VideoController(player, configuration: const VideoControllerConfiguration( enableHardwareAcceleration: true, )); final List mediaList = [ MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/C9PJJVFD0YPcgEhPPCRug_c2Qck1wzSiO28wdjYWT-Q=_skoop_media_6b7caebb3d91155b37a5fb5ebafcada8_278742315.mp4 ', ), MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/AX49jeJ6vo2sbOHBcHuUbEyOE54gIe3sFLP7zKsatDI=_skoop_media_ea3097636b49a79ab89ea87bf88bc93e_866131036.mp4 ', ), MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/tro1HCX2Uzp9Xf57QOk62wasE67MMJIaiCwgoOMAhB8=_skoop_media_8911cbf28c2d542a68da6ed4f693511d_413337684.mp4 ', ), MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/J6fyjWFWLdcdSLVZt0110qDHPQi9djoTkLb_QkfVwDk=_skoop_media_a3f17832747c62adc5800c40eb486cf5_976001660.mp4 ', ), MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/kX9kxpALx_Y2gxgmVM1F7gNins0Jx2q2grSf1sy22YY=_skoop_media_aa36974c0311bd86bcbac4df35dc1aee_499298982.mp4 ', ), MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/pPQTaOGiWOXHWlZ6XQvj75l6SCiy_4zwRsjVp_uvoMs=_skoop_media_b5cb0d99f79d428f08fb0fa071113a9a_787246526.mp4 ', ), MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/6Wd9lOXb_tGhAVz4C4Dz6HZ5bf3f8RKZBPCQHmSbPys=_skoop_media_10e59ce2b4c6e3a0fec175072fad308a_114780478.mp4 ', ), MediaItem( MediaType.Video, ' https://skoop-signage-storage-v2-staging.s3.amazonaws.com/aRItcZvgDVZXVU2w4zhnlH7JHq3pn79MRd9vj0yVmu0=_skoop_media_dfaab16e558e6df92d4d4443afc0f205_133380773.mp4 ', ), // Add more media items as needed ];

@OverRide https://github.com/OverRide void initState() { super.initState(); print('initState calls continuously'); _startTimer(); if (Platform.isWindows) { player = Player( configuration: PlayerConfiguration( ready: () { print('The initialization is complete.'); player.setVolume(0); player.open( Media(mediaList[_currentIndex].data), play: true, ); }, ), ); } }

void _startTimer() { _timer = Timer.periodic(const Duration(seconds: 5), (timer) { setState(() { _currentIndex = (_currentIndex + 1) % mediaList.length; print('Player dispose after every video 1'); player.open( Media(mediaList[_currentIndex].data), play: true, ); }); }); }

@OverRide https://github.com/OverRide void dispose() { _timer.cancel(); print('Player dispose after every video 1'); player.dispose(); super.dispose(); }

@OverRide https://github.com/OverRide Widget build(BuildContext context) { final currentMedia = mediaList[_currentIndex]; return Scaffold( appBar: AppBar(title: const Text('Media Player')), body: Center( child: Video( controller: controller!, controls: null, )), ); } }

i created a demo app to test but somehow there also app got stuck and it using a lot of Ram usage in 30 mints it use almost 1GB

— Reply to this email directly, view it on GitHub https://github.com/media-kit/media-kit/issues/660#issuecomment-1882514693, or unsubscribe https://github.com/notifications/unsubscribe-auth/APA77QWWOQCJJSHMGXQZEW3YNTTZ5AVCNFSM6AAAAABBGXLQWGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOBSGUYTINRZGM . You are receiving this because you commented.Message ID: @.***>

ubaidakmal commented 6 months ago

media_kit: VideoOutput: Create Texture: 2350425870768 Cmedia_kit: VideoOutput: Using H/W rendering. annot load nvcuda.dll flutter: VideoOutput.Resize flutter: {handle: 2351797081136, id: 2350425870768, rect: {height: 0, left: 0, top: 0, width: 0}} flutter: NativeVideoController: Texture ID: 2350425870768 flutter: media_kit: wakelock: _count = 2 flutter: media_kit: wakelock: _count = 1 flutter: media_kit: wakelock: _count = 2 flutter: media_kit: wakelock: _count = 1 media_kit: VideoOutput: Free Texture: 2350426290368 VideoOutput::~VideoOutput: 2351701828128 480 864 media_kit: VideoOutput: Free Texture: 2350425870768 media_kit: ANGLESurfaceManager: Direct3D Feature Level: 11_0 media_kit: VideoOutput: Create Texture: 2350430152176

these are the logs where app got stuck

waulite-786 commented 6 months ago

this is not error this medit kit log

use this code

import 'package:flutter/material.dart'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart';

class MyVideoPlayer extends StatefulWidget { final String path;

const MyVideoPlayer({super.key, required this.path});

@override State createState() => MyVideoPlayerState(); }

class MyVideoPlayerState extends State { // Create a [Player] to control playback. late final videoPlayer = Player(); // Create a [VideoController] to handle video output from [Player]. VideoController? videoController;

@override void initState() { super.initState(); videoController = VideoController(videoPlayer); onInit(); }

void onInit() async { try { await videoPlayer.open(Media(widget.path)); videoPlayer.stream.completed.listen( (bool complete) { if (complete) { videoController = null; videoPlayer.stop(); videoPlayer.dispose(); // write the logic when video complete } else { // Paused. } }, ); videoPlayer.stream.position.listen((Duration position) { double value = position.inMilliseconds.toDouble(); }); videoPlayer.stream.log.listen((event) {}); } catch (e) { print("exception"); } }

@override void dispose() { super.dispose(); }

@override Widget build(BuildContext context) { return Video( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, controller: videoController!, fit: BoxFit.fill, controls: NoVideoControls, ); } }

Regards, Abdul Majid Khan Senior Software Developer

ubaidakmal commented 6 months ago

this is basically my acutual code in which I locally download videos then get from local and play it if platform is mobile then use videoPlayer package if platform is Desktop play Media_kit package after your suggestion I made these changes in my code and in whole day just once app got stuck but issue is this now it using a lot of Ram memory in one hour almost 7GB Ram used, maybe it not dispose the player properly

basically I have a project In which i get a playlist of videos almost 8 to 10 videos and play them with duration of 10 sec and these videos played in a loop.

import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:flutter_bugfender/flutter_bugfender.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:path/path.dart';
import 'package:skoop_signage_app/extensions/getStorageExtension.dart';
import 'package:skoop_signage_app/ui/playlist_ad_loop_page.dart';

import 'package:easy_downloader/easy_downloader.dart';
import 'package:path_provider/path_provider.dart';
import 'package:skoop_signage_app/utils/setResolution.dart';
import 'package:video_player/video_player.dart' as Mobile;

// import 'package:video_player_win/video_player_win.dart';
import '../../net/ApiClient.dart';
import '../../utils/appLogs.dart';
import '../../utils/platform.dart';
import 'BlankScreen.dart';

class VideoPlayer extends StatefulWidget {
  final Function onGotoMenu;
  bool showBlank;

  VideoPlayer(
      {Key? key,
      required this.url,
      required this.onGotoMenu,
      required this.showBlank})
      : super(key: key);
  final String url;

  @override
  State<VideoPlayer> createState() => _VideoPlayerState();
}

class _VideoPlayerState extends State<VideoPlayer> with WidgetsBindingObserver{
  Mobile.VideoPlayerController? _controller;

   Player? player;
  ApiClient apiClient = Get.find();
  Isar? isar;
  List<FileSystemEntity> videoFiles = [];
  List videoHashes = [];
  var getPath = '';
  late EasyDownloader easyDownloader;
  late MediaResolution mediaResolution;
  var screenOnOfObserverListener;
  DownloadTask? currentVideoDownloadTask;
  late final controller = VideoController(player!, configuration: const VideoControllerConfiguration(
    enableHardwareAcceleration: true,
  ));
  currentDownloadTaskListener(DownloadTask task) {
    AppLogger.logInfo(
        "status downloading : thread name ${Isolate.current.debugName} : ${task.status} ${task.totalDownloaded.toHumanReadableSize()} / ${task.totalLength.toHumanReadableSize()} ${task.url}");
    if (task.status == DownloadStatus.completed) {
      if (mounted) {
        if (PlatformUtils.isMobile) {
          playMobileMedia(task.outputFilePath);
        }
        if (PlatformUtils.isDesktop) {
          print('Function 2');
          onDesktopPlayerOpen(task.outputFilePath);
        }
      }
    }
  }

  void onDesktopPlayerOpen(String source) async {
    print('Function 1');
    try {
      await player?.open(Media(source), play: true);
      player?.stream.completed.listen(
        (bool complete) {
          print('Value of Complete Boolean $complete');
          if (complete) {
            player = null;
            player?.stop();
            player?.dispose();
          } else {
            // player.pause();
          }
        },
      );
      player?.stream.position.listen((Duration position) {
        double value = position.inMilliseconds.toDouble();
      });
      player?.stream.log.listen((event) {});
    } catch (e) {
      print("exception");
    }
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    screenOnOfObserverListener = apiClient.screenOnOfObserver.listen((response) {
      widget.showBlank = response;
      if (mounted) {
        setState(() {});
      }
    });
    if (PlatformUtils.isDesktop) {
      player = Player(configuration: PlayerConfiguration(
        ready: () {
          AppLogger.logInfo('The initialization is complete.');
          print('The initialization is complete.');
          player?.setVolume(0);
        },
      ));
    }
    mediaResolution = MediaResolution();

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
      await getLocalFileData();
      performDownloadAndPlay();
    });
  }
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (PlatformUtils.isMobile) {
      if (_controller != null) {
        if (state == AppLifecycleState.resumed) {
          _controller!.play();
          print('App is in resumed state');
        } else {
          _controller!.pause();
          print('App is in paused or inActive state');
        }
      }
    }
  }

  var storage = GetStorage();

  @override
  Widget build(BuildContext context) {
    double? pixelRatio = MediaQuery.of(context).devicePixelRatio;
    return WillPopScope(
      onWillPop: () async => false,
      child: widget.showBlank == false
          ? ShowBlankScreen(gotoMenuScreen: widget.onGotoMenu)
          : Scaffold(
              body: Stack(
                children: [
                  RotatedBox(
                    quarterTurns: int.parse(storage.getRotationValue()),
                    child: Center(
                        child: PlatformUtils.isDesktop && controller == null
                            ? const CircularProgressIndicator()
                            : storage
                            .getScreen()
                            ?.resolution_height_in_px != 0 &&
                            storage
                                .getScreen()
                                ?.resolution_width_in_px !=
                                0
                            ? SizedBox(
                            height: mediaResolution.getHeightInPixels(
                                storage
                                    .getScreen()
                                    ?.resolution_height_in_px
                                    ?.toDouble() ??
                                    double.infinity,
                                pixelRatio),
                            width: mediaResolution.getWidthInPixels(
                                storage
                                    .getScreen()
                                    ?.resolution_width_in_px
                                    ?.toDouble() ??
                                    double.infinity,
                                pixelRatio),
                            child: PlatformUtils.isDesktop
                                ? Video(
                              alignment: Alignment.topLeft,
                              controller: controller!,
                              controls: null,
                            )
                                : PlatformUtils.isMobile &&
                                _controller != null
                                ? AspectRatio(
                                aspectRatio: _controller
                                    ?.value.aspectRatio ??
                                    0.0,
                                child: Mobile.VideoPlayer(
                                    _controller!))
                                : const SizedBox())
                            : PlatformUtils.isDesktop
                            ? Video(
                          controller: controller!,
                          controls: null,
                        )
                            : PlatformUtils.isMobile &&
                            _controller != null
                            ? AspectRatio(
                            aspectRatio:
                            _controller?.value.aspectRatio ?? 0.0,
                            child: Mobile.VideoPlayer(_controller!))
                            : const SizedBox()),
                  ),
                  InkWell(
                    child: const SizedBox(
                      width: 100,
                      height: 100,
                    ),
                    onLongPress: () {
                      widget.onGotoMenu();
                    },
                  ),
                  PingStatusView(apiClient: apiClient)
                ],
              ),
              backgroundColor: Colors.black,
            ),
    );
  }

  @override
  Future<void> dispose() async {
    super.dispose();
    WidgetsBinding.instance?.removeObserver(this);
    isFileDownloadedCheckTimer?.cancel();
    if (PlatformUtils.isMobile) {
      _controller?.pause();
      _controller?.dispose();
      _controller = null;
      currentVideoDownloadTask?.removeListener(currentDownloadTaskListener);
      screenOnOfObserverListener.cancel();
    } else {
      player = null;
      player?.stop();
      await player?.dispose();
      print('Desktop Player onDispose');
    }
    AppLogger.logInfo('onDispose');
    print('onDispose');
  }

  Future<void> performDownloadAndPlay() async {
    easyDownloader = EasyDownloader();
    getAllDownloadTaskInfo();
    var url = widget.url;
    AppLogger.logInfo("value of hashcode ${widget.url.hashCode.abs()}");
    print("value of hashcode ${widget.url.hashCode.abs()}");
    var name = "${url.hashCode.abs()}.mp4";
    var appDocDir;
    var appDocDirOS;
    if (PlatformUtils.isDesktop) {
      appDocDir = await getDownloadsDirectory();
    }
    if (Platform.isIOS) {
      appDocDirOS = await getApplicationDocumentsDirectory();
    }
    var androidAppDocDir;
    if (Platform.isAndroid) {
      androidAppDocDir = await getExternalStorageDirectory();
    }
    var path;
    if (Platform.isWindows) {
      path = '${appDocDir?.path}\\Skoop';
    } else if (Platform.isLinux) {
      path = '${appDocDir?.path}/Skoop';
    } else if (Platform.isIOS) {
      path = '${appDocDirOS?.path}/Skoop';
    } else if (PlatformUtils.isAndroid) {
      path = '${androidAppDocDir?.path}/Skoop';
    }
    getPath = path;
    AppLogger.logInfo('path: $path');
    print('path: $path');
    var file = File(name);
    if (file.existsSync()) {
      file.deleteSync();
    }
    await Isar.initializeIsarCore(download: true);
    AppLogger.logInfo("Isar Core initialization complete.");
    isar = Isar.getInstance("messages");
    if (isar?.isOpen == false) {
      isar = await Isar.open(
        EasyDownloader.schemas,
        directory: ".",
      );
    } //PRINT
    var dir = path;
    var skoopFolder = Directory(dir);
    if (await skoopFolder.exists()) {
      if(mounted){
        setState(() {
          videoFiles = skoopFolder.listSync().where((entity) {
            return entity is File && entity.path.toLowerCase().endsWith('.mp4');
          }).toList();
        });
      }
      AppLogger.logInfo('VideoFiles List is: $videoFiles');
      print('VideoFiles List is: $videoFiles');
    }
    // if (PlatformUtils.isDesktop) {
    //   print('Function 3');
    //   onDesktopPlayerOpen(url);
    // }
    var localFile;
    var fileAlreadyDownloaded = isDownloadedVideoExisted(widget.url.hashCode.abs().toString());
    if (fileAlreadyDownloaded) {
      AppLogger.logInfo(
          'Video is Already Downloaded and the hashCode of video is: ${widget.url.hashCode.abs()}');
      print(
          'Video is Already Downloaded and the hashCode of video is: ${widget.url.hashCode.abs()}');
    } else {
      currentVideoDownloadTask = await easyDownloader.download(
          url: widget.url,
          maxSplit: 2,
          autoStart: true,
          fileName: name,
          path: path);
      currentVideoDownloadTask?.addListener(currentDownloadTaskListener);
      var task = currentVideoDownloadTask!;
      AppLogger.logInfo('task path is${task.path}');print('task path is${task.path}');
      print('task path is${task.path}');print('task path is${task.path}');
      if (Platform.isWindows) {
        localFile = '${task.path}\\${task.fileName}';
      } else if (Platform.isLinux) {
        localFile = '${task.path}/${task.fileName}';
      } else if (PlatformUtils.isAndroid) {
        localFile = '${task.path}/${task.fileName}';
      } else if (PlatformUtils.isIOS) {
        localFile = '${task.path}/${task.fileName}';
      }
      AppLogger.logInfo('local file path is $localFile');
      print('local file path is $localFile');
    }
    String? filePath = getLocalDownloadedVideo(path);
    bool isLocalFileExisted;
    if (filePath != null && filePath.isNotEmpty) {
      isLocalFileExisted = true;
    } else {
      isLocalFileExisted = false;
    }
    if (isLocalFileExisted) {
      AppLogger.logInfo('local file is played');
      print('local file is played');
      if (PlatformUtils.isMobile) {
        AppLogger.logInfo('Play Video');
        print('Play Video');
        playMobileMedia(getLocalDownloadedVideo(path)!);
      } else {
        print('Function 4');
        onDesktopPlayerOpen(getLocalDownloadedVideo(path)!);
      }
    } else {
      AppLogger.logInfo('video played from url');
      print('video played from url');
      if (PlatformUtils.isMobile) {
        _controller = Mobile.VideoPlayerController.networkUrl(Uri.parse(widget.url));
        if (_controller != null && !_controller!.value.isInitialized) {
          _controller?.initialize().then((value) {
            _controller?.play();
            setState(() {});
          });
        }
      } else {
        print('Function 5');
        onDesktopPlayerOpen(localFile);
      }
    }
  }

  String? getLocalDownloadedVideo(var path) {
    String? foundValue;
    for (String hash in videoHashes) {
      if (hash == widget.url.hashCode.abs().toString()) {
        foundValue = hash;
        AppLogger.logInfo('value of found:- $foundValue');
        print('value of found:- $foundValue');
        break;
      }
    }
    var localFileName;
    var localFilePath;
    if (foundValue != null) {
      localFileName = '$foundValue.mp4';
      localFilePath;
      localFilePath = '$path/$localFileName';
      AppLogger.logInfo("Path of LocalFilePath: - $localFilePath");
      print("Path of LocalFilePath: - $localFilePath");
      AppLogger.logInfo("Name of LocalFilename: - $localFileName");
      print("Name of LocalFilename: - $localFileName");
      return localFilePath;
    } else {
      return null;
    }
  }

  Future<void> getLocalFileData() async {
    var appDocDir;
    var appDocDirOs;
    if (PlatformUtils.isDesktop) {
      appDocDir = await getDownloadsDirectory();
    }
    if (Platform.isIOS) {
      appDocDirOs = await getApplicationDocumentsDirectory();
    }
    var androidAppDocDir;
    if (Platform.isAndroid) {
      androidAppDocDir = await getExternalStorageDirectory();
    }
    var path;
    if (Platform.isWindows) {
      path = '${appDocDir?.path}\\Skoop';
    } else if (Platform.isLinux) {
      path = '${appDocDir?.path}/Skoop';
    } else if (Platform.isIOS) {
      path = '${appDocDirOs?.path}/Skoop';
    } else if (Platform.isAndroid) {
      path = '${androidAppDocDir?.path}/Skoop';
    }
    var dir = path;
    var skoopFolder = Directory(dir);
    if (await skoopFolder.exists()) {
     if(mounted){
       setState(() {
         videoFiles = skoopFolder.listSync().where((entity) {
           return entity is File && entity.path.toLowerCase().endsWith('.mp4');
         }).toList();
       });
     }
     AppLogger.logInfo(
          'VideoFiles List is in VideoPlayer File: ${videoFiles}');print(
          'VideoFiles List is in VideoPlayer File: ${videoFiles}');
    }
    videoHashes = extractVideoHashes(videoFiles);

    AppLogger.logInfo(
        'Extracted video hashes in VideoPlayer File: $videoHashes');
    print(
        'Extracted video hashes in VideoPlayer File: $videoHashes');
    AppLogger.logInfo('value of url hash ${widget.url.hashCode.abs()}');
    print('value of url hash ${widget.url.hashCode.abs()}');
  }

  List extractVideoHashes(List<FileSystemEntity> videoFiles) {
    List videoHashes = [];

    for (FileSystemEntity file in videoFiles) {
      String fileName =
          file.uri.pathSegments.last; // Get the filename from the URI.
      String fileNameWithoutExtension =
          fileName.replaceAll('.mp4', ''); // Remove extension.
      videoHashes.add(fileNameWithoutExtension);
    }

    return videoHashes;
  }

  Future<void> getAllDownloadTaskInfo() async {
    List<DownloadTask> downloadTasks;
    downloadTasks = await easyDownloader.allDownloadTasks();
    easyDownloader.allDownloadTasks().then((value) async {
      value.printInfo(info: 'allDownloadTasks');
      var existingTask = downloadTasks
          .firstWhereOrNull((element) => element.url == widget.url);
      if (existingTask != null) {
        bool anyFailedBlocks = await hasFailedBlocks(
          existingTask,
          easyDownloader,
        );
        if (anyFailedBlocks) {
          AppLogger.logInfo(
              "Some DownloadTask has blocks with status 'BlockStatus.failed'.");
          print(
              "Some DownloadTask has blocks with status 'BlockStatus.failed'.");
        } else {
          AppLogger.logInfo(
              "No DownloadTask has blocks with status 'BlockStatus.failed'.");print(
              "No DownloadTask has blocks with status 'BlockStatus.failed'.");
        }
      }
    });
  }

  Future<bool> hasFailedBlocks(DownloadTask currentTask,
      EasyDownloader easyDownloader) async {
    if (currentTask.status == DownloadStatus.completed) {
      AppLogger.logInfo(
          '${currentTask.url.hashCode.abs()}: Downloaded, URL: ${currentTask.url}');print(
          '${currentTask.url.hashCode.abs()}: Downloaded, URL: ${currentTask.url}');
    } else if (currentTask.status == DownloadStatus.paused) {
      currentTask.continueDownload();
      AppLogger.logInfo("downloading continues");print("downloading continues");
    } else if (currentTask.status == DownloadStatus.none) {
      currentTask.addInQueue();
      AppLogger.logInfo("downloading continues");print("downloading continues");
    } else {
      AppLogger.logInfo(" current status: ${currentTask.status}");print(" current status: ${currentTask.status}");
    }
    for (var block in currentTask.blocks) {
      if (block.status == BlockStatus.failed) {
        AppLogger.logInfo(
            'taskId of failed file: ${currentTask.downloadId}');print(
            'taskId of failed file: ${currentTask.downloadId}');
        bool? deleted =
            await easyDownloader.removeDownloadTask(currentTask.downloadId);
        if (deleted == true) {
          AppLogger.logInfo('taskId: ${currentTask.downloadId} is deleted');print('taskId: ${currentTask.downloadId} is deleted');
        } else {
          AppLogger.logInfo(
              'taskId: ${currentTask.downloadId} is not deleted');print(
              'taskId: ${currentTask.downloadId} is not deleted');
        }
        return true; // Found a failed block
      }
    }
    return false; // No failed blocks found
  }

  bool isDownloadedVideoExisted(String urlHashCode) {
    return videoHashes.contains(urlHashCode);
  }

  void playMobileMedia(String path) {
    'Play At Path: $path'.printInfo();
    _controller = Mobile.VideoPlayerController.file(
        File(path));
    if (_controller != null && !_controller!.value.isInitialized) {
      _controller?.initialize().then((value) {
        _controller?.play();
        setState(() {});
      });
    }
    setState(() {});
  }
}

Timer? isFileDownloadedCheckTimer;