abdelaziz-mahdy / flutter_meedu_videoplayer

Cross-Platform Video Player for flutter
https://abdelaziz-mahdy.github.io/flutter_meedu_videoplayer/
MIT License
132 stars 69 forks source link

Black rectangle on initialization #132

Closed krida2000 closed 11 months ago

krida2000 commented 12 months ago

I have a black rectangle before the video initialized. I think it is because media_kit Video.fill is not set and by default it's black. There is any way to set this paramether?

Video https://github.com/zezo357/flutter_meedu_videoplayer/assets/71345244/ac340d0e-5051-4b43-840f-77553bcce017
abdelaziz-mahdy commented 12 months ago

I think the black background is the default in most video players?

Does doing a flutter upgrade help? Since it will use the latest media_kit release

Does the video fill get passed to the media_kit video widget? If yes I will try to make it based of a custom theme (no promises) since I have been busy for a while

amaxcz commented 11 months ago

@zezo357

Dear author,

The issue of a black screen is indeed a significant problem. Currently, I am unable to use this well-functioning player simply due to one reason—the application has a white color scheme, and the black preloading screen ruins the overall experience. It is unknown how to resolve this.

Ideally, it would be great to have a parameter for customizing the background color of the placeholder. This is crucial for applications that require a seamless transition between video playback and the UI. Without such customization, it seems impossible to use this player code in a serious business setting.

I kindly request you to add the ability to customize the color.

Thank you in advance!

abdelaziz-mahdy commented 11 months ago

Thank you for explaining, your case I will try to provide a way to customize it, when I do I will let you know here

amaxcz commented 11 months ago

@zezo357 Dear author of the player, please take a look at the following code example. Currently, I am using this wrapper... It effectively solves several issues:

  1. Black screen
  2. Convenient source handling, whether the file is retrieved from the web or locally (I really don't want to know the details)
  3. Default dimensions, but not the dimensions of the placeholder...

In the attachment, I am simply showing you this code example to demonstrate real use cases and the challenges faced when using the player.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_meedu_videoplayer/meedu_player.dart';

class UVideoPlayer extends StatefulWidget {
  final String? source;
  final double? width;
  final double? height;

  const UVideoPlayer({
    Key? key,
    required this.source,
    this.width,
    this.height,
  }) : super(key: key);

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

class _UVideoPlayerState extends State<UVideoPlayer> with SingleTickerProviderStateMixin {
  final _meeduPlayerController = MeeduPlayerController(
    controlsStyle: ControlsStyle.custom,
    autoHideControls: false,
    controlsEnabled: false,
    enabledControls: EnabledControls(
      desktopDoubleTapToFullScreen: false,
      desktopTapToPlayAndPause: false,
      enterKeyOpensFullScreen: false,
      escapeKeyCloseFullScreen: false,
      numPadDecimalKeyToggleFit: false,
      onLongPressSpeedUp: false,
      seekArrows: false,
      seekSwipes: false,
      spaceKeyTogglePlay: false,
      volumeArrows: false,
      volumeSwipes: false,
    ),
  );
  late AnimationController _animationController;
  late Animation<double> _opacityAnimation;

  @override
  void initState() {
    super.initState();
    Future.microtask(updateSource);
    _animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 1000),
    );
    _opacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
    Timer(Duration(seconds: 1), () {
      _animationController.forward();
    });
  }

  void updateSource() async {
    if (_meeduPlayerController.playerStatus.playing) {
      await _meeduPlayerController.pause();
    }
    if (widget.source != null) {
      if (widget.source!.startsWith('https://') || widget.source!.startsWith('http://')) {
        await _meeduPlayerController.setDataSource(
          DataSource(
            type: DataSourceType.network,
            source: widget.source!,
          ),
          autoplay: true,
          looping: true,
        );
      } else {
        var file = File(widget.source!);
        await _meeduPlayerController.setDataSource(
          DataSource(
            type: DataSourceType.file,
            file: file,
          ),
          autoplay: true,
          looping: true,
        );
      }
    }

    await _meeduPlayerController.setVolume(90);
  }

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

  @override
  Widget build(BuildContext context) {
    late double width;
    late double height;

    if (widget.width == null || widget.height == null) {
      width = 256;
      height = 144;
    } else {
      width = widget.width!;
      height = widget.height!;
    }

    return Container(
      margin: EdgeInsets.all(0),
      child: Align(
        alignment: Alignment.topCenter,
        child: SizedBox(
          width: width,
          height: height,
          child: AnimatedBuilder(
            animation: _opacityAnimation,
            builder: (BuildContext context, Widget? child) {
              return Opacity(
                opacity: _opacityAnimation.value,
                child: child,
              );
            },
            child: widget.source != null
                ? AspectRatio(
                    aspectRatio: 16 / 9,
                    child: MeeduVideoPlayer(
                      controller: _meeduPlayerController,
                    ),
                  )
                : Container(),
          ),
        ),
      ),
    );
  }
}
abdelaziz-mahdy commented 11 months ago

@zezo357 Dear author of the player, please take a look at the following code example. Currently, I am using this wrapper... It effectively solves several issues:

  1. Black screen
  2. Convenient source handling, whether the file is retrieved from the web or locally (I really don't want to know the details)
  3. Default dimensions, but not the dimensions of the placeholder...

In the attachment, I am simply showing you this code example to demonstrate real use cases and the challenges faced when using the player.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_meedu_videoplayer/meedu_player.dart';

class UVideoPlayer extends StatefulWidget {
  final String? source;
  final double? width;
  final double? height;

  const UVideoPlayer({
    Key? key,
    required this.source,
    this.width,
    this.height,
  }) : super(key: key);

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

class _UVideoPlayerState extends State<UVideoPlayer> with SingleTickerProviderStateMixin {
  final _meeduPlayerController = MeeduPlayerController(
    controlsStyle: ControlsStyle.custom,
    autoHideControls: false,
    controlsEnabled: false,
    enabledControls: EnabledControls(
      desktopDoubleTapToFullScreen: false,
      desktopTapToPlayAndPause: false,
      enterKeyOpensFullScreen: false,
      escapeKeyCloseFullScreen: false,
      numPadDecimalKeyToggleFit: false,
      onLongPressSpeedUp: false,
      seekArrows: false,
      seekSwipes: false,
      spaceKeyTogglePlay: false,
      volumeArrows: false,
      volumeSwipes: false,
    ),
  );
  late AnimationController _animationController;
  late Animation<double> _opacityAnimation;

  @override
  void initState() {
    super.initState();
    Future.microtask(updateSource);
    _animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 1000),
    );
    _opacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
    Timer(Duration(seconds: 1), () {
      _animationController.forward();
    });
  }

  void updateSource() async {
    if (_meeduPlayerController.playerStatus.playing) {
      await _meeduPlayerController.pause();
    }
    if (widget.source != null) {
      if (widget.source!.startsWith('https://') || widget.source!.startsWith('http://')) {
        await _meeduPlayerController.setDataSource(
          DataSource(
            type: DataSourceType.network,
            source: widget.source!,
          ),
          autoplay: true,
          looping: true,
        );
      } else {
        var file = File(widget.source!);
        await _meeduPlayerController.setDataSource(
          DataSource(
            type: DataSourceType.file,
            file: file,
          ),
          autoplay: true,
          looping: true,
        );
      }
    }

    await _meeduPlayerController.setVolume(90);
  }

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

  @override
  Widget build(BuildContext context) {
    late double width;
    late double height;

    if (widget.width == null || widget.height == null) {
      width = 256;
      height = 144;
    } else {
      width = widget.width!;
      height = widget.height!;
    }

    return Container(
      margin: EdgeInsets.all(0),
      child: Align(
        alignment: Alignment.topCenter,
        child: SizedBox(
          width: width,
          height: height,
          child: AnimatedBuilder(
            animation: _opacityAnimation,
            builder: (BuildContext context, Widget? child) {
              return Opacity(
                opacity: _opacityAnimation.value,
                child: child,
              );
            },
            child: widget.source != null
                ? AspectRatio(
                    aspectRatio: 16 / 9,
                    child: MeeduVideoPlayer(
                      controller: _meeduPlayerController,
                    ),
                  )
                : Container(),
          ),
        ),
      ),
    );
  }
}

The black should still be visible when using windows or desktop in general due to media_kit I think

amaxcz commented 11 months ago

@zezo357 Under Linux, the player functions correctly, but a 1-second timeout is unacceptable for me. Checking Android now ... But anyway, we need to have option "all controls are disabled" just for dumb promo video, also, unified source will be great option IMO. But black screen is the real problem anyway.

abdelaziz-mahdy commented 11 months ago

@zezo357 Under Linux, the player functions correctly, but a 1-second timeout is unacceptable for me. Checking Android now ... But anyway, we need to have option "all controls are disabled" just for dumb promo video, also, unified source will be great option IMO. But black screen is the real problem anyway.

The unified source can be handled like how you handled it, the separation makes it easier for debugging, for most people,

Also can you explain the 1 second time out, you mentioned?

For the black background, I can check it next weekend, since I am working full time. Sorry if that takes some time

amaxcz commented 11 months ago

@zezo357 The animation with a 1-second delay after startup removes or hides the black screen, followed by a transparency animation. But... However, it is not suitable to have an empty white placeholder displayed for more than 1 second.

p.s. timeline is OK :) Thanks!

abdelaziz-mahdy commented 11 months ago

@zezo357 The animation with a 1-second delay after startup removes or hides the black screen, followed by a transparency animation. But... However, it is not suitable to have an empty white placeholder displayed for more than 1 second.

p.s. timeline is OK :) Thanks!

Thank you ❤️

abdelaziz-mahdy commented 11 months ago

https://github.com/zezo357/flutter_meedu_videoplayer/blob/master/package/example/lib/pages/custom_background.dart

check new release and example

@amaxcz @krida2000 hope it works well in your case

also for disabling controls you can set controlsEnabled to false , which will not put the ui controls and none of the touch/taps ones

amaxcz commented 11 months ago

@zezo357 works! finally! big thanks!