सार्वजनिक जानकारी से बना चयन मार्गदर्शन। केवल संदर्भ हेतु।
media_kit_video मीडिया किट पारिस्थितिकी तंत्र में वीडियो प्ले बैक के लिए एक नेटिव इम्प्लीमेंटेशन प्रदान करता है, जो एंड्रॉइड, आईओएस, वेब, मैकओएस, विंडोज और लिनक्स सहित कई प्लेटफॉर्मों पर उच्च प्रदर्शन वीडियो रेंडरिंग सुनिश्चित करता है। फ्लटर के साथ निर्मित, यह विकासकर्ताओं के लिए विश्वसनीय, कम-स्तरीय वीडियो हैंडलिंग के लिए बिना प्लेटफॉर्म-विशिष्ट कोड के बिना निरंतर एकीकरण प्रदान करता है। इस पैकेज में विभिन्न वीडियो फॉर्मेट और स्ट्रीमिंग प्रोटोकॉल का समर्थन है, जिससे व्यापक संगतता सुनिश्चित होती है। यह ऑप्टिमल प्रदर्शन और चिकनी प्ले अनुभव के लिए मूल मीडिया फ्रेमवर्क का उपयोग करता है।
उपयोग
स्ट्रीमिंग वीडियो सामग्री
स्थानीय वीडियो प्रदर्शन
प्लेटफॉर्म के आधार पर वीडियो एप्प
लाइव वीडियो फीड
वीडियो प्लेयर एंटीग्रेशन
मुख्य विशेषताएँ
मूल वीडियो रेंडरिंग
बहुपлатफॉर्म समर्थन
वाइड फॉर्मेट संगतता
कम लेटेंसी प्लेबैक
स्ट्रीम प्रोटोकॉल समर्थन
इनके लिए उपयुक्त
Flutter विकासक वीडियो प्लेयर बना रहे हैं
क्रॉस-प्लेटफ़ॉर्म वीडियो कार्यक्षमता की आवश्यकता वाले ऐप्स
प्रभावी वीडियो हैंडलिंग की आवश्यकता वाले प्रोजेक्ट्स
मीडिया-समृद्ध एप्लिकेशन्स
मीडिया_किट पारिस्थितिकी तंत्र का उपयोग करने वाले विकासकर्मी
विचार योग्य बातें
कुछ प्लेटफॉर्म पर मूल निर्भरता की आवश्यकता होती है
मुख्यधारा पैकेज की तुलना में सीमित दस्तावेज़ीकरण
उन्नत विशेषताओं के लिए अतिरिक्त कॉन्फ़िगरेशन की आवश्यकता हो सकती है
सरल उपयोग के मामलों के लिए आदर्श नहीं है जिसमें कम वीडियो की आवश्यकता हो
मूल README
संबंधित सोर्स रिपॉज़िटरी के मूल README का स्नैपशॉट। नवीनतम सामग्री के लिए रिपॉज़िटरी देखें।
MediaKit.ensureInitialized must be called before using the package:
voidmain() {
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#installationMediaKit.ensureInitialized();
runApp(constMyApp());
}
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.
finalPlayer player = Player();
Additional options may be provided using the configuration argument in the constructor. In general situations, you will never require this.
finalPlayer 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);
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).
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:
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().
Additional options may be provided using the configuration argument in the constructor. In general situations, you will never require this.
finalVideoController player = VideoController(
player,
configuration: constVideoControllerConfiguration(
// 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.
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:
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.
Pass custom builder Widget Function(BuildContext, VideoController) as controls argument.
Scaffold(
body: Video(
controller: controller,
// Provide custom builder for controls.
controls: (state) {
returnCenter(
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.
),
);
},
),
);
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:
API reference can be helpful for diving into deeper specifics.
if (/* Android 13 or higher. */) {
// Video permissions.if (awaitPermission.videos.isDenied || awaitPermission.videos.isPermanentlyDenied) {
final state = awaitPermission.videos.request();
if (!state.isGranted) {
awaitSystemNavigator.pop();
}
}
// Audio permissions.if (awaitPermission.audio.isDenied || awaitPermission.audio.isPermanentlyDenied) {
final state = awaitPermission.audio.request();
if (!state.isGranted) {
awaitSystemNavigator.pop();
}
}
} else {
if (awaitPermission.storage.isDenied || awaitPermission.storage.isPermanentlyDenied) {
final state = awaitPermission.storage.request();
if (!state.isGranted) {
awaitSystemNavigator.pop();
}
}
}
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;
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:
In case you prefer dynamic linking of mimalloc, you can additionally add the following line to your linux/CMakeLists.txt:
# use dynamically linked mimalloc
set(MIMALLOC_USE_STATIC_LIBS OFF)
In this case, please ensure you install libmimalloc-dev at compile time and libmimalloc2.0 as runtime dependencies.
Ubuntu/Debian
sudo apt install libmimalloc-dev libmimalloc2.0
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.
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, audioParamsStreams are important to render changes in the UI.
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.
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!
Update: The above issue is resolved in Dart SDK 3.1.0. NativeCallable can now be used to make async C callbacks.
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.
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.
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.
You may visit experimentation repository to see a minimal example showing OpenGL ES usage in Flutter Windows.