Multimedia Player

A production-grade, cross-platform Flutter video player package supporting network URLs, local files, assets, RTSP, HLS, DASH with customizable controls and memory-efficient playback.

pub package License

Features

🎥 Comprehensive Video Source Support

  • Network URLs (HTTP/HTTPS)
  • Local Files from device storage
  • Asset Videos bundled with your app
  • RTSP Streams for real-time streaming
  • HLS (.m3u8) adaptive streaming
  • DASH adaptive streaming
  • Custom HTTP headers for authenticated sources

🎮 Rich Controls & Customization

  • Default Beautiful Controls - Play/pause, seek, volume, fullscreen out-of-the-box
  • Fully Customizable UI - Replace controls with your own design
  • Playback Speed Control - 0.5x to 2.0x with custom speeds
  • Volume Control - Slider and mute toggle
  • Seek Controls - Forward/backward with configurable duration
  • Fullscreen Mode - Native fullscreen support
  • Auto-hide Controls - Configurable timeout

Performance & Memory Efficiency

  • Automatic Resource Management - Proper disposal and lifecycle handling
  • Visibility-based Auto-pause - Pause videos when scrolled out of view
  • Memory-efficient List Support - Optimized for ListView/PageView
  • Lazy Initialization - Load players only when needed
  • Concurrent Player Limits - Prevent memory issues with multiple players

🎨 Developer Experience

  • Beginner-Friendly - Simple API for quick integration
  • Expert-Ready - Deep customization hooks for advanced use cases
  • Event Callbacks - Listen to play, pause, buffering, completion, errors
  • Type-Safe - Full null safety support
  • Well Documented - Comprehensive API documentation and examples

Platform Support

Platform Supported Notes
Android Uses ExoPlayer for optimal performance
iOS Uses AVPlayer
Web HTML5 video element
macOS AVPlayer
Windows Media Foundation
Linux GStreamer

Installation

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

dependencies:
  multimedia_player: ^0.1.0

Then run:

flutter pub get

Quick Start

Basic Usage

import 'package:flutter/material.dart';
import 'package:multimedia_player/multimedia_player.dart';

class SimpleVideoPlayer extends StatefulWidget {
  @override
  State<SimpleVideoPlayer> createState() => _SimpleVideoPlayerState();
}

class _SimpleVideoPlayerState extends State<SimpleVideoPlayer> {
  late MultimediaVideoController _controller;

  @override
  void initState() {
    super.initState();
    _controller = MultimediaVideoController(
      source: VideoSource.network(
        'https://example.com/video.mp4',
      ),
      config: const VideoPlayerConfig(
        autoPlay: true,
        looping: true,
      ),
    );
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AspectRatio(
          aspectRatio: 16 / 9,
          child: MultimediaVideoPlayer(
            controller: _controller,
          ),
        ),
      ),
    );
  }
}

Usage Examples

Different Video Sources

Network Video

final controller = MultimediaVideoController(
  source: VideoSource.network(
    'https://example.com/video.mp4',
    headers: {'Authorization': 'Bearer token'}, // Optional headers
  ),
);

Local File

final controller = MultimediaVideoController(
  source: VideoSource.file(File('/path/to/video.mp4')),
);

Asset Video

final controller = MultimediaVideoController(
  source: VideoSource.asset('assets/videos/intro.mp4'),
);

HLS Stream

final controller = MultimediaVideoController(
  source: VideoSource.hls('https://example.com/stream.m3u8'),
);

RTSP Stream

final controller = MultimediaVideoController(
  source: VideoSource.rtsp('rtsp://example.com:8554/stream'),
);

Advanced Configuration

final controller = MultimediaVideoController(
  source: VideoSource.network('https://example.com/video.mp4'),
  config: VideoPlayerConfig(
    autoPlay: true,
    looping: false,
    volume: 0.8,
    playbackSpeed: 1.0,
    muted: false,
    fit: BoxFit.cover,
    controlsTimeout: Duration(seconds: 5),
    showPlaybackSpeed: true,
    showVolumeControl: true,
    doubleTapToSeek: true,
    seekDuration: Duration(seconds: 10),
    backgroundColor: Colors.black,
  ),
);

Custom Controls

MultimediaVideoPlayer(
  controller: controller,
  controlsBuilder: (controller) {
    return MyCustomControls(controller: controller);
  },
)

Event Handling

controller.onPlay(() {
  print('Video started playing');
});

controller.onPause(() {
  print('Video paused');
});

controller.onBuffering(() {
  print('Buffering...');
});

controller.onCompleted(() {
  print('Playback completed');
});

controller.onError((error) {
  print('Error: $error');
});

controller.onPositionChanged((position) {
  print('Position: ${position.inSeconds}s');
});

Video List with Auto-Pause

Perfect for social media feeds or video galleries:

class VideoListItem extends StatefulWidget {
  final String videoUrl;

  const VideoListItem({required this.videoUrl});

  @override
  State<VideoListItem> createState() => _VideoListItemState();
}

class _VideoListItemState extends State<VideoListItem> {
  late MultimediaVideoController _controller;

  @override
  void initState() {
    super.initState();
    _controller = MultimediaVideoController(
      source: VideoSource.network(widget.videoUrl),
      config: VideoPlayerConfig.forList(
        autoPlay: false,
        pauseOnInvisible: true,  // Auto-pause when scrolled out
      ),
    );
  }

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

  @override
  Widget build(BuildContext context) {
    return MultimediaVideoPlayer(
      controller: _controller,
      enableVisibilityTracking: true,
      visibilityKey: ValueKey(widget.videoUrl),
    );
  }
}

Programmatic Control

// Play/Pause
await controller.play();
await controller.pause();
await controller.togglePlayPause();

// Seeking
await controller.seekTo(Duration(seconds: 30));
await controller.seekForward(Duration(seconds: 10));
await controller.seekBackward(Duration(seconds: 10));

// Playback Speed
await controller.setPlaybackSpeed(1.5);

// Volume
await controller.setVolume(0.5);
await controller.setMuted(true);
await controller.toggleMute();

// Looping
await controller.setLooping(true);

// Fullscreen
controller.toggleFullscreen();
controller.setFullscreen(true);

State Management

// Listen to state changes
AnimatedBuilder(
  animation: controller,
  builder: (context, child) {
    final state = controller.state;

    return Column(
      children: [
        Text('Status: ${state.status}'),
        Text('Position: ${FormatHelper.formatDuration(state.position)}'),
        Text('Duration: ${FormatHelper.formatDuration(state.duration)}'),
        Text('Buffered: ${state.bufferPercentage * 100}%'),
        Text('Playing: ${state.isPlaying}'),
      ],
    );
  },
)

// Or use StreamBuilder
StreamBuilder<PlaybackState>(
  stream: controller.stateStream,
  builder: (context, snapshot) {
    final state = snapshot.data;
    if (state == null) return SizedBox();

    return Text('${state.position} / ${state.duration}');
  },
)

API Reference

MultimediaVideoController

Main controller for video playback.

Constructor:

MultimediaVideoController({
  required VideoSource source,
  VideoPlayerConfig? config,
})

Methods:

  • Future<void> initialize() - Initialize the player
  • Future<void> play() - Start playback
  • Future<void> pause() - Pause playback
  • Future<void> togglePlayPause() - Toggle play/pause
  • Future<void> seekTo(Duration position) - Seek to position
  • Future<void> seekForward([Duration? duration]) - Seek forward
  • Future<void> seekBackward([Duration? duration]) - Seek backward
  • Future<void> setPlaybackSpeed(double speed) - Set playback speed
  • Future<void> setVolume(double volume) - Set volume (0.0-1.0)
  • Future<void> setMuted(bool muted) - Mute/unmute
  • Future<void> toggleMute() - Toggle mute
  • Future<void> setLooping(bool looping) - Enable/disable looping
  • void toggleFullscreen() - Toggle fullscreen
  • void dispose() - Clean up resources

Properties:

  • PlaybackState state - Current playback state
  • Stream<PlaybackState> stateStream - Stream of state changes
  • bool isInitialized - Whether initialized
  • Duration position - Current position
  • Duration duration - Total duration
  • double aspectRatio - Video aspect ratio

Event Callbacks:

  • void onPlay(VideoEventCallback callback)
  • void onPause(VideoEventCallback callback)
  • void onBuffering(VideoEventCallback callback)
  • void onCompleted(VideoEventCallback callback)
  • void onError(VideoErrorCallback callback)
  • void onPositionChanged(VideoPositionCallback callback)

VideoSource

Factory constructors for different video sources:

VideoSource.network(String url, {Map<String, String>? headers})
VideoSource.file(File file)
VideoSource.asset(String assetPath, {String? package})
VideoSource.rtsp(String url, {Map<String, String>? headers})
VideoSource.hls(String url, {Map<String, String>? headers})
VideoSource.dash(String url, {Map<String, String>? headers})

VideoPlayerConfig

Configuration options for the player. See source for all available options.

Factory Constructors:

  • VideoPlayerConfig.forList() - Optimized for lists
  • VideoPlayerConfig.minimal() - Minimal UI

Performance Best Practices

  1. Always dispose controllers when done:

    @override
    void dispose() {
      _controller.dispose();
      super.dispose();
    }
    
  2. Use visibility tracking for lists:

    config: VideoPlayerConfig.forList(pauseOnInvisible: true)
    
  3. Limit concurrent players - Avoid more than 3 simultaneous video players

  4. Use appropriate video formats:

    • HLS for adaptive streaming
    • MP4 for compatibility
    • Lower resolutions for mobile networks
  5. Preload strategically - Initialize players just before needed

Known Limitations

Feature Android iOS Web Notes
RTSP Streams Not supported on web
Background Playback ⚠️ ⚠️ Requires additional configuration
Picture-in-Picture ⚠️ ⚠️ Platform-specific implementation needed
DRM Not currently supported
Subtitles ⚠️ ⚠️ ⚠️ Planned for future release

Troubleshooting

Video not playing

  • Check network connectivity
  • Verify video URL is accessible
  • Check CORS headers for web
  • Ensure video format is supported

Memory issues

  • Limit concurrent players to 3 or fewer
  • Always dispose controllers
  • Use pauseOnInvisible for lists

Controls not showing

  • Check showControls parameter
  • Verify controlsTimeout isn't too short
  • Tap video to toggle controls

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Acknowledgments

Built on top of the excellent video_player package by the Flutter team.

Libraries

multimedia_player
Multimedia Player - Production-grade Flutter video player package