better_player 0.0.10

  • Readme
  • Changelog
  • Example
  • Installing
  • 86

Better Player #

pub package pub package pub package

Advanced video player based on video_player and Chewie. It's solves many typical use cases and it's easy to run.

Introduction #

This plugin is based on Chewie. Chewie is awesome plugin and works well in many cases. Better Player is a continuation of ideas introduced in Chewie. Better player fix common bugs, adds more configuration options and solves typical use cases.

Features:
✔️ Fixed common bugs
✔️ Added advanced configuration options
✔️ Refactored player controls
✔️ Playlist support
✔️ Video in ListView support
✔️ Subtitles support (HTML tags support)

Install #

  1. Add this to your pubspec.yaml file:
dependencies:
  better_player: ^0.0.10
  1. Install it
$ flutter packages get
  1. Import it
import 'package:better_player/better_player.dart';

Usage #

Check Example project.

Basic usage #

Create BetterPlayerDataSource and BetterPlayerController. You should do it in initState:

BetterPlayerController _betterPlayerController;

  @override
  void initState() {
    super.initState();
    BetterPlayerDataSource betterPlayerDataSource = BetterPlayerDataSource(
        BetterPlayerDataSourceType.NETWORK,
        "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4");
    _betterPlayerController = BetterPlayerController(
        BetterPlayerConfiguration(),
        betterPlayerDataSource: betterPlayerDataSource);
  }

Create BetterPlayer widget wrapped in AspectRatio widget:

  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 16 / 9,
      child: BetterPlayer(
        controller: _betterPlayerController,
      ),
    );
  }

Playlist #

To use playlist, you need to create dataset with multiple videos:

  List<BetterPlayerDataSource> createDataSet() {
    List dataSourceList = List<BetterPlayerDataSource>();
    dataSourceList.add(
      BetterPlayerDataSource(
        BetterPlayerDataSourceType.NETWORK,
        "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4",
      ),
    );
    dataSourceList.add(
      BetterPlayerDataSource(BetterPlayerDataSourceType.NETWORK,
          "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"),
    );
    dataSourceList.add(
      BetterPlayerDataSource(BetterPlayerDataSourceType.NETWORK,
          "http://sample.vodobox.com/skate_phantom_flex_4k/skate_phantom_flex_4k.m3u8"),
    );
    return dataSourceList;
  }

Then create BetterPlayerPlaylist:

@override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 16 / 9,
      child: BetterPlayerPlaylist(
          betterPlayerConfiguration: BetterPlayerConfiguration(),
          betterPlayerPlaylistConfiguration: const BetterPlayerPlaylistConfiguration(),
          betterPlayerDataSourceList: dataSourceList),
    );
  }

BetterPlayerListViewPlayer #

BetterPlayerListViewPlayer will auto play/pause video once video is visible on screen with playFraction. PlayFraction describes percent of video that must be visibile to play video. If playFraction is 0.8 then 80% of video height must be visible on screen to auto play video

 @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 16 / 9,
      child: BetterPlayerListVideoPlayer(
        BetterPlayerDataSource(
            BetterPlayerDataSourceType.NETWORK, videoListData.videoUrl),
        key: Key(videoListData.hashCode.toString()),
        playFraction: 0.8,
      ),
    );
  }

You can control BetterPlayerListViewPlayer with BetterPlayerListViewPlayerController. You need to pass BetterPlayerListViewPlayerController to BetterPlayerListVideoPlayer. See more here: https://github.com/jhomlala/betterplayer/blob/master/example/lib/video_list/video_list_widget.dart

Subtitles #

Subtitles can be configured from 3 different sources: file, network and memory. Subtitles source is passed in BetterPlayerDataSource:

Network subtitles:

    var dataSource = BetterPlayerDataSource(
      BetterPlayerDataSourceType.NETWORK,
      "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4",
      subtitles: BetterPlayerSubtitlesSource(
          type: BetterPlayerSubtitlesSourceType.NETWORK,
          url:
              "https://dl.dropboxusercontent.com/s/71nzjo2ux3evxqk/example_subtitles.srt"),
    );

File subtitles:

 var dataSource = BetterPlayerDataSource(
      BetterPlayerDataSourceType.FILE,
      "${directory.path}/testvideo.mp4",
      subtitles: BetterPlayerSubtitlesSource(
        type: BetterPlayerSubtitlesSourceType.FILE,
        url: "${directory.path}/example_subtitles.srt",
      ),
    );

BetterPlayerConfiguration #

You can provide configuration to your player when creating BetterPlayerController.

    var betterPlayerConfiguration = BetterPlayerConfiguration(
      autoPlay: true,
      looping: true,
      fullScreenByDefault: true,
    );

Possible configuration options:

    /// Play the video as soon as it's displayed
    final bool autoPlay;

    /// Start video at a certain position
    final Duration startAt;

    /// Whether or not the video should loop
    final bool looping;

    /// Weather or not to show the controls when initializing the widget.
    final bool showControlsOnInitialize;

    /// When the video playback runs  into an error, you can build a custom
    /// error message.
    final Widget Function(BuildContext context, String errorMessage) errorBuilder;

    /// The Aspect Ratio of the Video. Important to get the correct size of the
    /// video!
    ///
    /// Will fallback to fitting within the space allowed.
    final double aspectRatio;

    /// The placeholder is displayed underneath the Video before it is initialized
    /// or played.
    final Widget placeholder;

    /// A widget which is placed between the video and the controls
    final Widget overlay;

    /// Defines if the player will start in fullscreen when play is pressed
    final bool fullScreenByDefault;

    /// Defines if the player will sleep in fullscreen or not
    final bool allowedScreenSleep;


    /// Defines the system overlays visible after exiting fullscreen
    final List<SystemUiOverlay> systemOverlaysAfterFullScreen;

    /// Defines the set of allowed device orientations after exiting fullscreen
    final List<DeviceOrientation> deviceOrientationsAfterFullScreen;

    /// Defines a custom RoutePageBuilder for the fullscreen
    final BetterPlayerRoutePageBuilder routePageBuilder;

    /// Defines a event listener where video player events will be send
    final Function(BetterPlayerEvent) eventListener;

    ///Defines subtitles configuration
    final BetterPlayerSubtitlesConfiguration subtitlesConfiguration;

    ///Defines controls configuration
    final BetterPlayerControlsConfiguration controlsConfiguration;

BetterPlayerSubtitlesConfiguration #

You can provide subtitles configuration with this class. You should put BetterPlayerSubtitlesConfiguration in BetterPlayerConfiguration.

 var betterPlayerConfiguration = BetterPlayerConfiguration(
      subtitlesConfiguration: BetterPlayerSubtitlesConfiguration(
        fontSize: 20,
        fontColor: Colors.green,
      ),
    );

Possible configuration options:

 ///Subtitle font size
  final double fontSize;

  ///Subtitle font color
  final Color fontColor;

  ///Enable outline (border) of the text
  final bool outlineEnabled;

  ///Color of the outline stroke
  final Color outlineColor;

  ///Outline stroke size
  final double outlineSize;

  ///Font family of the subtitle
  final String fontFamily;

  ///Left padding of the subtitle
  final double leftPadding;

  ///Right padding of the subtitle
  final double rightPadding;

  ///Bottom padding of the subtitle
  final double bottomPadding;

BetterPlayerControlsConfiguration #

Configuration for player GUI. You should pass this configuration to BetterPlayerConfiguration.

ar betterPlayerConfiguration = BetterPlayerConfiguration(
      controlsConfiguration: BetterPlayerControlsConfiguration(
        textColor: Colors.black,
        iconsColor: Colors.black,
      ),
    );

Possible configuration options:

  ///Color of the control bars
  final Color controlBarColor;

  ///Color of texts
  final Color textColor;

  ///Color of icons
  final Color iconsColor;

  ///Icon of play
  final IconData playIcon;

  ///Icon of pause
  final IconData pauseIcon;

  ///Icon of mute
  final IconData muteIcon;

  ///Icon of unmute
  final IconData unMuteIcon;

  ///Icon of fullscreen mode enable
  final IconData fullscreenEnableIcon;

  ///Icon of fullscreen mode disable
  final IconData fullscreenDisableIcon;

  ///Cupertino only icon, icon of skip
  final IconData skipBackIcon;

  ///Cupertino only icon, icon of forward
  final IconData skipForwardIcon;

  ///Flag used to enable/disable fullscreen
  final bool enableFullscreen;

  ///Flag used to enable/disable mute
  final bool enableMute;

  ///Flag used to enable/disable progress texts
  final bool enableProgressText;

  ///Flag used to enable/disable progress bar
  final bool enableProgressBar;

  ///Flag used to enable/disable play-pause
  final bool enablePlayPause;

  ///Progress bar played color
  final Color progressBarPlayedColor;

  ///Progress bar circle color
  final Color progressBarHandleColor;

  ///Progress bar buffered video color
  final Color progressBarBufferedColor;

  ///Progress bar background color
  final Color progressBarBackgroundColor;

  ///Time to hide controls
  final Duration controlsHideTime;

  ///Custom controls, it will override Material/Cupertino controls
  final Widget customControls;

  ///Flag used to show/hide controls
  final bool showControls;

  ///Flag used to show controls on init
  final bool showControlsOnInitialize;

  ///Control bar height
  final double controlBarHeight;

  ///Default error widget text
  final String defaultErrorText;

  ///Default loading next video text
  final String loadingNextVideoText;

  ///Text displayed when asset displayed in player is live stream
  final String liveText;

  ///Live text color;
  final Color liveTextColor;

BetterPlayerPlaylistConfiguration #

Configure your playlist. Pass this object to BetterPlayerPlaylist

 var betterPlayerPlaylistConfiguration = BetterPlayerPlaylistConfiguration(
      loopVideos: false,
      nextVideoDelay: Duration(milliseconds: 5000),
    );

Possible configuration options:

  ///How long user should wait for next video
  final Duration nextVideoDelay;

  ///Should videos be looped
  final bool loopVideos;

BetterPlayerDataSource #

Define source for one video in your app.

    var dataSource = BetterPlayerDataSource(
      BetterPlayerDataSourceType.NETWORK,
      "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4",
      subtitles: BetterPlayerSubtitlesSource(
        type: BetterPlayerSubtitlesSourceType.FILE,
        url: "${directory.path}/example_subtitles.srt",
      ),
    );

Possible configuration options:

  ///Type of source of video
  final BetterPlayerDataSourceType type;

  ///Url of the video
  final String url;

  ///Subtitles configuration
  final BetterPlayerSubtitlesSource subtitles;

  ///Flag to determine if current data source is live stream
  final bool liveStream;

BetterPlayerSubtitlesSource #

Define source of subtitles in your video:

 var subtitles = BetterPlayerSubtitlesSource(
        type: BetterPlayerSubtitlesSourceType.FILE,
        url: "${directory.path}/example_subtitles.srt",
      );

Possible configuration options:

  ///Source type
  final BetterPlayerSubtitlesSourceType type;

  ///Url of the subtitles, used with file or network subtitles
  final String url;

  ///Content of subtitles, used when type is memory
  final String content;

Listen to video events #

You can listen to video player events like:

  PLAY,
  PAUSE,
  SEEK_TO,
  OPEN_FULLSCREEN,
  HIDE_FULLSCREEN,
  SET_VOLUME,
  PROGRESS,
  FINISHED,
  EXCEPTION,

After creating BetterPlayerController you can add event listener this way:

 _betterPlayerController.addEventsListener((event){
      print("Better player event: ${event.betterPlayerEventType}");
    });

Your event listener will ne auto-disposed on dispose time :)

More documentation #

https://pub.dev/documentation/better_player/latest/better_player/better_player-library.html

0.0.10 #

  • Added BetterPlayerListVideoPlayerController to control list video player

0.0.9 #

  • Fixed setState called after dispose
  • General bugfixes

0.0.8 #

  • Fixed buffering indicator issue on Android

0.0.7 #

  • Fixed progress bar scroll lag

0.0.6 #

  • Fixed video duration issue
  • Added HTML subtitles

0.0.5 #

  • Added reusable video player
  • Bug fixes

0.0.4 #

  • Changed 'settings' to 'configuration'
  • Removed unused parameters from configuration
  • Documentation update

0.0.3 #

  • Updated documentation

0.0.2 #

  • Moved example project from better_player_example to example

0.0.1 #

  • Initial release

example/lib/main.dart

import 'package:better_player/better_player.dart';
import 'package:better_player_example/playlist_page/playlist_page.dart';
import 'package:better_player_example/video_list/video_list_page.dart';
import 'package:flutter/material.dart';

import 'general_page/general_page.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Better player demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  MainPage({Key key}) : super(key: key);

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

class _MainPageState extends State<MainPage> {
  static const List<String> pageTitles = ["General", "Playlist", "Video list"];

  BetterPlayerController betterPlayerController;
  List dataSourceList = List<BetterPlayerDataSource>();
  int _selectedIndex = 0;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Better Player - ${pageTitles[_selectedIndex]}"),
      ),
      body: _getSelectedPage(),
      bottomNavigationBar: BottomNavigationBar(
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.business_center),
            title: Text(pageTitles[0]),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            title: Text(pageTitles[1]),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text(pageTitles[2]),
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.black,
        onTap: _onItemTapped,
      ),
    );
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  Widget _getSelectedPage() {
    if (_selectedIndex == 0) {
      return GeneralPage();
    } else if (_selectedIndex == 1) {
      return PlaylistPage();
    } else {
      return VideoListPage();
    }
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  better_player: ^0.0.10

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:better_player/better_player.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
81
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
80
Overall:
Weighted score of the above. [more]
86
Learn more about scoring.

We analyzed this package on Jul 13, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.15
  • Flutter: 1.17.5

Analysis suggestions

Package does not support Flutter platform Linux

Because:

  • package:better_player/better_player.dart that declares support for platforms: Android, iOS

Package does not support Flutter platform Web

Because:

  • package:better_player/better_player.dart that declares support for platforms: Android, iOS

Package does not support Flutter platform Windows

Because:

  • package:better_player/better_player.dart that declares support for platforms: Android, iOS

Package does not support Flutter platform macOS

Because:

  • package:better_player/better_player.dart that declares support for platforms: Android, iOS

Package not compatible with SDK dart

Because:

  • better_player that is a package requiring null.

Health suggestions

Fix lib/src/video_player/video_player_platform_interface.dart. (-1 points)

Analysis of lib/src/video_player/video_player_platform_interface.dart reported 2 hints:

line 207 col 12: Avoid using unnecessary statements.

line 219 col 25: Avoid using braces in interpolation when not needed.

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (flutter_widget_from_html_core).

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
flutter_widget_from_html_core ^0.3.3+2 0.3.3+4 0.4.2
flutter_widgets ^0.1.12 0.1.12
meta ^1.0.5 1.1.8 1.2.2
open_iconic_flutter >=0.3.0 <0.4.0 0.3.0
pedantic ^1.8.0 1.9.0 1.9.2
wakelock >=0.1.2 <0.2.0 0.1.4+2
Transitive dependencies
charcode 1.1.3
collection 1.14.12 1.14.13
csslib 0.16.1
html 0.14.0+3
matcher 0.12.8
path 1.7.0
quiver 2.1.3
sky_engine 0.0.99
source_span 1.7.0
stack_trace 1.9.5
term_glyph 1.1.0
typed_data 1.1.6 1.2.0
vector_math 2.0.8 2.1.0-nullsafety
Dev dependencies
flutter_test