zeroratehls 1.0.7

SDKflutter
Platformandroidioslinux

A comprehensive Flutter SDK for seamless HLS (HTTP Live Streaming) video playback. This package provides a robust, feature-rich player with advanced capabilities including adaptive bitrate streaming, seek preview, custom controls, subtitle support, picture-in-picture mode, and quality selection.

zeroratehls

A robust HLS video player SDK with built-in quality switching, live stream support for flutter.

Features

  • Cross-platform support: Android, iOS, and Linux
  • Supports HLS & MP4 video and audio playback
  • Adaptive bitrate streaming
  • Handles live and on-demand streaming
  • Preview frames while seeking through the video(Android, iOS,)
  • Live stream support with DVR
  • Customizable UI components
  • Dynamic source switching
  • Linux optimization for TV platforms

Platform Support

PlatformVideo PlaybackAudio PlaybackSeek PreviewPicture-in-Picture
Android
iOS
Linux

Installation

Add zeroratehls to your pubspec.yaml file:

dependencies:
  zeroratehls: ^1.0.5

Run the install command:

flutter pub get

Setup

Basic Setup

All platforms require SDK initialization in your main function:

import 'package:zeroratehls/zerorate_hls_player.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  ZerorateHlsSDK.initialize(); // Required for cross-platform support
  
  runApp(MyApp());
}

Android Setup

For Android, add the following to your AndroidManifest.xml file (required for HTTP streams):

<application
    android:usesCleartextTraffic="true"
    ...>

IOS Setup

⚠️ Note: iOS requires a minimum deployment target of 14.0 due to ffmpeg_kit_flutter_new No additional setup required

Linux Setup

Linux support is automatically configured when you call ZerorateHlsSDK.initialize(). No additional setup required.

⚠️ Note: On Linux, seek preview thumbnails are disabled for optimal performance on TV platforms.

Basic Usage

Video Player

import 'package:zeroratehls/zerorate_hls_player.dart.dart';

ZerorateHlsPlayer(
  options: ZerorateHlsPlayerOptions(
    appId: 'your-app-id',
    region: 'region-code',
    src: 'https://example.com/video.m3u8',
    type: MediaType.video,
    aspectRatio: 16 / 9,
    autoplay: true,
  ),
)

Audio Player

ZerorateHlsPlayer(
  options: ZerorateHlsPlayerOptions(
    appId: 'your-app-id',
    region: 'region-code',
    src: 'https://example.com/audio.m3u8',
    type: MediaType.audio,
    poster: 'https://example.com/poster.jpg',
    autoplay: false,
  ),
)

Configuration Options

Video Configuration

ZerorateHlsPlayerOptions(
  // Required parameters
  appId: 'your-app-id',
  region: 'region-code',
  src: 'https://example.com/video.m3u8',
  type: MediaType.video,

  // ⭐ IMPORTANT: 
  // 🔒 User Authentication for Protected Content
  // - subscriberId and authUrl are REQUIRED for paid/protected content
  // - If accessing a paid or protected stream, you MUST provide these
  // - Omitting these for protected content will prevent the stream from loading

  // - subscriberId: A unique identifier for the user accessing the stream
  //   * This is typically a user-specific ID from your authentication system
  //   * Helps track and validate individual user access
  //   * Example: user's email, internal user ID, or generated unique token
  subscriberId: 'unique-user-identifier', 
  
  // - authUrl: The authentication endpoint provided by the content provider
  //   * This URL is used to validate the user's access to the stream
  //   * The backend will use the subscriberId to check user permissions
  //   * Provided by the content/streaming service developer
  authUrl: 'https://your-content-provider-auth-endpoint', 
  
  // Optional parameters
  mediaType: StreamType.onDemand, // or StreamType.live
  autoplay: true,
  muted: false,
  aspectRatio: 16 / 9,

  // The placeholder is a widget displayed before video playback begins. It serves multiple purposes:
  // - Provides visual feedback while the video is loading
  // - Shows a preview or poster image
  // - Improves user experience during initial load
  
  // Placeholder Hierarchy

  // 1. **Explicitly Provided Placeholder**
  //    - Highest priority
  //    - Custom widget you define

  // 2. **Poster Image**
  //    - Used if no custom placeholder is provided
  //    - Static image representing the video

  // 3. **Automatic PlaceHolder which could take a few seconds to come up**
  //    - Automatically extracts a placeholder from thw provided video source
  //    - Provides a dynamic preview of the video content

  // Custom placeholder widget
  placeholder: YourCustomWidget(),

  // Or use a poster image
  poster: 'https://example.com/poster.jpg',
  placeholderOnTop: true,
  
  // Video specific controls
  videoControlsConfig: VideoControlsConfig(
    enableSeekPreview: true,  // Enable thumbnail preview during seeking
    enablePlayPause: true,
    enableProgressBar: true,
    progressBarColor: Colors.red,
    useDefaultControls: true, // Set to false to use your own controls

    // You can add multiple subtitle files to your video configuration:
    // Subtitle Source Types
    // - Supports local asset files
    // - Supports network subtitle files
    subtitles: [
      SubtitleSource(
        path: 'assets/subtitles/movie_en.srt', 
        languageCode: 'en',
        name: 'English Subtitles'
        type: SubtitleSourceType.asset,
      ),
      SubtitleSource(
        path: 'http/link_to_subtitle', 
        languageCode: 'es',
        name: 'Spanish Subtitles'
        type: SubtitleSourceType.network,
      ),
    ],

    /// Video Resolution Configuration
    /// 
    /// You can add multiple video resolutions to your video configuration:
    /// 
    /// - Specify resolution name and corresponding URL

    resolutions: [
      VideoResolution(
        url: 'https://example.com/video_720p.m3u8', 
        name: '720p'
      ),
      VideoResolution(
        url: 'https://example.com/video_1080p.m3u8', 
        name: '1080p'
      ),
    ]
  ),
)

Audio Configuration

ZerorateHlsPlayerOptions(
  // Required parameters
  appId: 'your-app-id',
  region: 'region-code',
  src: 'https://example.com/audio.m3u8',
  type: MediaType.audio,
  
  // Optional parameters
  mediaType: StreamType.onDemand,
  autoplay: false,
  aspectRatio: 16 / 9,
  poster: 'https://example.com/poster.jpg',
  
  // Audio specific controls
  audioControlsConfiguration: AudioControlsConfiguration(
    enableProgressBar: true,
    enableProgressText: true,
    enableVolumeControl: true,
    enableSpeedControl: true,    // Allow changing playback speed
    progressBarColor: Colors.blue,
    textColor: Colors.white,
    useDefaultControls: true,    // Set to false to use your own controls
  ),
)

Event Handling

Listen to player events to respond to changes in playback state:

ZerorateHlsPlayerEventType Enum

Event TypeDescriptionPayload TypeTypical Use Case
playTriggered when media starts playingnullTrack when playback begins
pauseTriggered when media is pausednullMonitor pause interactions
seekedTriggered after seeking to a new positionDurationTrack user navigation
bufferingStartIndicates the start of bufferingnullHandle loading states
bufferingEndIndicates buffering has completednullResume UI interactions
errorOccurs when a playback error happensExceptionError handling and logging
loadedMedia source successfully loadedDuration?Prepare player after loading
positionChangedPeriodic update of playback positionDurationProgress tracking
completedMedia playback finishednullHandle end of media
thumbnailGeneratedThumbnail created during seek previewMap<String, dynamic>Custom thumbnail handling
controlsVisibilityChangedControls visibility toggledboolUI state management
qualityChangedStream quality changeddynamicQuality tracking
volumeChangedVolume level modifieddoubleVolume control tracking
audioStateChangedAudio-specific state changesMap<String, dynamic>Audio playback monitoring
ZerorateHlsPlayerOptions(
  // Basic options
  appId: 'your-app-id',
  region: 'region-code',
  src: 'https://example.com/video.m3u8',
  type: MediaType.video,
  
  // Event listeners
  eventListeners: {
    ZerorateHlsPlayerEventType.play: (event) {
      print('Video started playing');
    },
    ZerorateHlsPlayerEventType.pause: (event) {
      print('Video paused');
    },
    ZerorateHlsPlayerEventType.seeked: (event) {
      print('Seeked to position: ${event.data}');
    },
    ZerorateHlsPlayerEventType.error: (event) {
      print('Error occurred: ${event.data}');
    },
    ZerorateHlsPlayerEventType.completed: (event) {
      print('Playback completed');
    },
    // Only for video with seek preview enabled
    ZerorateHlsPlayerEventType.thumbnailGenerated: (event) {
      print('Thumbnail generated: ${event.data}');
    },
  },
  
  // Custom error UI
  errorBuilder: (error) => Center(
    child: Text('Error: ${error.toString()}'),
  ),
)

UI Customization

Custom Video Controls For complete control over the video player UI:

ZerorateHlsPlayerOptions(
  // Basic setup
  appId: 'your-app-id',
  region: 'region-code',
  src: 'https://example.com/video.m3u8',
  type: MediaType.video,
  
  // Disable default controls
  videoControlsConfig: VideoControlsConfig(
    useDefaultControls: false,
  ),
)

// Then build your own controls using player methods:
IconButton(
  icon: Icon(Icons.play_arrow),
  onPressed: () => yourPlayerReference.play(),
),
IconButton(
  icon: Icon(Icons.pause),
  onPressed: () => yourPlayerReference.pause(),
),

Custom Audio Controls For custom audio player UI:

ZerorateHlsPlayerOptions(
  // Basic setup
  appId: 'your-app-id',
  region: 'region-code',
  src: 'https://example.com/audio.m3u8',
  type: MediaType.audio,
  
  // Option 1: Custom component builders
  audioControlsConfiguration: AudioControlsConfiguration(
    playPauseBuilder: (player, onTap) {
      return CustomPlayButton(
        isPlaying: player.playing,
        onTap: onTap,
      );
    },
    progressBarBuilder: (player, current, total) {
      return CustomProgressBar(
        current: current,
        total: total,
        onSeek: (position) => player.seek(position),
      );
    },
  ),
  
  // Option 2: Disable default controls completely
  audioControlsConfiguration: AudioControlsConfiguration(
    useDefaultControls: false,
  ),
)

You can provide custom widgets for different playback states:

ZerorateHlsPlayerOptions(
  // ... other configurations
  audioControlsConfiguration: AudioControlsConfiguration(
    // Custom widget when audio is in default/idle state
    audioDefaultStateWidget: MyCustomIdleWidget(),
    
    // Custom widget when audio is playing
    audioPlayingStateWidget: MyCustomPlayingWidget(),
    
    // Set to false to use completely custom controls
    useDefaultControls: false,
  ),
)

Usage Scenarios:

  1. Default Controls (useDefaultControls: true)
  • Built-in UI with standard controls
  • Minimal configuration required
  • Quick setup for standard use cases
  1. Custom Controls (useDefaultControls: false)
  • Full control over player UI
  • Implement your own play/pause, progress tracking
  • Recommended for branded or complex UIs

Picture-in-Picture (PiP) Support

Android Configuration

To enable Picture-in-Picture mode for your Android app, you need to make two key modifications:

  1. Update AndroidManifest.xml:
<activity
    android:name=".MainActivity"
    android:supportsPictureInPicture="true"
    ... other configurations>
</activity>
  1. Minimum SDK Requirements:
  • Requires Android 8.0 (API level 26) or higher
  • Update android/app/build.gradle:
android {
    defaultConfig {
        minSdkVersion 26 // Minimum SDK for PiP support
    }
}

API Reference

ZerorateHlsPlayer Methods

MethodDescription
play()Start playback
pause()Pause playback
seekTo(Duration position)Seek to a position
setVolume(double volume)Set volume (0.0 to 1.0)
setPlaybackSpeed(double speed)Set audio playback speed
toggleFullscreen()Toggle fullscreen mode (video only)
resetToBeginning()Reset player duration to the start position
seekForward10Seconds()Skip forward 10 seconds
seekBackward10Seconds()Skip backward 10 seconds
toggleMute()Mute/unmute the player
enterPictureInPictureActivate Picture-in-Picture mode
exitPictureInPictureExit Picture-in-Picture mode

ZerorateHlsPlayer Properties

PropertyDescription
currentPositionCurrent playback position
durationTotal duration of the media
isPlayingWhether playback is currently playing
isBufferingWhether playback is currently buffering
isFullscreenWhether playback is currently in fullscreen
currentVolumeCurrent volume level
isCompletedHas media playback finished
currentSpeedCurrent playback speed

Important Notes

  • The seek preview feature only works when using the built-in video controlson supported platforms (Android, iOS,)

Example

A complete example with event handling and custom controls:

class PlayerScreen extends StatefulWidget {
  @override
  State<PlayerScreen> createState() => _PlayerScreenState();
}

class _PlayerScreenState extends State<PlayerScreen> {
  ZerorateHlsPlayer? _player;

  @override
  void initState() {
    super.initState();
    _initializePlayer();
  }

  void _initializePlayer() {
    setState(() {
      _player = ZerorateHlsPlayer(
        options: ZerorateHlsPlayerOptions(
          appId: 'my-app-id',
          region: 'us-01',
          src: 'https://example.com/video.m3u8',
          type: MediaType.video,
          autoplay: false,
          aspectRatio: 16 / 9,
          videoControlsConfig: VideoControlsConfig(
            enableSeekPreview: true,
          ),
          eventListeners: {
            ZerorateHlsPlayerEventType.play: (event) => print('Playing'),
            ZerorateHlsPlayerEventType.error: (event) => print('Error: ${event.data}'),
          },
        ),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Video Player')),
      body: Column(
        children: [
          if (_player != null)
            AspectRatio(
              aspectRatio: 16 / 9,
              child: _player!,
            ),
          
          // Custom controls below the player
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              IconButton(
                icon: Icon(Icons.replay_10),
                onPressed: () {
                  final position = _player?.currentPosition;
                  if (position != null) {
                    _player?.seekTo(
                      Duration(seconds: position.inSeconds - 10),
                    );
                  }
                },
              ),
              IconButton(
                icon: Icon(Icons.forward_10),
                onPressed: () {
                  final position = _player?.currentPosition;
                  if (position != null) {
                    _player?.seekTo(
                      Duration(seconds: position.inSeconds + 10),
                    );
                  }
                },
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Troubleshooting

HTTP streams not loading on Android

Make sure you've added android:usesCleartextTraffic="true" to your AndroidManifest.xml file.

Missing thumbnails in seek preview

The thumbnail generation runs in the background. On first run, thumbnails may take a moment to appear.

Contact Us

Contributions are not accepted at this time. For any feature requests, bug fixes, or inquiries regarding licensing and reuse, please contact us at hi@freepass.africa.