mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-22 06:28:04 +02:00
feat: implement Turbo-Start stream acceleration
- Add direct MPEG-TS support and optimized HLS tuning - Implement low-latency sync and instant bitrate selection - Achieve TiviMate-like zapping speed by reducing initial buffers
This commit is contained in:
1 parent
736ab0f51c
commit
0ca6f96710
5 files changed
+67
-18
No files matched your search
@@ -132,20 +132,29 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store URL for Lite Player
|
// Store URL for Lite Player
|
||||||
|
final isMobile = MediaQuery.of(context).size.width < 600;
|
||||||
|
final isLiveTV = widget.streamType == StreamType.live;
|
||||||
|
|
||||||
|
// TURBO-START: Use direct MPEG-TS for Live TV on Desktop/Android for instant zapping
|
||||||
|
if (isLiveTV && !isMobile) {
|
||||||
|
streamUrl = service.getLiveStreamUrlTs(currentStreamId);
|
||||||
|
}
|
||||||
|
|
||||||
_currentStreamUrl = streamUrl;
|
_currentStreamUrl = streamUrl;
|
||||||
|
|
||||||
final encodedUrl = Uri.encodeComponent(streamUrl);
|
final encodedUrl = Uri.encodeComponent(streamUrl);
|
||||||
// Force player choice based on stream type:
|
// Force player choice based on stream type:
|
||||||
// - Live TV: Player Lite (simple TS playback with mpegts.js)
|
// - Live TV: Player Lite (simple TS playback with mpegts.js)
|
||||||
// - VOD/Series: Player Standard (fuller controls, HLS support)
|
// - VOD/Series: Player Standard (fuller controls, HLS support)
|
||||||
final isMobile = MediaQuery.of(context).size.width < 600;
|
|
||||||
final isLiveTV = widget.streamType == StreamType.live;
|
|
||||||
// Cache buster to force reload of updated player.html
|
// Cache buster to force reload of updated player.html
|
||||||
final cacheBuster = DateTime.now().millisecondsSinceEpoch;
|
final cacheBuster = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
|
||||||
final streamTypeParam = widget.streamType == StreamType.live ? 'live' : 'vod';
|
final streamTypeParam = widget.streamType == StreamType.live ? 'live' : 'vod';
|
||||||
final playerFile = isMobile ? 'player_mobile.html' : (isLiveTV ? 'player_lite.html' : 'player.html');
|
final playerFile = isMobile ? 'player_mobile.html' : (isLiveTV ? 'player_lite.html' : 'player.html');
|
||||||
var playerSrc = '$playerFile?url=$encodedUrl&type=$streamTypeParam&v=$cacheBuster';
|
|
||||||
|
// Inject Turbo-Start flag
|
||||||
|
var playerSrc = '$playerFile?url=$encodedUrl&type=$streamTypeParam&turbo=true&v=$cacheBuster';
|
||||||
|
|
||||||
if (startTimeOverride != null) {
|
if (startTimeOverride != null) {
|
||||||
playerSrc += '&t=$startTimeOverride';
|
playerSrc += '&t=$startTimeOverride';
|
||||||
|
|||||||
@@ -89,13 +89,24 @@ class XtreamService {
|
|||||||
_currentPlaylist = playlist;
|
_currentPlaylist = playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate stream URL for live TV
|
/// Generate stream URL for live TV (HLS)
|
||||||
String getLiveStreamUrl(String streamId) {
|
String getLiveStreamUrl(String streamId) {
|
||||||
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
||||||
// Use HLS (.m3u8) with a subpath to ensure relative segments resolve correctly
|
|
||||||
return '$_backendBaseUrl/api/live/$streamId/playlist.m3u8';
|
return '$_backendBaseUrl/api/live/$streamId/playlist.m3u8';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate stream URL for live TV (Direct MPEG-TS)
|
||||||
|
/// Faster zapping on compatible players (mpegts.js)
|
||||||
|
String getLiveStreamUrlTs(String streamId) {
|
||||||
|
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
||||||
|
// Direct link to the .ts stream through our proxy
|
||||||
|
final dns = _currentPlaylist!.dns;
|
||||||
|
final user = _currentPlaylist!.username;
|
||||||
|
final pass = _currentPlaylist!.password;
|
||||||
|
final url = '$dns/live/$user/$pass/$streamId.ts';
|
||||||
|
return '$_backendBaseUrl/api/xtream/${Uri.encodeComponent(url)}';
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate stream URL for VOD (movies)
|
/// Generate stream URL for VOD (movies)
|
||||||
String getVodStreamUrl(String streamId, String containerExtension) {
|
String getVodStreamUrl(String streamId, String containerExtension) {
|
||||||
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
||||||
|
|||||||
+13
-1
@@ -250,7 +250,19 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hls = new Hls({ maxBufferLength: 45, enableWorker: true });
|
const isTurbo = urlParams.get('turbo') === 'true';
|
||||||
|
|
||||||
|
const hls = new Hls({
|
||||||
|
maxBufferLength: isTurbo ? 30 : 45,
|
||||||
|
enableWorker: true,
|
||||||
|
liveSyncDurationCount: isTurbo ? 2 : 4,
|
||||||
|
// Turbo-Start specific
|
||||||
|
startLevel: isTurbo ? 0 : -1,
|
||||||
|
initialLiveManifestSize: 1,
|
||||||
|
abrEwmaDefaultEstimate: 500000,
|
||||||
|
manifestLoadingRetryDelay: 500,
|
||||||
|
levelLoadingRetryDelay: 500
|
||||||
|
});
|
||||||
window.hlsInstance = hls;
|
window.hlsInstance = hls;
|
||||||
hls.loadSource(url);
|
hls.loadSource(url);
|
||||||
hls.attachMedia(video);
|
hls.attachMedia(video);
|
||||||
|
|||||||
+16
-7
@@ -242,13 +242,21 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isTurbo = urlParams.get('turbo') === 'true';
|
||||||
|
|
||||||
const hls = new Hls({
|
const hls = new Hls({
|
||||||
maxBufferLength: 60, // Increased for better stability
|
maxBufferLength: isTurbo ? 30 : 60,
|
||||||
maxMaxBufferLength: 120,
|
maxMaxBufferLength: isTurbo ? 60 : 120,
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
liveSyncDurationCount: 5, // More stable sync
|
liveSyncDurationCount: isTurbo ? 2 : 5, // Aggressive sync for Turbo
|
||||||
liveMaxLatencyDurationCount: 15,
|
liveMaxLatencyDurationCount: isTurbo ? 10 : 15,
|
||||||
lowLatencyMode: true
|
lowLatencyMode: true,
|
||||||
|
// Turbo-Start specific
|
||||||
|
startLevel: isTurbo ? 0 : -1, // Lowest bitrate first
|
||||||
|
initialLiveManifestSize: 1,
|
||||||
|
abrEwmaDefaultEstimate: 500000, // Start with conservative estimate
|
||||||
|
manifestLoadingRetryDelay: 500,
|
||||||
|
levelLoadingRetryDelay: 500
|
||||||
});
|
});
|
||||||
|
|
||||||
window.hlsInstance = hls;
|
window.hlsInstance = hls;
|
||||||
@@ -277,14 +285,15 @@
|
|||||||
|
|
||||||
if (!mpegts.isSupported()) return false;
|
if (!mpegts.isSupported()) return false;
|
||||||
|
|
||||||
|
const isTurbo = urlParams.get('turbo') === 'true';
|
||||||
const player = mpegts.createPlayer({
|
const player = mpegts.createPlayer({
|
||||||
type: 'mpegts',
|
type: 'mpegts',
|
||||||
isLive: isLive,
|
isLive: isLive,
|
||||||
url: url
|
url: url
|
||||||
}, {
|
}, {
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
stashInitialSize: 512 * 1024, // Smaller stash for faster start and better audio sync
|
stashInitialSize: isTurbo ? 128 * 1024 : 512 * 1024, // Tiny stash for Turbo zapping
|
||||||
enableStashBuffer: true,
|
enableStashBuffer: !isTurbo, // Direct pass-through for Live TV Turbo
|
||||||
lazyLoad: false
|
lazyLoad: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+13
-5
@@ -228,13 +228,21 @@
|
|||||||
// Android / Chrome - HLS.js
|
// Android / Chrome - HLS.js
|
||||||
if (isHLS && Hls.isSupported()) {
|
if (isHLS && Hls.isSupported()) {
|
||||||
log('Using Hls.js optimized for mobile');
|
log('Using Hls.js optimized for mobile');
|
||||||
|
const isTurbo = urlParams.get('turbo') === 'true';
|
||||||
|
|
||||||
const hls = new Hls({
|
const hls = new Hls({
|
||||||
maxBufferLength: 60, // More buffer for mobile stability
|
maxBufferLength: isTurbo ? 30 : 60,
|
||||||
maxMaxBufferLength: 120,
|
maxMaxBufferLength: isTurbo ? 60 : 120,
|
||||||
liveSyncDurationCount: 5,
|
liveSyncDurationCount: isTurbo ? 2 : 5,
|
||||||
liveMaxLatencyDurationCount: 15,
|
liveMaxLatencyDurationCount: isTurbo ? 10 : 15,
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
lowLatencyMode: false // Disable low latency for continuity
|
lowLatencyMode: !isTurbo, // Prioritize stability unless Turbo requested
|
||||||
|
// Turbo-Start specific
|
||||||
|
startLevel: isTurbo ? 0 : -1,
|
||||||
|
initialLiveManifestSize: 1,
|
||||||
|
abrEwmaDefaultEstimate: 500000,
|
||||||
|
manifestLoadingRetryDelay: 500,
|
||||||
|
levelLoadingRetryDelay: 500
|
||||||
});
|
});
|
||||||
hls.loadSource(streamUrl);
|
hls.loadSource(streamUrl);
|
||||||
hls.attachMedia(video);
|
hls.attachMedia(video);
|
||||||
|
|||||||
Reference in new issue
Block a user