av_player 0.2.1
av_player: ^0.2.1 copied to clipboard
A powerful Flutter video player with native Picture-in-Picture support, gesture controls, media notifications, and playlist management. Zero external dependencies.
AV Player #
A powerful Flutter video player with native Picture-in-Picture, gesture controls, media notifications, playlist management, and theming — all with zero external dependencies. Uses native platform players directly (ExoPlayer, AVPlayer, GStreamer, HTML5 Video).
Built by FlutterPlaza.

Features #
- Native PIP on Android, iOS, macOS, and Web
- In-app PIP overlay on all platforms (draggable, corner-snapping)
- Video playback from network URL, HLS/DASH stream, asset, or file
- Gesture controls — double-tap skip, swipe volume/brightness, long-press speed, horizontal swipe seek
- Media notifications — lock screen and notification bar controls
- Playlist management — queue, shuffle, repeat (none / one / all)
- Content-type presets —
.video(),.music(),.live(),.short() - Theming — full color customization via
AVPlayerTheme - Playback speed — 0.25x to 3.0x
- Background audio playback
- System volume & brightness control
- Wakelock support
- Zero external dependencies — uses native platform players directly
Platform Support #
| Feature | Android | iOS | macOS | Linux | Windows | Web |
|---|---|---|---|---|---|---|
| Video Playback | Yes | Yes | Yes | Yes | Stub | Yes |
| Native PIP | Yes | Yes | Yes | — | — | Yes |
| In-App PIP | Yes | Yes | Yes | Yes | Yes | Yes |
| Media Notifications | Yes | Yes | — | Yes | — | Yes |
| System Volume | Yes | Read-only | Yes | Yes | — | Per-element |
| Brightness | Yes | Yes | Built-in only | sysfs | — | — |
| Wakelock | Yes | Yes | Yes | Yes | — | Yes |
Installation #
dependencies:
av_player: ^0.2.1
import 'package:av_player/av_player.dart';
iOS & macOS — Swift Package Manager #
This plugin supports both CocoaPods and Swift Package Manager (SPM) for iOS and macOS.
CocoaPods (default) #
No extra setup is required. flutter build uses CocoaPods automatically.
Swift Package Manager #
Flutter 3.24.5+ can resolve iOS and macOS dependencies through SPM instead of CocoaPods. To enable it:
flutter config --enable-swift-package-manager
Then build as usual:
cd example
flutter build ios # or: flutter build macos
Flutter detects the Package.swift files in ios/av_player/ and macos/av_player/ and resolves the plugin through SPM. No Podfile changes are needed — if SPM is enabled, Flutter prefers it; otherwise it falls back to CocoaPods.
To disable SPM and return to CocoaPods:
flutter config --no-enable-swift-package-manager
Quick Start #
class MyPlayer extends StatefulWidget {
const MyPlayer({super.key});
@override
State<MyPlayer> createState() => _MyPlayerState();
}
class _MyPlayerState extends State<MyPlayer> {
late final AVPlayerController _controller;
@override
void initState() {
super.initState();
_controller = AVPlayerController(
const AVVideoSource.network('https://example.com/video.mp4'),
)..initialize();
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<AVPlayerState>(
valueListenable: _controller,
builder: (context, state, _) {
return AspectRatio(
aspectRatio: state.aspectRatio,
child: AVVideoPlayer.video(_controller, title: 'My Video'),
);
},
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
Content-Type Presets #
AV Player provides four presets that configure controls and gestures for different content types.
Video Player — .video() #
Full controls with all features enabled: play/pause, seek bar, skip forward/backward, speed selector, loop toggle, PIP button, fullscreen button, and gesture controls.

AVVideoPlayer.video(
controller,
title: 'My Video',
onFullscreen: () => enterFullscreen(),
)
Shorts — .short() #
Minimal UI for vertical short-form content (TikTok/Reels/Shorts style). Only play/pause center button with double-tap and long-press gestures. Set looping for continuous replay.

// Enable looping after initialization
controller.setLooping(true);
controller.play();
AVVideoPlayer.short(controller)
Music Player — .music() #
Audio-focused controls with skip next/previous, speed, and loop. Disables PIP and fullscreen since the video surface is used for album art or visualizer.

AVVideoPlayer.music(
controller,
title: 'Song Name',
onNext: () => playlist.next(),
onPrevious: () => playlist.previous(),
)
Live Stream — .live() #
Live content preset. Disables seek bar, skip buttons, and speed control since live streams cannot be seeked. Only play/pause, PIP, and fullscreen remain.

AVVideoPlayer.live(controller, title: 'LIVE')
Picture-in-Picture #
Native PIP #
Uses the OS-level picture-in-picture window. Supported on Android, iOS, macOS, and Web.

// Enter native PIP
await controller.enterPip();
// Exit native PIP
await controller.exitPip();
// Check availability
final available = await controller.isPipAvailable();
In-App PIP Overlay #
A draggable, corner-snapping mini-player overlay that works on all platforms. Place it in your app's top-level Stack.

Stack(
children: [
// Your app content
Navigator(...),
// Floating PIP overlay
if (showPip)
AVPipOverlay(
controller: controller,
initialSize: AVPipSize.medium, // small, medium, large
initialCorner: AVPipCorner.bottomRight,
onClose: () => setState(() => showPip = false),
onExpand: () => navigateToFullPlayer(),
),
],
)
Gesture Controls #
Gesture controls are enabled automatically with the .video() and .short() presets. You can also configure them manually.

| Gesture | Action |
|---|---|
| Tap | Show/hide controls overlay |
| Double-tap right | Skip forward 10s |
| Double-tap left | Skip backward 10s |
| Long press | Play at 2x speed while held |
| Swipe up/down (right side) | Adjust volume |
| Swipe up/down (left side) | Adjust brightness |
| Horizontal swipe | Seek through video |
AVVideoPlayer(
controller,
showControls: true,
gestureConfig: const AVGestureConfig(
doubleTapToSeek: true,
seekDuration: Duration(seconds: 10),
longPressSpeed: true,
longPressSpeedMultiplier: 2.0,
swipeToVolume: true,
swipeToBrightness: true,
horizontalSwipeToSeek: false,
),
)
Playlist Management #
AVPlaylistController manages a queue of video sources with navigation, repeat modes, and shuffle.

final playlist = AVPlaylistController(
sources: [
const AVVideoSource.network('https://example.com/track1.mp4'),
const AVVideoSource.network('https://example.com/track2.mp4'),
const AVVideoSource.network('https://example.com/track3.mp4'),
],
onSourceChanged: (source) async {
// Reinitialize the player with the new source
controller.dispose();
controller = AVPlayerController(source);
await controller.initialize();
await controller.play();
},
);
// Navigation
playlist.next();
playlist.previous();
playlist.jumpTo(2);
// Repeat modes: none, one, all
playlist.setRepeatMode(AVRepeatMode.all);
// Shuffle
playlist.setShuffle(true);
// Queue management
playlist.add(const AVVideoSource.network('https://example.com/track4.mp4'));
playlist.removeAt(1);
playlist.reorder(0, 2);
// Auto-advance on completion
controller.addListener(() {
if (controller.value.isCompleted) {
playlist.onTrackCompleted();
}
});
Theming #
Customize the player's appearance with AVPlayerTheme. All controls, gestures, and PIP overlay respect the theme.

AVPlayerTheme(
data: const AVPlayerThemeData(
accentColor: Colors.deepOrange,
iconColor: Colors.white,
overlayColor: Color(0x61000000),
sliderActiveColor: Colors.deepOrange,
sliderThumbColor: Colors.deepOrange,
sliderBufferColor: Color(0x62FFFFFF),
sliderInactiveColor: Color(0x3DFFFFFF),
progressBarColor: Colors.deepOrange,
),
child: AVVideoPlayer.video(controller),
)
Replay #
When a video completes, the controls automatically show a replay icon. Tapping play (or the replay icon) seeks to the beginning and restarts playback.
![]()
Media Notifications #
Display playback info on the lock screen and notification bar with media command support.
// Set metadata
await controller.setMediaMetadata(const AVMediaMetadata(
title: 'Video Title',
artist: 'Artist Name',
album: 'Album Name',
));
// Enable/disable notification
await controller.setNotificationEnabled(true);
// Handle media commands (next, previous, seek)
final controller = AVPlayerController(
source,
onMediaCommand: (command, {seekPosition}) {
switch (command) {
case AVMediaCommand.next:
playlist.next();
case AVMediaCommand.previous:
playlist.previous();
default:
break;
}
},
);
Custom Controls #
Replace the built-in controls with your own widget using controlsBuilder.
AVVideoPlayer(
controller,
showControls: true,
controlsBuilder: (context, controller) {
return ValueListenableBuilder<AVPlayerState>(
valueListenable: controller,
builder: (context, state, _) {
return Center(
child: IconButton(
iconSize: 64,
icon: Icon(state.isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: () {
state.isPlaying ? controller.pause() : controller.play();
},
),
);
},
);
},
)
API Reference #
AVPlayerController #
| Method | Description |
|---|---|
initialize() |
Create the native player and start listening for events |
play() |
Start or resume playback (seeks to start if completed) |
pause() |
Pause playback |
seekTo(Duration) |
Seek to position |
setPlaybackSpeed(double) |
Set speed (0.25–3.0) |
setLooping(bool) |
Enable/disable looping |
setVolume(double) |
Set player volume (0.0–1.0) |
enterPip() |
Enter native Picture-in-Picture |
exitPip() |
Exit native Picture-in-Picture |
isPipAvailable() |
Check if PIP is supported |
setMediaMetadata(AVMediaMetadata) |
Set notification metadata |
setNotificationEnabled(bool) |
Toggle media notification |
setSystemVolume(double) |
Set system volume (0.0–1.0) |
getSystemVolume() |
Get current system volume |
setScreenBrightness(double) |
Set screen brightness (0.0–1.0) |
getScreenBrightness() |
Get current brightness |
setWakelock(bool) |
Prevent screen from sleeping |
dispose() |
Release native resources |
AVPlayerState #
| Property | Type | Description |
|---|---|---|
position |
Duration |
Current playback position |
duration |
Duration |
Total video duration |
buffered |
Duration |
Amount buffered |
isPlaying |
bool |
Whether currently playing |
isBuffering |
bool |
Whether buffering |
isLooping |
bool |
Whether looping is enabled |
isInitialized |
bool |
Whether the player is ready |
isInPipMode |
bool |
Whether in native PIP |
isCompleted |
bool |
Whether playback has finished |
playbackSpeed |
double |
Current speed multiplier |
volume |
double |
Player volume |
aspectRatio |
double |
Video aspect ratio |
errorDescription |
String? |
Error message if failed |
Example App #
The example app includes 8 dedicated screens showcasing each feature. Run it with:
cd example
flutter run
See example/lib/main.dart for the full source.
Linux Build Dependencies #
sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpulse-dev libgtk-3-dev
Contributing #
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
License #
This project is licensed under the BSD 3-Clause License — see the LICENSE file for details.