GithubHelp home page GithubHelp logo

media-kit / media-kit Goto Github PK

View Code? Open in Web Editor NEW
1.1K 19.0 174.0 81.55 MB

A cross-platform video player & audio player for Flutter & Dart.

Home Page: https://github.com/media-kit/media-kit

License: MIT License

Dart 70.00% CMake 5.24% C 1.82% C++ 12.18% Swift 4.31% Makefile 0.82% Ruby 1.80% Objective-C 0.01% Java 2.80% Kotlin 0.01% HTML 0.18% Shell 0.82%
dart flutter libmpv c cpp media-player linux windows audio video android ios macos web java obj-c swift audio-player video-player hacktoberfest

media-kit's Introduction

A cross-platform video player & audio player for Flutter & Dart.

Github Actions


Sponsored with 💖 by

Stream Chat

Try the Flutter Chat tutorial



Stream Chat

Clever Apps for Film Professionals

Installation

package:media_kit is split into multiple packages to improve modularity & reduce bundle size.

For apps that need video playback:

dependencies:
  media_kit: ^1.1.11 # Primary package.
  media_kit_video: ^1.2.5 # For video rendering.
  media_kit_libs_video: ^1.0.5 # Native video dependencies.

For apps that need audio playback:

dependencies:
  media_kit: ^1.1.11 # Primary package.
  media_kit_libs_audio: ^1.0.5 # Native audio dependencies.

Notes:

Platforms

Platform Video Audio Notes Demo
Android Android 5.0 or above. Download
iOS iOS 9 or above. Download
macOS macOS 10.9 or above. Download
Windows Windows 7 or above. Download
GNU/Linux Any modern GNU/Linux distribution. Download
Web Any modern web browser. Visit
Android iOS
Android Android iOS iOS
macOS Windows
macOS Windows
GNU/Linux Web
GNU/Linux Web
  • ✅ Video playback
  • ✅ Audio playback
  • ✅ Cross platform
  • ✅ Wide format/codec support
  • ✅ Hardware/GPU acceleration
  • ✅ Playlist support with next/previous/jump/shuffle
  • ✅ Volume/Rate/Pitch change
  • ✅ Video/Audio/Subtitle track selection
  • ✅ External audio/subtitle track selection
  • ✅ HTTP headers
  • ✅ Video controls
  • ✅ Subtitle styling
  • ✅ Screenshot

TL;DR

A quick usage example.

import 'package:flutter/material.dart';

// Make sure to add following packages to pubspec.yaml:
// * media_kit
// * media_kit_video
// * media_kit_libs_video
import 'package:media_kit/media_kit.dart';                      // Provides [Player], [Media], [Playlist] etc.
import 'package:media_kit_video/media_kit_video.dart';          // Provides [VideoController] & [Video] etc.

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // Necessary initialization for package:media_kit.
  MediaKit.ensureInitialized();
  runApp(
    const MaterialApp(
      home: MyScreen(),
    ),
  );
}

class MyScreen extends StatefulWidget {
  const MyScreen({Key? key}) : super(key: key);
  @override
  State<MyScreen> createState() => MyScreenState();
}

class MyScreenState extends State<MyScreen> {
  // Create a [Player] to control playback.
  late final player = Player();
  // Create a [VideoController] to handle video output from [Player].
  late final controller = VideoController(player);

  @override
  void initState() {
    super.initState();
    // Play a [Media] or [Playlist].
    player.open(Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'));
  }

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.width * 9.0 / 16.0,
        // Use [Video] widget to display video output.
        child: Video(controller: controller),
      ),
    );
  }
}

Note: You may need to add required permissions to your project (only if required).

Guide

A usage guide for package:media_kit.

Tip: Use Ctrl + F to quickly search for things.

Contents

Initialization

MediaKit.ensureInitialized must be called before using the package:

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // Make sure to add the required packages to pubspec.yaml:
  // * https://github.com/media-kit/media-kit#installation
  // * https://pub.dev/packages/media_kit#installation
  MediaKit.ensureInitialized();
  runApp(const MyApp());
}

The method also has some optional arguments to customize the global behavior. To handle any initialization errors, this may be surrounded by try/catch.

Create a Player

A Player instance is used to start & control the playback of a media source e.g. URL or file.

final Player player = Player();

Additional options may be provided using the configuration argument in the constructor. In general situations, you will never require this.

final Player player = Player(
  configuration: PlayerConfiguration(
    // Supply your options:
    title: 'My awesome package:media_kit application',
    ready: () {
      print('The initialization is complete.');
    },
  ),
);

Dispose a Player

It is extremely important to release the allocated resources back to the system:

await player.dispose();

Open a Media or Playlist

A Playable can either be a Media or a Playlist.

  • Media: Single playback source (file or URL).
  • Playlist: Queue of playback sources (file or URL).

Use the Player.open method to load & start playback.

Media

final playable = Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4');
await player.open(playable);

Playlist

final playable = Playlist(
  [
    Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373709-603a7a89-2105-4e1b-a5a5-a6c3567c9a59.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4'),
  ],
);
await player.open(playable);

Notes:

  1. By default, this will automatically start playing the playable. This may be disabled as follows:
await player.open(
  playable,
  play: false,
);
  1. By default, the playlist will start at the index 0. This may be changed as follows:
final playable = Playlist(
  [
    Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373709-603a7a89-2105-4e1b-a5a5-a6c3567c9a59.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4'),
  ],
  // Declare the starting position.
  index: 0,
);
await player.open(playable);

Play, pause or play/pause

The 3 methods are:

await player.play();
await player.pause();
await player.playOrPause();

Stop

The stop method may be used to stop the playback of currently opened Media or Playlist.

await player.stop();

It does not release allocated resources back to the system (unlike dispose) & Player still stays usable.

Seek

Supply the final position to Player.seek method as Duration:

await player.seek(
  const Duration(
    minutes: 6,
    seconds: 9,
  ),
);

Loop or repeat

Three PlaylistModes are available:

  • PlaylistMode.none: End playback once end of the playlist is reached.
  • PlaylistMode.single: Indefinitely loop over the currently playing file in the playlist.
  • PlaylistMode.loop: Loop over the playlist & restart it from beginning once end is reached.
await player.setPlaylistMode(PlaylistMode.single);

Set volume, rate or pitch

Set the volume

This controls the loudness of audio output. The maximum volume is 100.0.

await player.setVolume(50.0);

Set the rate

This controls the playback speed.

await player.setRate(1.5);

Set the pitch

This controls the pitch of the audio output.

await player.setPitch(1.2);

Note: This requires pitch argument to be true in PlayerConfiguration.

Handle playback events

You can access or subscribe to Player's state changes.

Event handling is an extremely important part of media playback. It is used to show changes in the UI, handle errors, detect the occurrence of play/pause, end-of-file, position updates etc.

  • Player.stream.*: Provides access to Player's state as Stream(s).
  • Player.state.*: Provides access to Player's state directly (for instantaneous access).

A typical example will be:

player.stream.playing.listen(
  (bool playing) {
    if (playing) {
      // Playing.
    } else {
      // Paused.
    }
  },
);
player.stream.position.listen(
  (Duration position) {
    setState(() {
      // Update UI.
    });
  },
);

The following state(s) are available as events:

Type Name Description
Stream<Playlist> playlist Currently opened media sources.
Stream<bool> playing Whether playing or not.
Stream<bool> completed Whether end of currently playing media source has been reached.
Stream<Duration> position Current playback position.
Stream<Duration> duration Current playback duration.
Stream<double> volume Current volume.
Stream<double> rate Current playback rate.
Stream<double> pitch Current pitch.
Stream<bool> buffering Whether buffering or not.
Stream<Duration> buffer Current buffer position. This indicates how much of the stream has been decoded & cached by the demuxer.
Stream<PlaylistMode> playlistMode Current playlist mode.
Stream<AudioParams> audioParams Audio parameters of the currently playing media source e.g. sample rate, channels, etc.
Stream<VideoParams> videoParams Video parameters of the currently playing media source e.g. width, height, rotation etc.
Stream<double?> audioBitrate Audio bitrate of the currently playing media source.
Stream<AudioDevice> audioDevice Currently selected audio device.
Stream<List<AudioDevice>> audioDevices Currently available audio devices.
Stream<Track> track Currently selected video, audio and subtitle track.
Stream<Tracks> tracks Currently available video, audio and subtitle tracks.
Stream<int> width Currently playing video's width.
Stream<int> height Currently playing video's height.
Stream<int> subtitle Currently displayed subtitle.
Stream<PlayerLog> log Internal logs.
Stream<String> error Error messages. This may be used to handle & display errors to the user.

Shuffle the queue

You may find the requirement to shuffle the Playlist you open'd in Player, like some music players do.

await player.setShuffle(true);

Note: This option is reset upon the next Player.open call.

Use HTTP headers

Declare the httpHeaders argument in Media constructor. It takes the HTTP headers as Map<String, String>.

final playable = Media(
  'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
  httpHeaders: {
    'Foo': 'Bar',
    'Accept': '*/*',
    'Range': 'bytes=0-',
  },
);

Use extras to store additional data with Media

The extras argument may be utilized to store additional data with a Media in form of Map<String, dynamic>.

final playable = Media(
  'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
  extras: {
    'track': '9',
    'year': '2012',
    'title': 'Courtesy Call',
    'artist': 'Thousand Foot Krutch',
    'album': 'The End Is Where We Begin',
  },
);

Modify Player's queue

You can add or remove (etc.) a Media in an already playing Playlist:

Add

Add a new Media to the back of the queue:

await player.add(Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'));

Remove

Remove any item from the queue:

await player.remove(0);

Move

Move any item in the queue from one position to another:

await player.move(6, 9);

Go to next, previous or any other position in queue

Skip to the next queue item

await player.next();

Skip to the previous queue item

await player.previous();

Skip to any other queue item

await player.jump(5);

Select video, audio or subtitle track

A media source may contain multiple video, audio or subtitle tracks e.g. for multiple languages. Available video, audio or subtitle tracks are notified through Player's state. See "Handle playback events" section for related information.

By default, video, audio & subtitle track is selected automatically i.e. VideoTrack.auto(), AudioTrack.auto() & SubtitleTrack.auto().

Automatic selection

await player.setVideoTrack(VideoTrack.auto());

await player.setAudioTrack(AudioTrack.auto());

await player.setSubtitleTrack(SubtitleTrack.auto());

Disable track

This may be used to essentially disable video output, disable audio output or stop rendering of subtitles etc.

await player.setVideoTrack(VideoTrack.no());

await player.setAudioTrack(AudioTrack.no());

await player.setSubtitleTrack(SubtitleTrack.no());

Select custom track

  • Retrieve currently available tracks:
List<VideoTrack> videos = player.state.tracks.video;
List<AudioTrack> audios = player.state.tracks.audio;
List<SubtitleTrack> subtitles = player.state.tracks.subtitle;

// Get notified as [Stream]:
player.stream.tracks.listen((event) {
  List<VideoTrack> videos = event.video;
  List<AudioTrack> audios = event.audio;
  List<SubtitleTrack> subtitles = event.subtitle;
});
  • Select the track:
await player.setVideoTrack(videos[0]);
await player.setAudioTrack(audios[1]);
await player.setSubtitleTrack(subtitles[2]);
  • Get notified about currently selected track:
VideoTrack video = player.state.track.video;
AudioTrack audio = player.state.track.audio;
SubtitleTrack subtitle = player.state.track.subtitle;

// Get notified as [Stream]:
player.stream.track.listen((event) {
  VideoTrack video = event.video;
  AudioTrack audio = event.audio;
  SubtitleTrack subtitle = event.subtitle;
});

Select audio device

Available audio devices are notified through Player's state. See "Handle playback events" section for related information.

By default, audio device is selected automatically i.e. AudioDevice.auto().

Default selection

await player.setAudioDevice(AudioDevice.auto());

Disable audio output

await player.setAudioDevice(AudioDevice.no());

Select custom audio device

  • Retrieve currently available audio devices:
List<AudioDevice> devices = player.state.audioDevices;

// Get notified as [Stream]:
player.stream.audioDevices.listen((event) {
  List<AudioDevice> devices = event;
});
  • Select the audio device:
await player.setAudioDevice(devices[1]);
  • Get notified about currently selected audio device:
AudioDevice device = player.state.audioDevice;

// Get notified as [Stream]:
player.stream.audioDevice.listen((event) {
  AudioDevice device = event;
});

Display the video

The existing "TL;DR example" should provide you better idea.

For displaying the video inside Flutter UI, you must:

  • Create VideoController
    • Pass the Player you already have.
  • Create Video widget
    • Pass the VideoController you already have.

The code is easier to understand:

class _MyScreenState extends State<MyScreen> {
  late final Player player = Player();
  late final VideoController controller = VideoController(player);

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Video(
        controller: controller,
      ),
    );
  }
}

The video playback uses hardware acceleration i.e. GPU by default.

Additional options may be provided using the configuration argument in the constructor. In general situations, you will never require this.

final VideoController player = VideoController(
  player,
  configuration: const VideoControllerConfiguration(
    // Supply your options:
    enableHardwareAcceleration: true,      // default: true
    width: 640,                            // default: null
    height: 480,                           // default: null
    // The in-code comments is best place to know more about these options:
    // https://github.com/media-kit/media-kit/blob/main/media_kit_video/lib/src/video_controller/video_controller.dart
  ),
);

Capture screenshot

The screenshot method takes the snapshot of the current video frame & returns encoded image bytes as Uint8List.

final Uint8List? screenshot = await player.screenshot();

Additionally format argument may be specified to change the encoding format. Following formats are supported:

  • image/jpeg: Returns a JPEG encoded image.
  • image/png: Returns a PNG encoded image.
  • null: Returns BGRA pixel buffer.

Customize subtitles

SubtitleViewConfiguration can be passed to the Video widget for customizing the subtitles. The code is easier to understand:

Notably, TextStyle, TextAlign & EdgeInsetsGeometry can be provided.

Video(
  controller: controller,
  subtitleViewConfiguration: const SubtitleViewConfiguration(
    style: TextStyle(
      height: 1.4,
      fontSize: 24.0,
      letterSpacing: 0.0,
      wordSpacing: 0.0,
      color: Color(0xffffffff),
      fontWeight: FontWeight.normal,
      backgroundColor: Color(0xaa000000),
    ),
    textAlign: TextAlign.center,
    padding: EdgeInsets.all(24.0),
  ),
);
subtitles.mp4

Load external subtitle track

The SubtitleTrack.uri constructor can be used to load external subtitle track with URI e.g. SRT, WebVTT etc. The code is easier to understand:

await player.setSubtitleTrack(
  SubtitleTrack.uri(
    'https://www.iandevlin.com/html5test/webvtt/upc-video-subtitles-en.vtt',
    title: 'English',
    language: 'en',
  ),
);

The SubtitleTrack.data constructor can be used to load external subtitle track with data e.g. SRT, WebVTT etc. The code is easier to understand:

player.setSubtitleTrack(
  SubtitleTrack.data(
    '''WEBVTT FILE

1
00:00:03.500 --> 00:00:05.000 D:vertical A:start
Everyone wants the most from life

2
00:00:06.000 --> 00:00:09.000 A:start
Like internet experiences that are rich <b>and</b> entertaining

3
00:00:11.000 --> 00:00:14.000 A:end
Phone conversations where people truly <c.highlight>connect</c>

4
00:00:14.500 --> 00:00:18.000
Your favourite TV programmes ready to watch at the touch of a button

5
00:00:19.000 --> 00:00:24.000
Which is why we are bringing TV, internet and phone together in <c.highlight>one</c> super package

6
00:00:24.500 --> 00:00:26.000
<c.highlight>One</c> simple way to get everything

7
00:00:26.500 --> 00:00:27.500 L:12%
UPC

8
00:00:28.000 --> 00:00:30.000 L:75%
Simply for <u>everyone</u>
''',
    title: 'English',
    language: 'en',
  ),
);

Load external audio track

The AudioTrack.uri constructor can be used to load external audio track with URI. The code is easier to understand:

await player.setAudioTrack(
  AudioTrack.uri(
    'https://www.iandevlin.com/html5test/webvtt/v/upc-tobymanley.mp4',
    title: 'English',
    language: 'en',
  ),
);

Video controls

package:media_kit provides highly-customizable pre-built video controls for usage.

Apart from theming, layout can be customized, position of buttons can be modified, custom buttons can be created etc. Necessary features like fullscreen, keyboard shortcuts & swipe-based controls are also supported by default.

MaterialDesktopVideoControls MaterialVideoControls
  • Video widget provides controls argument to display & customize video controls.
  • By default, AdaptiveVideoControls are used.

Types

Type Description
AdaptiveVideoControls Selects MaterialVideoControls, CupertinoVideoControls etc. based on platform.
MaterialVideoControls Material Design video controls.
MaterialDesktopVideoControls Material Design video controls for desktop.
CupertinoVideoControls iOS-style video controls.
NoVideoControls Disable video controls i.e. only render video output.
Custom Provide custom builder for video controls.

Select existing video controls

Modify the controls argument. For advanced theming of existing video controls, see theming & modifying video controls section.

Scaffold(
  body: Video(
    controller: controller,
    // Select [MaterialVideoControls].
    controls: MaterialVideoControls,
  ),
);
Scaffold(
  body: Video(
    controller: controller,
    // Select [CupertinoVideoControls].
    controls: CupertinoVideoControls,
  ),
);

Build custom video controls

Pass custom builder Widget Function(BuildContext, VideoController) as controls argument.

Scaffold(
  body: Video(
    controller: controller,
    // Provide custom builder for controls.
    controls: (state) {
      return Center(
        child: IconButton(
          onPressed: () {
            state.widget.controller.player.playOrPause();
          },
          icon: StreamBuilder(
            stream: state.widget.controller.player.stream.playing,
            builder: (context, playing) => Icon(
              playing.data == true ? Icons.pause : Icons.play_arrow,
            ),
          ),
          // It's not necessary to use [StreamBuilder] or to use [Player] & [VideoController] from [state].
          // [StreamSubscription]s can be made inside [initState] of this widget.
        ),
      );
    },
  ),
);

Use & modify video controls

AdaptiveVideoControls
MaterialVideoControls
  • Material Design video controls.
  • Theming:
    • Use MaterialVideoControlsTheme widget.
    • Video widget(s) in the child tree will follow the specified theme:
// Wrap [Video] widget with [MaterialVideoControlsTheme].
MaterialVideoControlsTheme(
  normal: MaterialVideoControlsThemeData(
    // Modify theme options:
    buttonBarButtonSize: 24.0,
    buttonBarButtonColor: Colors.white,
    // Modify top button bar:
    topButtonBar: [
      const Spacer(),
      MaterialDesktopCustomButton(
        onPressed: () {
          debugPrint('Custom "Settings" button pressed.');
        },
        icon: const Icon(Icons.settings),
      ),
    ],
  ),
  fullscreen: const MaterialVideoControlsThemeData(
    // Modify theme options:
    displaySeekBar: false,
    automaticallyImplySkipNextButton: false,
    automaticallyImplySkipPreviousButton: false,
  ),
  child: Scaffold(
    body: Video(
      controller: controller,
    ),
  ),
);
  • Related widgets (may be used in primaryButtonBar, topButtonBar & bottomButtonBar):
    • MaterialPlayOrPauseButton
    • MaterialSkipNextButton
    • MaterialSkipPreviousButton
    • MaterialFullscreenButton
    • MaterialCustomButton
    • MaterialPositionIndicator
MaterialDesktopVideoControls
  • Material Design video controls for desktop.
  • Theming:
    • Use MaterialDesktopVideoControlsTheme widget.
    • Video widget(s) in the child tree will follow the specified theme:
// Wrap [Video] widget with [MaterialDesktopVideoControlsTheme].
MaterialDesktopVideoControlsTheme(
  normal: MaterialDesktopVideoControlsThemeData(
    // Modify theme options:
    seekBarThumbColor: Colors.blue,
    seekBarPositionColor: Colors.blue,
    toggleFullscreenOnDoublePress: false,
    // Modify top button bar:
    topButtonBar: [
      const Spacer(),
      MaterialDesktopCustomButton(
        onPressed: () {
          debugPrint('Custom "Settings" button pressed.');
        },
        icon: const Icon(Icons.settings),
      ),
    ],
    // Modify bottom button bar:
    bottomButtonBar: const [
      Spacer(),
      MaterialDesktopPlayOrPauseButton(),
      Spacer(),
    ],
  ),
  fullscreen: const MaterialDesktopVideoControlsThemeData(),
  child: Scaffold(
    body: Video(
      controller: controller,
    ),
  ),
);
  • Related widgets (may be used in primaryButtonBar, topButtonBar & bottomButtonBar):
    • MaterialDesktopPlayOrPauseButton
    • MaterialDesktopSkipNextButton
    • MaterialDesktopSkipPreviousButton
    • MaterialDesktopFullscreenButton
    • MaterialDesktopCustomButton
    • MaterialDesktopVolumeButton
    • MaterialDesktopPositionIndicator
  • Keyboard shortcuts may be modified using keyboardShortcuts argument. Default ones are listed below:
Shortcut Action
Media Play Button Play
Media Pause Button Pause
Media Play/Pause Button Play/Pause
Media Next Track Button Skip Next
Media Previous Track Button Skip Previous
Space Play/Pause
J Seek 10s Behind
I Seek 10s Ahead
Arrow Left Seek 2s Behind
Arrow Right Seek 2s Ahead
Arrow Up Increase Volume 5%
Arrow Down Decrease Volume 5%
F Enter/Exit Fullscreen
Escape Exit Fullscreen
CupertinoVideoControls
  • iOS-style video controls.
  • Theming:
    • Use CupertinoVideoControlsTheme widget.
    • Video widget(s) in the child tree will follow the specified theme:
// Wrap [Video] widget with [CupertinoVideoControlsTheme].
CupertinoVideoControlsTheme(
  normal: const CupertinoVideoControlsThemeData(
    // W.I.P.
  ),
  fullscreen: const CupertinoVideoControlsThemeData(
    // W.I.P.
  ),
  child: Scaffold(
    body: Video(
      controller: controller,
    ),
  ),
);
NoVideoControls
  • Disable video controls i.e. only render video output.
  • Theming:
    • No theming applicable.

Next steps

This guide follows a tutorial-like structure & covers nearly all features that package:media_kit offers. However, it is not complete by any means. You are free to improve this page & add more documentation, which newcomers may find helpful. The following places can help you learn more:

Goals

package:media_kit is a library for Flutter & Dart which provides video & audio playback.

  • Strong: Supports most video & audio codecs.
  • Performant:
    • Handles multiple FHD videos flawlessly.
    • Rendering is GPU-powered (hardware accelerated).
    • 4K / 8K 60 FPS is supported.
  • Stable: Implementation is well-tested & used across number of intensive media playback related apps.
  • Feature Proof: A simple usage API while offering a large number of features to target multitude of apps.
  • Modular: Project is split into a number of packages for reducing bundle size.
  • Cross Platform: Implementation works on all platforms supported by Flutter & Dart:
    • Android
    • iOS
    • macOS
    • Windows
    • GNU/Linux
    • Web
  • Flexible Architecture:
    • Major part of implementation (80%+) is in 100% Dart (FFI) & shared across platforms.
      • Makes the behavior of library same & more predictable across platforms.
      • Makes development & implementation of new features easier & faster.
      • Avoids separate maintenance of native implementation for each platform.
    • Only video embedding code is platform-specific & part of separate package.

You may see project's architecture & implementation details for further information.

The project aims to meet demands of the community, this includes:

  1. Holding accountability.
  2. Ensuring timely maintenance.

Supported Formats

A wide variety of formats & codecs are supported. Complete list may be found below:

3dostr          3DO STR
4xm             4X Technologies
aa              Audible AA format files
aac             raw ADTS AAC (Advanced Audio Coding)
aax             CRI AAX
ac3             raw AC-3
ace             tri-Ace Audio Container
acm             Interplay ACM
act             ACT Voice file format
adf             Artworx Data Format
adp             ADP
ads             Sony PS2 ADS
adx             CRI ADX
aea             MD STUDIO audio
afc             AFC
aiff            Audio IFF
aix             CRI AIX
alaw            PCM A-law
alias_pix       Alias/Wavefront PIX image
alp             LEGO Racers ALP
amr             3GPP AMR
amrnb           raw AMR-NB
amrwb           raw AMR-WB
anm             Deluxe Paint Animation
apac            raw APAC
apc             CRYO APC
ape             Monkey's Audio
apm             Ubisoft Rayman 2 APM
apng            Animated Portable Network Graphics
aptx            raw aptX
aptx_hd         raw aptX HD
aqtitle         AQTitle subtitles
argo_asf        Argonaut Games ASF
argo_brp        Argonaut Games BRP
argo_cvg        Argonaut Games CVG
asf             ASF (Advanced / Active Streaming Format)
asf_o           ASF (Advanced / Active Streaming Format)
ass             SSA (SubStation Alpha) subtitle
ast             AST (Audio Stream)
au              Sun AU
av1             AV1 Annex B
avi             AVI (Audio Video Interleaved)
avr             AVR (Audio Visual Research)
avs             Argonaut Games Creature Shock
avs2            raw AVS2-P2/IEEE1857.4
avs3            raw AVS3-P2/IEEE1857.10
bethsoftvid     Bethesda Softworks VID
bfi             Brute Force & Ignorance
bfstm           BFSTM (Binary Cafe Stream)
bin             Binary text
bink            Bink
binka           Bink Audio
bit             G.729 BIT file format
bitpacked       Bitpacked
bmp_pipe        piped bmp sequence
bmv             Discworld II BMV
boa             Black Ops Audio
bonk            raw Bonk
brender_pix     BRender PIX image
brstm           BRSTM (Binary Revolution Stream)
c93             Interplay C93
caf             Apple CAF (Core Audio Format)
cavsvideo       raw Chinese AVS (Audio Video Standard)
cdg             CD Graphics
cdxl            Commodore CDXL video
cine            Phantom Cine
codec2          codec2 .c2 demuxer
codec2raw       raw codec2 demuxer
concat          Virtual concatenation script
cri_pipe        piped cri sequence
dash            Dynamic Adaptive Streaming over HTTP
data            raw data
daud            D-Cinema audio
dcstr           Sega DC STR
dds_pipe        piped dds sequence
derf            Xilam DERF
dfa             Chronomaster DFA
dfpwm           raw DFPWM1a
dhav            Video DAV
dirac           raw Dirac
dnxhd           raw DNxHD (SMPTE VC-3)
dpx_pipe        piped dpx sequence
dsf             DSD Stream File (DSF)
dshow           DirectShow capture
dsicin          Delphine Software International CIN
dss             Digital Speech Standard (DSS)
dts             raw DTS
dtshd           raw DTS-HD
dv              DV (Digital Video)
dvbsub          raw dvbsub
dvbtxt          dvbtxt
dxa             DXA
ea              Electronic Arts Multimedia
ea_cdata        Electronic Arts cdata
eac3            raw E-AC-3
epaf            Ensoniq Paris Audio File
exr_pipe        piped exr sequence
f32be           PCM 32-bit floating-point big-endian
f32le           PCM 32-bit floating-point little-endian
f64be           PCM 64-bit floating-point big-endian
f64le           PCM 64-bit floating-point little-endian
ffmetadata      FFmpeg metadata in text
film_cpk        Sega FILM / CPK
filmstrip       Adobe Filmstrip
fits            Flexible Image Transport System
flac            raw FLAC
flic            FLI/FLC/FLX animation
flv             FLV (Flash Video)
frm             Megalux Frame
fsb             FMOD Sample Bank
fwse            Capcom's MT Framework sound
g722            raw G.722
g723_1          G.723.1
g726            raw big-endian G.726 ("left aligned")
g726le          raw little-endian G.726 ("right aligned")
g729            G.729 raw format demuxer
gdigrab         GDI API Windows frame grabber
gdv             Gremlin Digital Video
gem_pipe        piped gem sequence
genh            GENeric Header
gif             CompuServe Graphics Interchange Format (GIF)
gif_pipe        piped gif sequence
gsm             raw GSM
gxf             GXF (General eXchange Format)
h261            raw H.261
h263            raw H.263
h264            raw H.264 video
hca             CRI HCA
hcom            Macintosh HCOM
hdr_pipe        piped hdr sequence
hevc            raw HEVC video
hls             Apple HTTP Live Streaming
hnm             Cryo HNM v4
ico             Microsoft Windows ICO
idcin           id Cinematic
idf             iCE Draw File
iff             IFF (Interchange File Format)
ifv             IFV CCTV DVR
ilbc            iLBC storage
image2          image2 sequence
image2pipe      piped image2 sequence
imf             IMF (Interoperable Master Format)
ingenient       raw Ingenient MJPEG
ipmovie         Interplay MVE
ipu             raw IPU Video
ircam           Berkeley/IRCAM/CARL Sound Format
iss             Funcom ISS
iv8             IndigoVision 8000 video
ivf             On2 IVF
ivr             IVR (Internet Video Recording)
j2k_pipe        piped j2k sequence
jacosub         JACOsub subtitle format
jpeg_pipe       piped jpeg sequence
jpegls_pipe     piped jpegls sequence
jpegxl_pipe     piped jpegxl sequence
jv              Bitmap Brothers JV
kux             KUX (YouKu)
kvag            Simon & Schuster Interactive VAG
laf             LAF (Limitless Audio Format)
lavfi           Libavfilter virtual input device
live_flv        live RTMP FLV (Flash Video)
lmlm4           raw lmlm4
loas            LOAS AudioSyncStream
lrc             LRC lyrics
luodat          Video CCTV DAT
lvf             LVF
lxf             VR native stream (LXF)
m4v             raw MPEG-4 video
matroska,webm   Matroska / WebM
mca             MCA Audio Format
mcc             MacCaption
mgsts           Metal Gear Solid: The Twin Snakes
microdvd        MicroDVD subtitle format
mjpeg           raw MJPEG video
mjpeg_2000      raw MJPEG 2000 video
mlp             raw MLP
mlv             Magic Lantern Video (MLV)
mm              American Laser Games MM
mmf             Yamaha SMAF
mods            MobiClip MODS
moflex          MobiClip MOFLEX
mov,mp4,m4a,3gp,3g2,mj2 QuickTime / MOV
mp3             MP2/3 (MPEG audio layer 2/3)
mpc             Musepack
mpc8            Musepack SV8
mpeg            MPEG-PS (MPEG-2 Program Stream)
mpegts          MPEG-TS (MPEG-2 Transport Stream)
mpegtsraw       raw MPEG-TS (MPEG-2 Transport Stream)
mpegvideo       raw MPEG video
mpjpeg          MIME multipart JPEG
mpl2            MPL2 subtitles
mpsub           MPlayer subtitles
msf             Sony PS3 MSF
msnwctcp        MSN TCP Webcam stream
msp             Microsoft Paint (MSP))
mtaf            Konami PS2 MTAF
mtv             MTV
mulaw           PCM mu-law
musx            Eurocom MUSX
mv              Silicon Graphics Movie
mvi             Motion Pixels MVI
mxf             MXF (Material eXchange Format)
mxg             MxPEG clip
nc              NC camera feed
nistsphere      NIST SPeech HEader REsources
nsp             Computerized Speech Lab NSP
nsv             Nullsoft Streaming Video
nut             NUT
nuv             NuppelVideo
obu             AV1 low overhead OBU
ogg             Ogg
oma             Sony OpenMG audio
paf             Amazing Studio Packed Animation File
pam_pipe        piped pam sequence
pbm_pipe        piped pbm sequence
pcx_pipe        piped pcx sequence
pfm_pipe        piped pfm sequence
pgm_pipe        piped pgm sequence
pgmyuv_pipe     piped pgmyuv sequence
pgx_pipe        piped pgx sequence
phm_pipe        piped phm sequence
photocd_pipe    piped photocd sequence
pictor_pipe     piped pictor sequence
pjs             PJS (Phoenix Japanimation Society) subtitles
pmp             Playstation Portable PMP
png_pipe        piped png sequence
pp_bnk          Pro Pinball Series Soundbank
ppm_pipe        piped ppm sequence
psd_pipe        piped psd sequence
psxstr          Sony Playstation STR
pva             TechnoTrend PVA
pvf             PVF (Portable Voice Format)
qcp             QCP
qdraw_pipe      piped qdraw sequence
qoi_pipe        piped qoi sequence
r3d             REDCODE R3D
rawvideo        raw video
realtext        RealText subtitle format
redspark        RedSpark
rka             RKA (RK Audio)
rl2             RL2
rm              RealMedia
roq             id RoQ
rpl             RPL / ARMovie
rsd             GameCube RSD
rso             Lego Mindstorms RSO
rtp             RTP input
rtsp            RTSP input
s16be           PCM signed 16-bit big-endian
s16le           PCM signed 16-bit little-endian
s24be           PCM signed 24-bit big-endian
s24le           PCM signed 24-bit little-endian
s32be           PCM signed 32-bit big-endian
s32le           PCM signed 32-bit little-endian
s337m           SMPTE 337M
s8              PCM signed 8-bit
sami            SAMI subtitle format
sap             SAP input
sbc             raw SBC (low-complexity subband codec)
sbg             SBaGen binaural beats script
scc             Scenarist Closed Captions
scd             Square Enix SCD
sdns            Xbox SDNS
sdp             SDP
sdr2            SDR2
sds             MIDI Sample Dump Standard
sdx             Sample Dump eXchange
ser             SER (Simple uncompressed video format for astronomical capturing)
sga             Digital Pictures SGA
sgi_pipe        piped sgi sequence
shn             raw Shorten
siff            Beam Software SIFF
simbiosis_imx   Simbiosis Interactive IMX
sln             Asterisk raw pcm
smjpeg          Loki SDL MJPEG
smk             Smacker
smush           LucasArts Smush
sol             Sierra SOL
sox             SoX native
spdif           IEC 61937 (compressed data in S/PDIF)
srt             SubRip subtitle
stl             Spruce subtitle format
subviewer       SubViewer subtitle format
subviewer1      SubViewer v1 subtitle format
sunrast_pipe    piped sunrast sequence
sup             raw HDMV Presentation Graphic Stream subtitles
svag            Konami PS2 SVAG
svg_pipe        piped svg sequence
svs             Square SVS
swf             SWF (ShockWave Flash)
tak             raw TAK
tedcaptions     TED Talks captions
thp             THP
tiertexseq      Tiertex Limited SEQ
tiff_pipe       piped tiff sequence
tmv             8088flex TMV
truehd          raw TrueHD
tta             TTA (True Audio)
tty             Tele-typewriter
txd             Renderware TeXture Dictionary
ty              TiVo TY Stream
u16be           PCM unsigned 16-bit big-endian
u16le           PCM unsigned 16-bit little-endian
u24be           PCM unsigned 24-bit big-endian
u24le           PCM unsigned 24-bit little-endian
u32be           PCM unsigned 32-bit big-endian
u32le           PCM unsigned 32-bit little-endian
u8              PCM unsigned 8-bit
v210            Uncompressed 4:2:2 10-bit
v210x           Uncompressed 4:2:2 10-bit
vag             Sony PS2 VAG
vbn_pipe        piped vbn sequence
vc1             raw VC-1
vc1test         VC-1 test bitstream
vfwcap          VfW video capture
vidc            PCM Archimedes VIDC
vividas         Vividas VIV
vivo            Vivo
vmd             Sierra VMD
vobsub          VobSub subtitle format
voc             Creative Voice
vpk             Sony PS2 VPK
vplayer         VPlayer subtitles
vqf             Nippon Telegraph and Telephone Corporation (NTT) TwinVQ
w64             Sony Wave64
wady            Marble WADY
wav             WAV / WAVE (Waveform Audio)
wavarc          Waveform Archiver
wc3movie        Wing Commander III movie
webm_dash_manifest WebM DASH Manifest
webp_pipe       piped webp sequence
webvtt          WebVTT subtitle
wsaud           Westwood Studios audio
wsd             Wideband Single-bit Data (WSD)
wsvqa           Westwood Studios VQA
wtv             Windows Television (WTV)
wv              WavPack
wve             Psion 3 audio
xa              Maxis XA
xbin            eXtended BINary text (XBIN)
xbm_pipe        piped xbm sequence
xmd             Konami XMD
xmv             Microsoft XMV
xpm_pipe        piped xpm sequence
xvag            Sony PS3 XVAG
xwd_pipe        piped xwd sequence
xwma            Microsoft xWMA
yop             Psygnosis YOP
yuv4mpegpipe    YUV4MPEG pipe

Notes:

  • The list contains the supported formats (& not containers).
    • A video/audio format may be present in a number of containers.
    • e.g. an MP4 file generally contains H264 video stream.
  • On the web, format support depends upon the web browser.
    • It happens to be extremely limited as compared to native platforms.

Permissions

You may need to declare & request internet access or file-system permissions depending upon platform.

Android

Edit android/app/src/main/AndroidManifest.xml to add the following permissions inside <manifest> tag:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.app">
    <application
      ...
      />
    </application>
    <!--
      Internet access permissions.
      -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--
      Media access permissions.
      Android 13 or higher.
      https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions
      -->
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
    <!--
      Storage access permissions.
      Android 12 or lower.
      -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

Use package:permission_handler to request access at runtime:

if (/* Android 13 or higher. */) {
  // Video permissions.
  if (await Permission.videos.isDenied || await Permission.videos.isPermanentlyDenied) {
    final state = await Permission.videos.request();
    if (!state.isGranted) {
      await SystemNavigator.pop();
    }
  }
  // Audio permissions.
  if (await Permission.audio.isDenied || await Permission.audio.isPermanentlyDenied) {
    final state = await Permission.audio.request();
    if (!state.isGranted) {
      await SystemNavigator.pop();
    }
  }
} else {
  if (await Permission.storage.isDenied || await Permission.storage.isPermanentlyDenied) {
    final state = await Permission.storage.request();
    if (!state.isGranted) {
      await SystemNavigator.pop();
    }
  }
}

iOS

Edit ios/Runner/Info-Release.plist, ios/Runner/Info-Profile.plist, ios/Runner/Info-Debug.plist:

Enable internet access

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Windows

N/A

macOS

Edit macos/Runner/Release.entitlements & macos/Runner/DebugProfile.entitlements:

Enable internet access

<key>com.apple.security.network.client</key>
<true/>

Disable sand-box to access files

<key>com.apple.security.app-sandbox</key>
<false/>

GNU/Linux

N/A

Web

N/A

Notes

Android

N/A

iOS

N/A

Windows

N/A

macOS

During the build phase, the following warnings are not critical and cannot be silenced:

#import "Headers/media_kit_video-Swift.h"
        ^
/path/to/media_kit/media_kit_test/build/macos/Build/Products/Debug/media_kit_video/media_kit_video.framework/Headers/media_kit_video-Swift.h:270:31: warning: 'objc_ownership' only applies to Objective-C object or block pointer types; type here is 'CVPixelBufferRef' (aka 'struct __CVBuffer *')
- (CVPixelBufferRef _Nullable __unsafe_unretained)copyPixelBuffer SWIFT_WARN_UNUSED_RESULT;
# 1 "<command line>" 1
 ^
<command line>:20:9: warning: 'POD_CONFIGURATION_DEBUG' macro redefined
#define POD_CONFIGURATION_DEBUG 1 DEBUG=1
        ^
#define POD_CONFIGURATION_DEBUG 1
        ^

GNU/Linux

Install libmpv

System shared libraries from distribution specific user-installed packages are used by-default. This is how GNU/Linux works. You can install these as follows:

Ubuntu/Debian
sudo apt install libmpv-dev mpv
Packaging

There are other ways to bundle these within your app package e.g. within Snap or Flatpak. Few examples:

Utilize mimalloc

You should consider replacing the default memory allocator with mimalloc for avoiding memory leaks.

This is as simple as adding one line to linux/CMakeLists.txt:

target_link_libraries(${BINARY_NAME} PRIVATE ${MIMALLOC_LIB})

Web

On the web, libmpv is not used. Video & audio playback is handled by embedding HTML <video> element. The format support depends upon the web browser. It happens to be extremely limited as compared to native platforms.

Architecture

package:media_kit

Click on the zoom button on top-right or pinch inside.

%%{
  init: {
    'themeVariables': {
      'fontFamily': 'BlinkMacSystemFont, Segoe UI, Noto Sans, Helvetica, Arial, Apple Color Emoji, Segoe UI Emoji'
    }
  }
}%%
classDiagram

  Player *-- PlatformPlayer
  PlatformPlayer <|-- NativePlayer
  PlatformPlayer <|-- WebPlayer
  PlatformPlayer *-- PlayerState
  PlatformPlayer *-- PlayerStream
  PlatformPlayer o-- PlayerConfiguration

  NativePlayer <.. NativeLibrary
  NativePlayer <.. Initializer
  Initializer o-- InitializerIsolate
  Initializer o-- InitializerNativeEventLoop

  Playable <.. Media
  Playable <.. Playlist

  class Initializer {
    +create(path: String, callback: Function, options: Map<String, String>): Future<Pointer<mpv_handle>>
    +dispose(handle: Pointer<mpv_handle>)
  }

  class InitializerIsolate {
    +create(path: String, callback: Function, options: Map<String, String>): Future<Pointer<mpv_handle>>
    +dispose(handle: Pointer<mpv_handle>)
  }

  class InitializerNativeEventLoop {
    +ensureInitialized()
    +create(path: String, callback: Future<void> Function(Pointer<mpv_event> event), options: Map<String, String>): Future<Pointer<mpv_handle>>
    +dispose(handle: Pointer<mpv_handle>)
  }

  class Playable {
  }

  class AudioDevice {
  }

  class Media {
    +String uri
    +dynamic extras
  }

  class Playlist {
    +List<Media> medias
    +index index
  }

  class PlayerStream {
    +Stream<Playlist> playlist
    +Stream<bool> playing
    +Stream<bool> completed
    +Stream<Duration> position
    +Stream<Duration> duration
    +Stream<Duration> buffer
    +Stream<double> volume
    +Stream<double> rate
    +Stream<double> pitch
    +Stream<bool> buffering
    +Stream<Duration> buffer
    +Stream<AudioParams> audioParams
    +Stream<VideoParams> videoParams
    +Stream<double?> audioBitrate
    +Stream<AudioDevice> audioDevice
    +Stream<List<AudioDevice>> audioDevices
    +Stream<Track> track
    +Stream<Tracks> tracks
    +Stream<int> width
    +Stream<int> height
    +Stream<List<String>> subtitle
    +Stream<PlayerLog> log
    +Stream<String> error
  }

  class PlayerState {
    +Playlist playlist
    +bool playing
    +bool completed
    +Duration position
    +Duration duration
    +Duration buffer
    +double volume
    +double rate
    +double pitch
    +bool buffering
    +Duration buffer
    +AudioParams audioParams
    +VideoParams videoParams
    +double? audioBitrate
    +AudioDevice audioDevice
    +List<AudioDevice audioDevices
    +Track track
    +Tracks tracks
    +int width
    +int height
    +List<String> subtitle
  }

  class Player {
    +PlatformPlayer? platform

    +«get» PlayerState state
    +«get» PlayerStream stream

    +dispose()
    +open(playable: Playable)
    +play()
    +stop()
    +pause()
    +playOrPause()
    +add(media: Media)
    +remove(index: int)
    +next()
    +previous()
    +jump(index: int)
    +move(from: int, to: int)
    +seek(duration: Duration)
    +setPlaylistMode(playlistMode: PlaylistMode)
    +setVolume(volume: double)
    +setRate(rate: double)
    +setPitch(pitch: double)
    +setShuffle(bool: double)
    +setAudioDevice(device: AudioDevice)
    +setVideoTrack(track: VideoTrack)
    +setAudioTrack(track: AudioTrack)
    +setSubtitleTrack(track: SubtitleTrack)
    +screenshot(): Uint8List
  }

  class PlatformPlayer {
    +PlayerState state
    +PlayerStream stream
    +PlayerConfiguration configuration

    +dispose()*
    +open(playable: Playable)*
    +play()*
    +stop()*
    +pause()*
    +playOrPause()*
    +add(media: Media)*
    +remove(index: int)*
    +next()*
    +previous()*
    +jump(index: int)*
    +move(from: int, to: int)*
    +seek(duration: Duration)*
    +setPlaylistMode(playlistMode: PlaylistMode)*
    +setVolume(volume: double)*
    +setRate(rate: double)*
    +setPitch(pitch: double)*
    +setShuffle(bool: double)*
    +setAudioDevice(device: AudioDevice)*
    +setVideoTrack(track: VideoTrack)*
    +setAudioTrack(track: AudioTrack)*
    +setSubtitleTrack(track: SubtitleTrack)*
    +screenshot(): Uint8List*

    +«get» handle: Future<int>*

    #StreamController<Playlist> playlistController
    #StreamController<bool> playingController
    #StreamController<bool> completedController
    #StreamController<Duration> positionController
    #StreamController<Duration> durationController
    #StreamController<Duration> bufferController
    #StreamController<double> volumeController
    #StreamController<double> rateController
    #StreamController<double> pitchController
    #StreamController<bool> bufferingController
    #StreamController<PlayerLog> logController
    #StreamController<PlayerError> errorController
    #StreamController<AudioParams> audioParamsController
    #StreamController<double?> audioBitrateController
    #StreamController<AudioDevice> audioDeviceController
    #StreamController<List<AudioDevice>> audioDevicesController
    #StreamController<Track> trackController
    #StreamController<Tracks> tracksController
    #StreamController<int> widthController
    #StreamController<int> heightController
  }

  class NativePlayer {
    +dispose()
    +open(playable: Playable)
    +play()
    +stop()
    +pause()
    +playOrPause()
    +add(media: Media)
    +remove(index: int)
    +next()
    +previous()
    +jump(index: int)
    +move(from: int, to: int)
    +seek(duration: Duration)
    +setPlaylistMode(playlistMode: PlaylistMode)
    +setVolume(volume: double)
    +setRate(rate: double)
    +setPitch(pitch: double)
    +setShuffle(bool: double)
    +setAudioDevice(device: AudioDevice)
    +setVideoTrack(track: VideoTrack)
    +setAudioTrack(track: AudioTrack)
    +setSubtitleTrack(track: SubtitleTrack)
    +screenshot(): Uint8List

    +«get» handle: Future<int>
  }

  class WebPlayer {
    +dispose()
    +open(playable: Playable)
    +play()
    +stop()
    +pause()
    +playOrPause()
    +add(media: Media)
    +remove(index: int)
    +next()
    +previous()
    +jump(index: int)
    +move(from: int, to: int)
    +seek(duration: Duration)
    +setPlaylistMode(playlistMode: PlaylistMode)
    +setVolume(volume: double)
    +setRate(rate: double)
    +setPitch(pitch: double)
    +setShuffle(bool: double)
    +setAudioDevice(device: AudioDevice)
    +setVideoTrack(track: VideoTrack)
    +setAudioTrack(track: AudioTrack)
    +setSubtitleTrack(track: SubtitleTrack)
    +screenshot(): Uint8List

    +«get» handle: Future<int>
  }

  class NativeLibrary {
    +find()$ String?
  }
Loading

package:media_kit_video

Click on the zoom button on top-right or pinch inside.

Android

%%{
  init: {
    'themeVariables': {
      'fontFamily': 'BlinkMacSystemFont, Segoe UI, Noto Sans, Helvetica, Arial, Apple Color Emoji, Segoe UI Emoji'
    }
  }
}%%
classDiagram

  MediaKitVideoPlugin "1" *-- "1" VideoOutputManager: Create VideoOutput(s) with VideoOutputManager for handle passed through platform channel
  VideoOutputManager "1" *-- "*" VideoOutput: Create VideoOutput(s) to send back id & wid for render. Dispose to release.
  VideoOutput <.. MediaKitAndroidHelper: Create & dispose JNI global object reference to android.view.Surface (for --wid)

  class MediaKitVideoPlugin {
    +Activity activity$
    -MethodChannel channel
    -TextureRegistry textureRegistry
    -VideoOutputManager videoOutputManager
  }

  class VideoOutputManager {
    -HashMap<Long, VideoOutput> videoOutputs
    -MethodChannel channelReference
    -TextureRegistry textureRegistryReference
    -Object lock

    +create(handle: long): VideoOutput
    +dispose(handle: long): void
    +createSurface(handle: long): long
    +setSurfaceTextureSize(handle: long, width: int, height: int): void
  }

  class VideoOutput {
    +long id
    +long wid

    -Surface surface
    -TextureRegistry.SurfaceTextureEntry surfaceTextureEntry
    -Method newGlobalObjectRef
    -Method deleteGlobalObjectRef

    -long handle
    -MethodChannel channelReference
    -TextureRegistry textureRegistryReference

    +dispose()
    +createSurface(): long
    +setSurfaceTextureSize(width: int, height: int)
  }

  class MediaKitAndroidHelper {
    +newGlobalObjectRef(obj: Object): long
    +deleteGlobalObjectRef(ref: long): void
    +setApplicationContext(context: Context): void
    +copyAssetToExternalFilesDir(assetName: String): String
  }

Loading

iOS

TODO: documentation.

macOS

TODO: documentation.

Windows

%%{
  init: {
    'themeVariables': {
      'fontFamily': 'BlinkMacSystemFont, Segoe UI, Noto Sans, Helvetica, Arial, Apple Color Emoji, Segoe UI Emoji'
    }
  }
}%%
classDiagram

  MediaKitVideoPlugin "1" *-- "1" VideoOutputManager: Create VideoOutput(s) with VideoOutputManager for handle passed through platform channel
  VideoOutputManager "1" *-- "*" VideoOutput: Takes PluginRegistrarWindows as reference
  VideoOutputManager "1" *-- "1" ThreadPool
  VideoOutput "*" o-- "1" ThreadPool: Post creation, resize & render etc. tasks involving EGL to ensure synchronous EGL/ANGLE usage across multiple VideoOutput(s)
  VideoOutput "1" *-- "1" ANGLESurfaceManager: Only for H/W accelerated rendering

  class MediaKitVideoPlugin {
    -flutter::PluginRegistrarWindows registrar_
    -std::unique_ptr<MethodChannel> channel_
    -std::unique_ptr<VideoOutputManager> video_output_manager_
    -HandleMethodCall(method_call, result);
  }

  class ThreadPool {
    +Post(function: std::function)
  }

  class VideoOutputManager {
    +Create(handle: int, width: optional<int>, height: optional<int>, texture_update_callback: std::function)
    +Dispose(handle: int)

    -std::mutex mutex_
    -std::unique_ptr<ThreadPool> thread_pool_
    -flutter::PluginRegistrarWindows registrar_
    -std::unordered_map<int64_t, std::unique_ptr<VideoOutput>> video_outputs_
  }

  class VideoOutput {
    +«get» texture_id: int64_t
    +«get» width: int64_t
    +«get» height: int64_t
    -mpv_handle* handle_
    -mpv_render_context* render_context_
    -std::optional<int64_t> width_
    -std::optional<int64_t> height_
    -bool enable_hardware_acceleration_
    -int64_t texture_id_
    -flutter::PluginRegistrarWindows registrar_
    -ThreadPool* thread_pool_ref_
    -bool destroyed_
    -std::mutex textures_mutex_
    -std::unordered_map<int64_t, std::unique_ptr<flutter::TextureVariant>> texture_variants_
    -std::unique_ptr<ANGLESurfaceManager> surface_manager_ HW
    -std::unordered_map<int64_t, std::unique_ptr<FlutterDesktopGpuSurfaceDescriptor>> textures_ HW
    -std::unique_ptr<uint8_t[]> pixel_buffer_ SW
    -std::unordered_map<int64_t, std::unique_ptr<FlutterDesktopPixelBuffer>> pixel_buffer_textures_ SW
    -std::function texture_update_callback_

    +SetTextureUpdateCallback(callback: std::function<void(int64_t, int64_t, int64_t)>)
    +SetSize(width: std::optional<int64_t>, height: std::optional<int64_t>)
    -NotifyRender()
    -Render()
    -CheckAndResize()
    -Resize(required_width: int64_t, required_height: int64_t)
    -GetVideoWidth(): int64_t
    -GetVideoHeight(): int64_t
  }

  class ANGLESurfaceManager {
    +«get» width: int32_t
    +«get» height: int32_t
    +«get» handle: HANDLE

    +HandleResize(width: int32_t, height: int32_t)
    +Draw(draw_callback: std::function<void()>)
    +Read()
    +MakeCurrent(value: bool)
    -CreateEGLDisplay()
    -SwapBuffers()
    -Create()
    -CleanUp(release_context: bool)
    -CreateD3DTexture()
    -CreateEGLDisplay()
    -CreateAndBindEGLSurface()

    -IDXGIAdapter* adapter_
    -int32_t width_
    -int32_t height_
    -HANDLE internal_handle_
    -HANDLE handle_
    -HANDLE mutex_
    -ID3D11Device* d3d_11_device_
    -ID3D11DeviceContext* d3d_11_device_context_
    -Microsoft::WRL::ComPtr<ID3D11Texture2D> internal_d3d_11_texture_2D_
    -Microsoft::WRL::ComPtr<IDXGISwapChain> d3d_11_texture_2D_
    -EGLSurface surface_
    -EGLDisplay display_
    -EGLContext context_
    -EGLConfig config_
  }
Loading

GNU/Linux

%%{
  init: {
    'themeVariables': {
      'fontFamily': 'BlinkMacSystemFont, Segoe UI, Noto Sans, Helvetica, Arial, Apple Color Emoji, Segoe UI Emoji'
    }
  }
}%%
classDiagram

  MediaKitVideoPlugin "1" *-- "1" VideoOutputManager: Create VideoOutput(s) with VideoOutputManager for handle passed through platform channel
  VideoOutputManager "1" *-- "*" VideoOutput: Takes FlTextureRegistrar as reference
  VideoOutput "1" *-- "1" TextureGL: For H/W rendering.
  TextureGL "1" o-- "1" VideoOutput: Take VideoOutput as reference
  VideoOutput "1" *-- "1" TextureSW: For S/W rendering.
  TextureSW "1" o-- "1" VideoOutput: Take VideoOutput as reference
  TextureGL "1" <-- "1" FlTextureGL
  TextureSW "1" <-- "1" FlTexture

  class MediaKitVideoPlugin {
    -FlMethodChannel* channel
    -VideoOutputManager* video_output_manager
  }

  class VideoOutputManager {
    -GHashTable* video_outputs
    -FlTextureRegistrar* texture_registrar
    +video_output_manager_create(self: VideoOutputManager*, handle: gint64, width: gint64, height: gint64, texture_update_callback: TextureUpdateCallback, texture_update_callback_context: gpointer)
    +video_output_manager_dispose(self: VideoOutputManager*, handle: gint64)
  }

  class VideoOutput {
    -TextureGL* texture_gl
    -GdkGLContext* context_gl
    -mpv_handle* handle
    -mpv_render_context* render_context
    -gint64 width
    -gint64 height
    -TextureUpdateCallback texture_update_callback
    -gpointer texture_update_callback_context
    -FlTextureRegistrar* texture_registrar
    +video_output_set_texture_update_callback(self: VideoOutput*, texture_update_callback: TextureUpdateCallback, texture_update_callback_context: gpointer)
    +video_output_get_render_context(self: VideoOutput*): mpv_render_context*
    +video_output_get_width(self: VideoOutput*): gint64
    +video_output_get_height(self: VideoOutput*): gint64
    +video_output_get_texture_id(self: VideoOutput*): gint64
    +video_output_notify_texture_update(self: VideoOutput*);
  }

  class TextureGL {
    -guint32 name
    -guint32 fbo
    -guint32 current_width
    -guint32 current_height
    -VideoOutput* video_output
    texture_gl_populate_texture(texture: FlTextureGL*, target: guint32*, name: guint32*, width: guint32*, height: guint32*, error: GError**): gboolean
  }

  class TextureSW {
    -guint32 current_width
    -guint32 current_height
    -VideoOutput* video_output
    texture_sw_copy_pixels(texture: FlPixelBufferTexture*, buffer: const uint8_t**, width: uint32_t*, height: uint32_t*, error: GError**): gboolean
  }
Loading

Web

TODO: documentation.

Implementation

libmpv is used for leveraging audio & video playback. It seems the best possible option since supports a wide variety of audio & video formats, provides hardware acceleration & bundle size is also minimal (select only required decoders etc. in FFmpeg/mpv).

Another major advantage is that large part of implementation (80%+) is shared across platforms using FFI. This makes the behavior of package very-very similar on all supported platforms & makes maintenance easier (since there is less code & most of it within Dart).

Alternative backends may be implemented in future to meet certain demands (& project architecture makes it possible).

package:media_kit

package:media_kit is entirely written in Dart. It uses dart:ffi to invoke native C API of libmpv through it's shared libraries. All the callback management, event-Streams, other methods to control playback of audio/video are implemented in Dart with the help of FFI. Event management i.e. position, duration, bitrate, audioParams Streams are important to render changes in the UI.

A big limitation with FFI in Dart SDK has been that it does not support async callbacks from another thread. Learn more about this at: dart/sdk#37022. Following situation will explain better:

If you pass a function pointer from Dart to C code, you can invoke it fine. But, as soon as you invoke it from some other thread on the native side, Dart VM will instantly crash. This feature is important because most events take place on a background thread.

However, I could easily do this within Dart because libmpv offers an "event polling"-like way to listen to events. I got awesome idea to spawn a background Isolate, where I run the event-loop. I get the memory address of each event and forward it outside the Isolate with the help of ReceivePort, where I finally interpret it using more FFI code. I have explained this in detail within the in-code comments of initializer.dart, where I had to perform a lot more trickery to get this to work.

Thus, invoking native methods & handling of events etc. could be done within 100% Dart using FFI. This is enough for audio playback & supports both Flutter SDK & Dart VM. Although event handling works entirely within Dart. Later, it was discovered that going beyond certain number of simultaneous instances caused a deadlock (dart-lang/sdk#51254 & dart-lang/sdk#51261), making UI entirely freezed along-side any other Dart code in execution. To deal with this, a new package package:media_kit_native_event_loop is created. Adding package:media_kit_native_event_loop to pubspec.yaml automatically resolves this issue without any chagnes to code!

However, no such "event-polling" like API is possible for video rendering. So, I best idea seemed to create a new package package:media_kit_video for specifically offering platform-specific video embedding implementation which internally handles Flutter's Texture Registry API & libmpv's OpenGL rendering API. This package only consumes the mpv_handle* (which can be shared as primitive int value easily) of the instance (created with package:media_kit through FFI) to setup a new viewport. Detailed implementation is discussed below.

package:media_kit_native_event_loop

Platform specific threaded event handling for media_kit. Enables support for higher number of concurrent instances.

The package contains a minimal C++ implementation which spawns a detach-ed std::thread. This runs the mpv_wait_event loop & forwads the events using postCObject, SendPort & ReceivePort to Dart VM. Necessary mutex synchronization also takes place.

Isolate based event loop is avoided once this package is added to the project.

package:media_kit_video

Android

On Android, texture registry API is based on android.graphics.SurfaceTexture.

libmpv can render directly onto an android.view.Surface after setting --wid. Creation of a new android.view.Surface requires reference to an existing android.graphics.SurfaceTexture, which can be consumed from the texture entry created by Flutter itself.

This requires --hwdec=mediacodec for hardware decoding, along with --vo=mediacodec_embed and --wid=(intptr_t)(*android.view.Surface).

More details may be found at: https://mpv.io/manual/stable/#video-output-drivers-mediacodec-embed

Obtaining a global reference pointer to a Java object (android.view.Surface in our case) requires JNI. For this, a custom shared library is used, you can find it's implementation at media-kit/media-kit-android-helper. Since compilation of this would require NDK (& make process tedious), pre-built shared libraries is bundled for each architecture at the time of development/build.

Since the package:media_kit is a Dart package (which works independent of Flutter), accessing assets was a challenging part. The mentioned shared libraries generated by media-kit/media-kit-android-helper helps to access assets bundled inside Android APK from Dart (using FFI, without depending on Flutter).

iOS

iOS shares much of it's implementation with macOS. Only difference is that OpenGL ES is used instead of OpenGL.

macOS

On macOS the current implementation is based on libmpv and can be summarized as follows:

  1. H/W video decoding: mpv option hwdec is set to auto, does not depend on a pixel buffer.
  2. OpenGL rendering to an OpenGL texture backed by a pixel buffer, which makes it interoperable with METAL (CVPixelBuffer)

Windows

The two APIs above are hardware accelerated i.e. GPU backed buffers are used. This is performant approach, easily capable for rendering 4K 60 FPS videos, rest depends on the hardware. Since libmpv API is OpenGL based & the Texture API in Flutter is Direct3D based, ANGLE (Almost Native Graphics Layer Engine) is used for interop, which translates the OpenGL ES 2.0 calls into Direct3D.

This hardware-accelerated video output requires DirectX 11 or higher. Most Windows systems with either integrated or discrete GPUs should support this already. On systems where Direct3D fails to load due to missing graphics drivers or unsupported feature-level or DirectX version etc. a fallback pixel-buffer based software renderer is used. This means that video is rendered by CPU & every frame is copied back to the RAM. This will cause some redundant load on the CPU, result in decreased battery life & may not play higher resolution videos properly. However, it works well.

Windows 7 & 8.x also work correctly.

0 1

You may visit experimentation repository to see a minimal example showing OpenGL ES usage in Flutter Windows.

GNU/Linux

On Flutter Linux, both OpenGL (H/W) & pixel buffer (S/W) APIs are available for rendering on Texture widget.

Web

Video & audio playback is handled by embedding HTML <video> element.

License

Copyright © 2021 & onwards, Hitesh Kumar Saini <[email protected]>

This project & the work under this repository is governed by MIT license that can be found in the LICENSE file.

media-kit's People

Contributors

23doors avatar abdelaziz-mahdy avatar acarlsen avatar ahmedabouelkher avatar airyzz avatar alexmercerind avatar alexmercerind2 avatar alexv525 avatar areille avatar ashilkn avatar birros avatar deckerst avatar default-anton avatar dferrarigrowtech avatar domingomg avatar femalemonkeyman avatar jamiepiccolo avatar kirill-21 avatar moffatman avatar noelex avatar prateekmedia avatar punxch avatar quackdoc avatar refi64 avatar sapphire008 avatar wanjm avatar wizlif avatar yehudakremer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

media-kit's Issues

[Question] Build fails on Windows 10 and Flutter 3.8 beta

Hi. Even when trying to launch the app on Windows 10 and Flutter 3.8, the build fails.
Could you tell me where is wrong?

Log

Launching lib\main.dart on Windows in debug mode...
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppBuild.targets(382,5): error MSB3491: �s���t�@�C�� "x64\Debug\media_kit_libs_windows_video_ANGLE_EXTRACT\media_ki.11B11C55.tlog\media_kit_libs_windows_video_ANGLE_EXTRACT.lastbuildstate" �ɏ������߂܂���ł����B�p�X: x64\Debug\media_kit_libs_windows_video_ANGLE_EXTRACT\media_ki.11B11C55.tlog\media_kit_libs_windows_video_ANGLE_EXTRACT.lastbuildstate �� OS �̃p�X�̏�����z���Ă��܂��B���S�C���̃t�@�C������ 260 �����ȉ��ɂ���K�v������܂��B [C:\Users\<user>\OneDrive\development\flutter_applications\media_kit_test_app\build\windows\plugins\media_kit_libs_windows_video\media_kit_libs_windows_video_ANGLE_EXTRACT.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppBuild.targets(382,5): error MSB3491: �s���t�@�C�� "x64\Debug\media_kit_libs_windows_video_LIBMPV_EXTRACT\media_ki.9F972795.tlog\media_kit_libs_windows_video_LIBMPV_EXTRACT.lastbuildstate" �ɏ������߂܂���ł����B�p�X: x64\Debug\media_kit_libs_windows_video_LIBMPV_EXTRACT\media_ki.9F972795.tlog\media_kit_libs_windows_video_LIBMPV_EXTRACT.lastbuildstate �� OS �̃p�X�̏�����z���Ă��܂��B���S�C���̃t�@�C������ 260 �����ȉ��ɂ���K�v������܂��B [C:\Users\<user>\OneDrive\development\flutter_applications\media_kit_test_app\build\windows\plugins\media_kit_libs_windows_video\media_kit_libs_windows_video_LIBMPV_EXTRACT.vcxproj]
Exception: Build process failed.
Exited (sigterm)

Steps to reproduce

  1. Create a new flutter app.
  2. Edit the pubspec.yaml as described later.
  3. flutter pub get
  4. Press F5 on VSCode.

Envs

Flutter doctor
> flutter doctor -v  
[√] Flutter (Channel beta, 3.8.0-10.1.pre, on Microsoft Windows [Version 10.0.19045.2673],
    locale ja-JP)
    • Flutter version 3.8.0-10.1.pre on channel beta at C:\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 1a0a03a41d (4 weeks ago), 2023-02-16 22:03:58 -0600
    • Engine revision 639e313f99
    • Dart version 3.0.0 (build 3.0.0-218.1.beta)
    • DevTools version 2.21.1

[√] Windows Version (Installed version of Windows is version 10 or higher)   

[X] Android toolchain - develop for Android devices
    • Android SDK at C:\Users\<user>\AppData\Local\Android\sdk
    X cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe        

[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.5.2)
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
    • Visual Studio Community 2022 version 17.5.33502.453
    • Windows 10 SDK version 10.0.19041.0

[!] Android Studio (version 2021.3)
    • Android Studio at C:\Program Files\Android\Android Studio
    • 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
    X Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[√] VS Code (version 1.74.3)
    • VS Code at C:\Users\<user>\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.60.0

[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version
      10.0.19045.2673]
    • Chrome (web)      • chrome  • web-javascript • Google Chrome 111.0.5563.65
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 110.0.1587.41

[√] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 2 categories.
pubspec.yaml
name: media_kit_test_app
description: A new Flutter project.
publish_to: "none" # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1

environment:
  sdk: ">=3.0.0-218.1.beta <4.0.0"

dependencies:
  flutter:
    sdk: flutter

  media_kit:
    git:
      url: https://github.com/alexmercerind/media_kit
      path: media_kit
      ref: 24f95f20233105220306388d7e3f5aef413d8cb9
  media_kit_video:
    git:
      url: https://github.com/alexmercerind/media_kit
      path: media_kit_video
      ref: 24f95f20233105220306388d7e3f5aef413d8cb9
  # media_kit_native_event_loop: ^1.0.0
  media_kit_libs_windows_video: ^1.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true
</details>

[Question] Federated plugin

Hi,

Are there plans to support offering this plugin as a federated plugin of video_player? The API's are different, being able to use this plugin as a federated plugin of video_player would make transitioning between the packages much easier.

Thanks!

[Question] RTSP live stream low delay

I want to play an rtsp live stream. If I want to set a very low delay, how should I set it? I followed the setup method provided by MPV without success
image

'''
if (player.platform is libmpvPlayer) {

(player.platform as libmpvPlayer)

.setProperty("opengl-glfinish", "yes");
(player.platform as libmpvPlayer)
 .setProperty("untimed", "")
....

'''

[Question] Setting HTTP headers for a URL source

With better_player package I can set HTTP headers for a URL source as following:

      var newSource = BetterPlayerDataSource(
        BetterPlayerDataSourceType.network,
        url,
        drmConfiguration: null,
        headers: {"Cookie": cookie},
      );

I tried the same with the extras parameter but could not play the same URL source successfully:

                      player.open(
                        Playlist(
                          [
                            Media(_video.text, extras: {
                              "Cookie": cookie
                            }),
                          ],
                        ),
                      );

Is there a way to set HTTP headers for a URL source?

[Request] Please delete un-attended forks containing my code

Hi!

I see you have an old fork containing my code/commits at:

Please consider deleting those repositories containing un-maintained code authored & licensed by me.

This is the actual repository, which contains the final work rooted from that old state. I decided to rename package:libmpv to package:media_kit, in-order to have more freedom in terms of project's direction. Here, I just implemented H/W accelerated video playback too. The project now has much more to see here & a number of new things have also been added. Let's build it together. Get to the README for more information.

Thanks!

[Windows] Remove flutter::FlutterView::GetGraphicsAdapter usage

Hello !

To get started, thank's for your work ! :)

I wanted to test this package with your example but i got an error :

Launching lib\main.dart on Windows in debug mode...
E:\temp\media_kit-master\media_kit\media_kit_test\windows\flutter\ephemeral.plugin_symlinks\media_kit_core_video\windows\video_output_manager.cc(81,33): error C2039: 'GetGraphicsAdapter' n'est pas membre de 'flutter::FlutterView' [E:\temp\media_kit-master\media_kit\media_kit_test\build\windows\plugins\media_kit_core_video\media_kit_core_video_plugin.vcxproj]
Building Windows application...
Exception: Build process failed.

I've upgraded Flutter to the last version, clean everything i can.
If you want more informations tell me !

[Question] Listen for network errors

Hello!
First of all, thank you for this awesome new project!
I'd like to know if it's possible to listen for network errors. I'm listening to the player.stream.error stream but when I enable the airplane mode, no error is raised. Is there any other solution?
Thanks!

[Enhancement] custom libmpv shared libraries

We need own libmpv builds for:

  • Allowing usage of package:media_kit in proprietary/commercial applications (by using LGPL compliant libmpv).
  • Reducing the final bundle size of the resulting application using package:media_kit as it's dependency.
  • Keeping specialized libmpv binaries available for download (e.g. GitHub releases) to to build projects having package:media_kit.

With the highest priority being first:

Windows [Done]

media_kit_core_audio bundles audio-only libmpv-2.dll on Windows.
media_kit_core_video bundles minimal video+audio libmpv-2.dll on Windows.

Both are LGPL compliant & allow commercial usage.

References:

Linux [Done]

package:media_kit doesn't bundle anything related to libmpv / FFmpeg etc. etc. It is not feasible either.

  • On Linux, distribution specific packages are the "standard".
  • Distribution specific packages are expected to be installed by the users themselves before installing application package.
  • Since, any commercial / proprietary application won't distribute these, it's not important for these to be LGPL etc.
  • In case of an alternative distribution methodology e.g. Snapcraft, Flathub etc., it is responsibility of the package:media_kit dependents to handle it themselves. Few references in regards to this may be located here, where libmpv, FFmpeg etc. are "bundled" into Flatpak package.

macOS [WIP]

  • Take hints from IINA. A really polished media player for macOS based on libmpv.

Android [Soon]

iOS [Soon]

  • ???

[Question] Subtitles are not working

var pp = windowsvidplayer.platform as libmpvPlayer;
      await pp.setProperty("sub-file", "E:\\sub.srt");
      await pp.setProperty("subs-with-matching-audio", "no");
      await pp.setProperty("sub-forced-only", "yes");
      await pp.setProperty("blend-subtitles", "video");
      controller = await VideoController.create(windowsvidplayer.handle);

      setState(() {});

      windowsvidplayer.open(Playlist([dta]));

experted
mpv " https://my-video-path" --sub-file=E:\sub.srt --subs-with-matching-audio=no --sub-forced-only=yes --blend-subtitles=video

using mpv exe an arggument is working fine;
but setProperty is not working in flutter applixcation

[Question] Build failed on Windows 10 and Flutter 3.7

after upgrading flutter to 3.7 following error occurs when trying to use this package

Error waiting for a debug connection: The log reader stopped unexpectedly, or never started.
Error launching application on Windows.

with flutter run -v shows a little bit more

           #4      CommandRunner.runCommand (package:args/command_runner.dart:209:13)
           <asynchronous suspension>
           #5      FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:283:9)
           <asynchronous suspension>
           #6      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
           <asynchronous suspension>
           #7      FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:229:5)
           <asynchronous suspension>
           #8      run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:64:9)
           <asynchronous suspension>
           #9      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
           <asynchronous suspension>
           #10     main (package:flutter_tools/executable.dart:91:3)
           <asynchronous suspension>

Minimal example

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyScreen(),
    );
  }
}

class MyScreen extends StatefulWidget {
  const MyScreen({Key? key}) : super(key: key);
  @override
  State<MyScreen> createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
  final Player player = Player();
  VideoController? controller;

  @override
  void initState() {
    super.initState();
    Future.microtask(() async {
      controller = await VideoController.create(player.handle);
      setState(() {});
    });
  }

  @override
  void dispose() {
    Future.microtask(() async {
      await controller?.dispose();
      await player.dispose();
    });
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Video(
      controller: controller,
    );
  }
}

pubspec.yaml

name: media_kit_test
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: '>=2.19.0 <3.0.0'

dependencies:
  flutter:
    sdk: flutter
  media_kit:
    git:
      url: https://github.com/alexmercerind/media_kit
      path: media_kit
  media_kit_video:
    git:
      url: https://github.com/alexmercerind/media_kit
      path: media_kit_video
  cupertino_icons: ^1.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true
flutter doctor -v
[√] Flutter (Channel stable, 3.7.0, on Microsoft Windows [Version 10.0.19045.2486], locale de-DE)
    • Flutter version 3.7.0 on channel stable at C:\flutter                                      
    • Upstream repository https://github.com/flutter/flutter.git                                 
    • Framework revision b06b8b2710 (2 days ago), 2023-01-23 16:55:55 -0800                      
    • Engine revision b24591ed32                                                                 
    • Dart version 2.19.0                                                                        
    • DevTools version 2.20.1                                                                    
                                                                                                 
[X] Windows Version (Unable to confirm if installed Windows version is 10 or greater)            

[√] Android toolchain - develop for Android devices (Android SDK version 32.0.0) 
    • Android SDK at C:\Users\Filly\AppData\Local\Android\Sdk                    
    • Platform android-33, build-tools 32.0.0                                    
    • ANDROID_HOME = C:\Users\Filly\AppData\Local\Android\Sdk                    
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java       
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.                                             
                                                                                 
[√] Chrome - develop for the web                                                 
    • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe      
                                                                                 
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.4.4)    
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community   
    • Visual Studio Community 2022 version 17.4.33213.308                        
    • Windows 10 SDK version 10.0.22621.0                                        
                                                                                 
[√] Android Studio (version 2022.1)                                              
    • Android Studio at C:\Program Files\Android\Android Studio                  
    • 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 11.0.15+0-b2043.56-8887301)

[√] VS Code (version 1.74.3)
    • VS Code at C:\Users\Filly\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.56.0

[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.19045.2486]
    • Chrome (web)      • chrome  • web-javascript • Google Chrome 108.0.5359.125
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 109.0.1518.61

[√] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.

[Enhancement] pub.dev scores

Now that package:media_kit is available on pub.dev, I'm noticing that we're losing few scores.
From what I've seen so far, primarily due to:

  • Missing example(s) in various packages.
  • Having too short description in pubspec.yaml of various packages.

A solid 140/140 on all packages will be good to have. Current scores:

The 'Package layout convention' page suggests that we can have examples at following places. It is important to consider because few of the packages don't have any Dart code in them (at all) & only native implementation or build steps.

  • example/example[.md]
  • example[/lib]/main.dart
  • example[/lib]/package_name.dart
  • example[/lib]/package_name_example.dart
  • example[/lib]/example.dart
  • example/README[.md]

[Question] flutter build windows is failing due to ANGLE.7z's failed integrity check

I followed all the steps in the README. The app runs fine if I run it with flutter run -d windows, but, when I run it with flutter build windows, the following error is thrown.

Logs

PS > flutter build windows 

 Building with sound null safety 

CMake Error at flutter/ephemeral/.plugin_symlinks/media_kit_core_video/windows/CMakeLists.txt:78 (message):
  ANGLE.7z seems corrupt.


Building Windows application...                                         
Unable to generate build files

Sample video of my hobby project on MacOS

Hi,
I have a hobby project for playing TV channels from my cable TV subscription which runs on iOS, Android and Android TV. This package made it possible to use the same code base to create a MacOS version of the project and it worked so well.

Thanks for the excellent implementation and sharing.

Here is how the app works on MacOS:

sample.mp4

[Question] Set additional libmpv arguments

My Local RTSP-Stream (TV-Stream via Router) needs an additional argument for mpv to work --rtsp-transport=udp

cmd: mpv.exe "rtsp://..." --rtsp-transport=udp

is this somehow currently possible or will be in future?

[BUG] V/A out of sync when increasing `Player.rate`

While working on the implementation for macOS, I noticed that there was a progressive audio and video desynchronization when I change the rate of the Player:

player.rate = 2.0;

Tests (commit 21eb88d)

Platform Behavior
macOS V/A out of sync
Linux V/A out of sync
Windows Not tested

Ideas

One of these three possibilities may explain it:

  • If the issue is not present on Windows, it's possible that the lack of thread usage in the Linux and macOS implementations could be causing it
  • A missing option may be required by mpv
  • A bad implementation of rendering, perhaps certain frames need to be manually dropped, maybe through MPV_RENDER_PARAM_SKIP_RENDERING

Documentation website

package:media_kit is becoming really large & there are a large number of features that need good documentation. As the project is growing further, it might be a good idea to provide documentation separately on a website; instead of GitHub README.

[Feature Request] setAudioFile, setSubFile

I am looking at the code and stumble upon setAudioTrack, setVideoTrack, setSubtitleTrack.

But this does not work for me.
I want to play a video, with a detached audio file and another file for the subtitle.

I have found that I can do that with mpv by using --audio-file and --sub-file. I wasn't able to get it working with --vid and --aid, that SetVideo/AudioTrack are used for.

I tried to use those switches in this package with setProperty but looking at the source, it seems only a limited subset is taken into account, and not those 2.

So either, add them to the list of setProperty taken into account or add dedicated method, like setAudioFile, setSubFile.

Thank you

[Bug] 8 or more Player(s) freeze the application

Filed dart-lang/sdk#51254 for now.

Let's see what should be done in regard to this. It is quite important to fix this. Many users of package:media_kit are definitely playing more than 8 videos at once. Reaching that level of stability/performance is certainly a goal for project.

8 is definitely not a less number. Most applications are never going to play this number of videos simultaneously.


You can +1 this issue comment. Working on this will require substantial time.

[Bug Report][GNU/Linux] Memory usage not freeing with dispose

I' just noticing that the memory taken up by both my own and the test application on linux (I have not tested other platforms) is never clearing. It is fine to begin with but eventually does get out of hand. I looked a bit and didn't really see an issue with flutter itself pertaining to this so i was just wondering if there was any insight.

[Question] macOS fatal error: 'mpv/client.h' file not found

In file included from /Users/jiangchunyu/Downloads/media_kit-main/media_kit_native_event_loop/macos/Classes/media_kit_native_event_loop.cc:3:
In file included from /Users/jiangchunyu/Downloads/media_kit-main/media_kit_native_event_loop/src/media_kit_native_event_loop.cc:9:
/Users/jiangchunyu/Downloads/media_kit-main/media_kit_native_event_loop/src/media_kit_native_event_loop.h:17:10: fatal error: 'mpv/client.h' file not found
#include <mpv/client.h>
^~~~~~~~~~~~~~
1 error generated.
Command CompileSwiftSources failed with a nonzero exit code
Command CompileSwiftSources failed with a nonzero exit code
** BUILD FAILED **

Exception: Build process failed
Macos is install mpv,but not found

[Enhancement] Player's setter and getter API

The current player API is a bit confusing:

// the following code is valid, but only the first instruction call mpv
player.rate = 2.0;       // call mpv
player.state.rate = 2.0; // don't do anything

I think it would be better to either:

  • move the setters to PlayerState
  • merge Player & PlayerState
  • turn the PlayerState into a read only class

Request to Enable Discussions in Repository

I was wondering if it might be possible for you to enable discussions within this GitHub repository.

This would allow people to engage in Q&A sessions, share information about new releases or unexpected documentation, and showcase projects they've been working on. By providing this separate space for discussion, we could help prevent the issue tracker from becoming cluttered and ensure that issues are addressed in a more streamlined manner. It would also give you the opportunity to focus on more pressing matters, without feeling guilty about not responding to every comment or question that arises.

Would you be willing to consider enabling discussions within the repository?

[Enhancement] Possibility to resize the rect of `VideoController`

From the documentation:

/// 1. You can limit size of the video output by specifying `width` & `height`.
///    By default, both `height` & `width` are `null` i.e. output is based on video's resolution.

Currently, I initialize the video with 640x360, but I find the need to use a smaller resolution when the video is resized (192x144). Would it be possible to change the height and width of the VideoController?

I tried to create different video controllers with different resolutions, but it seems that the second controller isn't created if one controller is already initialized. It also crashes when the second controller is initialized. Is that by design?

[Question] More Log-Output, Location of Temp-Dir (if used)

when opening files from my NAS (mounted as an Windows Network Share) then it takes minutes for these files to start playing, approximately the same amount of time it would need to copy these files to local storage.
is that or something similar maybe happening with network files? if so (and in general) are there any temporary/logging directories for this package and/or the libraries it's using?

some other files cannot be opened at all (local or network), the app always crashes with these files, I just see a "Lost connection to device".
are there any logfiles written somewhere or is there a possibility to see more logging output in order to investigate the problem with these files? they work with VLC or the official mpv-Player but not with the package

[Bug Report][GNU/Linux] Rendering broken on Flutter 3.9.x & Snapshot widget freezes UI on Flutter 3.7.x

Edit by @alexmercerind:

This is a regression in Flutter. I have filed an issue at:
flutter/flutter#124009

Please drop a +1 to that issue for expecting quick fixes.

Thanks!

Original comment:

I was testing the plugin player, and couldn't get back in navigator history.

It finally worked, when carefully copying that missing snippet about the pageTransitionsTheme of MaterialApp theme, that I saw in the media_kit_test example app. Then, it finally worked. But when I tried to use ZoomPageTransitionBuilder instead, it didn't work again; meaning I can't go back to my previous route, and the player freeze and the app is stuck/frozen.

This is easily reproduced by modifying the pageTransitionsTheme of main.dart (line 25-29) of media_kit_test.

[Bug Report] GLib-Error: creating thread 'mpv_render_context_set_update_callback': Resource temporarily unavailable

It's running out of memory gradually, even though I see dispose messages for every controller.

Screenshot from 2023-03-27 20-27-24
Screenshot from 2023-03-27 20-30-22

I am on Ubuntu 22.04 LTS, media_kit master, mpv 0.34.1, FFmpeg version: 4.4.2-0ubuntu0.22.04.1.

I am having a controller for each player. Gradually, over the period of 1-2 minutes, the app crashes with

GLib-ERROR **: 20:30:54.533: creating thread 'mpv_render_context_set_update_callback': Error creating thread: Resource temporarily unavailable

[Question] Web support timeline

I saw that the platforms table, doesnt include web

does that mean its not planned? and we need to create a work around to use media_kit with video_player to work across all platforms?

thank you for the package

[Question] App does not build on linux

Logs

CMake Error at flutter/ephemeral/.plugin_symlinks/media_kit_video/linux/CMakeLists.txt:15 (add_library):
  Target "media_kit_video_plugin" links to target "PkgConfig::mpv" but the
  target was not found.  Perhaps a find_package() call is missing for an
  IMPORTED target, or an ALIAS target is missing?


CMake Generate step failed.  Build files cannot be regenerated correctly.

I did follow all the steps described in the README (sudo apt install libmpv-dev libmpv2), but I get the following error (see E)

--- sudo apt install libmpv-dev libmpv2
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package libmpv2

[Windows] Playing file is in a seperate window

Hi,

Using the following code:

(note; these are just snippets of code)

  final Player _player = Player();
  VideoController? _videoController;
  _player.open(Playlist(
        [
          Media('file://${file.path}'),
        ],
      ));
      _videoController = await VideoController.create(_player.handle);
      setState(() {});
Video(
    controller: _videoController,
),

Code block 2 is in a function, when the first video gets loaded. It opens a seperate window to play said video. Then after switching between videos for a few times it suddenly work and is shown in the widget as defined in block 3.

Thanks in advance!
Kind regards,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.