vlc_player 2.0.1
vlc_player: ^2.0.1 copied to clipboard
A Flutter plugin for video playback using VLC.
vlc_player #
A Flutter plugin for video playback using VLC.
vlc_player creates a native VLC-backed video view and exposes a Dart
controller for loading media, controlling playback, selecting tracks, handling
subtitles, reading playback state and media statistics, and capturing
snapshots.
Supported platforms #
- Android
- iOS
- macOS
- Windows
- Linux
The plugin forwards media URIs to the native VLC library. Supported media
formats, codecs, playlists, and stream protocols depend on the VLC runtime used
on the target platform. Common VLC-supported sources include MP4, MOV, MKV,
WebM, AVI, FLV, MPEG-TS, HLS (.m3u8), DASH, RTSP, and RTP.
Installation #
Add the package to your app:
dependencies:
vlc_player: ^2.0.1
Then run:
flutter pub get
Apps that embed this plugin must satisfy the binary distribution and license requirements for libVLC, MobileVLCKit, VLCKit, and the VLC Windows runtime. See THIRD_PARTY_NOTICES.md for the third-party runtime and source components that app distributors need to account for.
Platform setup #
Android #
Android apps must use minSdk 29 or newer.
Network playback requires internet access. The plugin manifest declares:
<uses-permission android:name="android.permission.INTERNET" />
iOS #
The iOS implementation depends on MobileVLCKit.
HTTPS media URLs work without extra transport configuration. If your app plays
non-HTTPS URLs, configure App Transport Security in the app's Info.plist.
macOS #
The macOS implementation depends on VLCKit.
For sandboxed apps that play network media, enable the network client entitlement:
<key>com.apple.security.network.client</key>
<true/>
Use CocoaPods 1.13.0 or newer so the VLCKit runtime path script phase runs
reliably.
Windows #
The Windows implementation downloads the VLC Windows runtime during
flutter build windows and bundles it into your app automatically:
build/windows/x64/runner/Release/
your_app.exe
libvlc.dll
libvlccore.dll
plugins/
The first Windows build requires network access to download the verified VLC runtime archive.
Linux #
The Linux implementation links against the system libVLC package through pkg-config. Install VLC development files before building a Linux app:
sudo apt install libvlc-dev vlc
Usage #
Create a player #
import 'package:flutter/material.dart';
import 'package:vlc_player/vlc_player.dart';
class VideoPage extends StatefulWidget {
const VideoPage({super.key});
@override
State<VideoPage> createState() => _VideoPageState();
}
class _VideoPageState extends State<VideoPage> {
late final VlcPlayerController controller = VlcPlayerController(
mediaSource: VlcMediaSource(
uri: Uri.parse('https://example.com/video.mp4'),
),
autoPlay: true,
);
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 16 / 9,
child: VlcPlayer(controller: controller),
);
}
}
setMedia() can be called before the controller is attached to a VlcPlayer.
Commands such as play(), pause(), and seekTo() require an attached player
and throw StateError if called too early or after disposal.
Play an HLS stream #
Pass the .m3u8 playlist URL as the media source:
final controller = VlcPlayerController(
mediaSource: VlcMediaSource(
uri: Uri.parse('https://example.com/live/playlist.m3u8'),
),
autoPlay: true,
);
Load media with headers and VLC options #
Use VlcMediaSource when a URL needs request headers, per-item VLC media
options, or an initial seek position:
await controller.setMedia(
VlcMediaSource(
uri: Uri.parse('https://example.com/protected/video.mp4'),
httpHeaders: const <String, String>{
'Authorization': 'Bearer token',
},
mediaOptions: const <String>[
':network-caching=1200',
],
startPosition: const Duration(seconds: 30),
),
autoPlay: true,
);
Control playback #
await controller.play();
await controller.pause();
await controller.seekTo(const Duration(seconds: 30));
await controller.setVolume(100);
await controller.setPlaybackSpeed(1.25);
await controller.setAudioDelay(const Duration(milliseconds: -120));
await controller.setSubtitleDelay(const Duration(milliseconds: 250));
await controller.stop();
Fit the video #
Use VlcPlayer.fit to choose how the video is fitted inside the widget:
VlcPlayer(
controller: controller,
fit: VlcVideoFit.cover,
)
Available values are contain, cover, fill, and none.
Capture a snapshot #
final pngBytes = await controller.takeSnapshot(width: 320);
debugPrint('snapshot bytes=${pngBytes.length}');
When only width or height is provided, VLC preserves the source aspect ratio
where the platform backend supports it.
Play a playlist #
await controller.setPlaylist(
<VlcMediaSource>[
VlcMediaSource(uri: Uri.parse('https://example.com/episode-1.mp4')),
VlcMediaSource(uri: Uri.parse('https://example.com/episode-2.mp4')),
],
autoPlay: true,
autoAdvance: true,
loopMode: VlcPlaylistLoopMode.loopAll,
);
await controller.next();
await controller.previous();
await controller.jumpTo(0);
await controller.addToPlaylist(
VlcMediaSource(uri: Uri.parse('https://example.com/bonus.mp4')),
);
await controller.shufflePlaylist(seed: 42);
Playlist state is available through playlist, playlistIndex,
playlistLoopMode, currentMediaSource, hasNext, and hasPrevious.
Select tracks and subtitles #
final audioTracks = await controller.getAudioTracks();
if (audioTracks.isNotEmpty) {
await controller.setAudioTrack(audioTracks.first.id);
}
final subtitleTracks = await controller.getSubtitleTracks();
if (subtitleTracks.isNotEmpty) {
await controller.setSubtitleTrack(subtitleTracks.first.id);
}
await controller.addSubtitle(Uri.file('/path/to/subtitles.srt'));
await controller.disableSubtitle();
final info = await controller.getMediaInfo();
debugPrint('duration=${info.duration}');
final stats = await controller.getMediaStats();
if (stats.isAvailable) {
debugPrint('decoded video blocks=${stats.decodedVideo}');
}
Track selection methods use native VLC track ids returned by
getAudioTracks() and getSubtitleTracks().
Listen for state changes #
VlcPlayerController extends ValueNotifier<VlcPlayerValue>.
ValueListenableBuilder<VlcPlayerValue>(
valueListenable: controller,
builder: (context, value, child) {
return Text('${value.state} ${value.position}');
},
)
Native platform failures throw VlcPlayerException and may also be exposed
through VlcPlayerValue.error.
try {
await controller.play();
} on VlcPlayerException catch (error) {
debugPrint('VLC command failed: ${error.code} ${error.message}');
}
API #
The supported application-facing API is exported from:
import 'package:vlc_player/vlc_player.dart';
Native view attachment, texture creation, method channels, and platform view type details are implementation internals.
VlcPlayer #
VlcPlayer is the Flutter widget that hosts the native VLC video output.
const VlcPlayer({
Key? key,
required VlcPlayerController controller,
Color backgroundColor = Colors.black,
VlcVideoFit fit = VlcVideoFit.contain,
})
controller: controller used to load media, control playback, and observe state.backgroundColor: color shown behind the native video output.fit: video fitting behavior inside the widget bounds.
VlcPlayerController #
VlcPlayerController owns playback state and sends commands to the native VLC
player.
VlcPlayerController({
VlcMediaSource? mediaSource,
bool autoPlay = false,
List<String> options = const <String>[],
Duration? eventThrottleInterval,
})
mediaSource: optional initial media item.autoPlay: starts playback after the initial media source is loaded.options: VLC instance options applied when the native player is created.eventThrottleInterval: optional interval for coalescing progress-only native events.
Important properties:
value: currentVlcPlayerValue.isAttached: whether the controller is attached to a native player.playlist,playlistIndex,playlistLoopMode: current playlist state.currentMediaSource: active or pending media source.hasNext,hasPrevious: whether playlist navigation can move without wrapping.
Media and playlist methods:
setMedia(VlcMediaSource source, {bool autoPlay = false})setPlaylist(List<VlcMediaSource> sources, {int initialIndex = 0, bool autoPlay = false, bool autoAdvance = true, VlcPlaylistLoopMode loopMode = VlcPlaylistLoopMode.none})next({bool autoPlay = true})previous({bool autoPlay = true})jumpTo(int index, {bool autoPlay = true})addToPlaylist(VlcMediaSource source)insertIntoPlaylist(int index, VlcMediaSource source)removeFromPlaylistAt(int index, {bool autoPlay = true})clearPlaylist()shufflePlaylist({int? seed})
Playback methods:
play()pause()stop()seekTo(Duration position)setVolume(int volume)setPlaybackSpeed(double speed)setAudioDelay(Duration delay)setSubtitleDelay(Duration delay)takeSnapshot({int? width, int? height})
Track, subtitle, and media information methods:
getAudioTracks()setAudioTrack(int id)getSubtitleTracks()setSubtitleTrack(int id)disableSubtitle()addSubtitle(Uri uri)getMediaInfo()getMediaStats()
setVolume() clamps values to VLC's 0..200 range. seekTo() requires a
non-negative position. setPlaybackSpeed() requires a finite value greater
than zero.
VlcMediaSource #
VlcMediaSource describes one media item before it is passed to VLC.
VlcMediaSource({
required Uri uri,
Map<String, String> httpHeaders = const <String, String>{},
List<String> mediaOptions = const <String>[],
Duration startPosition = Duration.zero,
})
uri: non-empty media URI to load.httpHeaders: HTTP headers used when opening the media.mediaOptions: VLC media options applied only to this source.startPosition: non-negative initial playback position.
VlcPlayerValue #
VlcPlayerValue is the immutable playback snapshot emitted by the controller.
Fields:
statepositiondurationvolumeplaybackSpeedaudioDelaysubtitleDelayisReadyisSeekableisLivevideoSizebufferingProgresserrorerrorDescription
Convenience getters:
isPlayingisBufferinghasError
VlcPlaybackState #
Possible playback states:
idleopeningbufferingplayingpausedstoppedendederror
VlcVideoFit #
Possible video fitting values:
containcoverfillnone
VlcPlaylistLoopMode #
Possible playlist loop values:
noneloopOneloopAll
Track, media information, and media statistics #
getAudioTracks() and getSubtitleTracks() return
VlcTrackDescription objects:
id: native VLC track id.name: track name reported by VLC.language: optional language code or label reported by VLC.
getMediaInfo() returns VlcMediaInfo:
title,artist,album: metadata discovered by VLC when available.duration: media duration, orDuration.zerowhen unknown.videoTracks,audioTracks,subtitleTracks: lists ofVlcMediaTrackInfo.
VlcMediaTrackInfo includes type, codec, language, bitrate, width,
height, channels, and sampleRate. These values are best-effort because
containers and streams do not always expose every field.
getMediaStats() returns VlcMediaStats:
isAvailable: whether VLC reported statistics for the current media.readBytes,inputBitrate: current input module counters.demuxReadBytes,demuxBitrate,demuxCorrupted,demuxDiscontinuity: current demux counters.decodedVideo,decodedAudio: decoded block counters.displayedPictures,lostPictures: video output counters.playedAudioBuffers,lostAudioBuffers: audio output counters.sentPackets,sentBytes,sendBitrate: stream-output counters.
When no media is loaded or VLC cannot provide statistics, isAvailable is
false and the numeric values are zero.
Errors #
Native command failures are exposed as VlcPlayerException, which wraps a
structured VlcPlayerError.
VlcPlayerError exposes:
codemessagedetailsdescription
Common error codes are available in VlcPlayerErrorCode, including
invalidArgs, playerNotFound, createFailed, setSourceFailed,
trackNotFound, addSubtitleFailed, playbackError, disposed, and
eventChannelError.
API stability #
The 2.x line follows Semantic Versioning. Backward-compatible additions use
minor versions, fixes use patch versions, and breaking API, platform, or
behavior changes use major versions.
Native view attachment, texture creation, method channels, platform view type
strings, and generated platform registration details are implementation
internals. Applications should import only package:vlc_player/vlc_player.dart
and use the public types documented above.
Migrating from 1.x or 0.8.x #
Version 2.0.0 requires Android minSdk 29 or newer.
The Dart-facing API remains backward compatible, but Android apps that still target a lower minimum SDK must raise it before upgrading.
Migrating from 0.7.21 or earlier #
For apps migrating from older releases that used source, httpHeaders, or
setSource(), use VlcMediaSource and setMedia() instead:
final controller = VlcPlayerController(
mediaSource: VlcMediaSource(
uri: Uri.parse('https://example.com/video.mp4'),
httpHeaders: const <String, String>{
'Authorization': 'Bearer token',
},
),
autoPlay: true,
);
await controller.setMedia(
VlcMediaSource(uri: Uri.parse('https://example.com/next.mp4')),
autoPlay: true,
);
Troubleshooting #
player_not_found #
This usually means a command was sent after the native player was disposed or
before the controller attached to the current VlcPlayer. Keep one
VlcPlayerController per player widget and call dispose() from the owning
widget's dispose() method.
Network playback fails #
Check that:
- The media URL is reachable from the device.
- Android has internet permission.
- macOS sandboxed apps have the network client entitlement.
- iOS allows the URL through App Transport Security if it is not HTTPS.
- Required HTTP headers are passed through
VlcMediaSource.httpHeaders. - Linux has
libvlc-devandvlcinstalled.
macOS Library not loaded: VLCKit #
Run pod install in the macOS app directory and rebuild:
cd macos
pod install
cd ..
flutter build macos
Also make sure CocoaPods is 1.13.0 or newer.