zeroratehls 1.0.5
zeroratehls: ^1.0.5 copied to clipboard
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, [...]
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 #
Platform | Video Playback | Audio Playback | Seek Preview | Picture-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"
...>
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 Type | Description | Payload Type | Typical Use Case |
---|---|---|---|
play |
Triggered when media starts playing | null |
Track when playback begins |
pause |
Triggered when media is paused | null |
Monitor pause interactions |
seeked |
Triggered after seeking to a new position | Duration |
Track user navigation |
bufferingStart |
Indicates the start of buffering | null |
Handle loading states |
bufferingEnd |
Indicates buffering has completed | null |
Resume UI interactions |
error |
Occurs when a playback error happens | Exception |
Error handling and logging |
loaded |
Media source successfully loaded | Duration? |
Prepare player after loading |
positionChanged |
Periodic update of playback position | Duration |
Progress tracking |
completed |
Media playback finished | null |
Handle end of media |
thumbnailGenerated |
Thumbnail created during seek preview | Map<String, dynamic> |
Custom thumbnail handling |
controlsVisibilityChanged |
Controls visibility toggled | bool |
UI state management |
qualityChanged |
Stream quality changed | dynamic |
Quality tracking |
volumeChanged |
Volume level modified | double |
Volume control tracking |
audioStateChanged |
Audio-specific state changes | Map<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:
- Default Controls (useDefaultControls: true)
- Built-in UI with standard controls
- Minimal configuration required
- Quick setup for standard use cases
- 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:
- Update
AndroidManifest.xml
:
<activity
android:name=".MainActivity"
android:supportsPictureInPicture="true"
... other configurations>
</activity>
- 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 #
Method | Description |
---|---|
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 |
enterPictureInPicture |
Activate Picture-in-Picture mode |
exitPictureInPicture |
Exit Picture-in-Picture mode |
ZerorateHlsPlayer Properties #
Property | Description |
---|---|
currentPosition |
Current playback position |
duration |
Total duration of the media |
isPlaying |
Whether playback is currently playing |
isBuffering |
Whether playback is currently buffering |
isFullscreen |
Whether playback is currently in fullscreen |
currentVolume |
Current volume level |
isCompleted |
Has media playback finished |
currentSpeed |
Current 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
.