Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 4,483 Bytes
2e813e6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
// lib/widgets/video_player/playback_controller.dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:aitube2/config/config.dart';
import 'package:aitube2/services/clip_queue/video_clip.dart';
/// Manages video playback logic for the video player
class PlaybackController {
/// The current video player controller
VideoPlayerController? currentController;
/// The next video player controller (preloaded)
VideoPlayerController? nextController;
/// The current clip being played
VideoClip? currentClip;
/// Whether the video is playing
bool isPlaying = false;
/// Whether the video is loading
bool isLoading = false;
/// Whether this is the initial load
bool isInitialLoad = true;
/// Current playback position
Duration currentPlaybackPosition = Duration.zero;
/// Whether initial playback has started
bool startedInitialPlayback = false;
/// Timer for checking if buffer is ready
Timer? nextClipCheckTimer;
/// Timer for playback duration
Timer? playbackTimer;
/// Timer for tracking position
Timer? positionTrackingTimer;
/// Whether the controller is disposed
bool isDisposed = false;
/// Callback for when video is completed
Function()? onVideoCompleted;
/// Callback for when the queue needs updating
Function()? onQueueUpdate;
/// Toggle playback between play and pause
void togglePlayback() {
if (isLoading) return;
final controller = currentController;
if (controller == null) return;
isPlaying = !isPlaying;
if (isPlaying) {
// Restore previous position before playing
controller.seekTo(currentPlaybackPosition);
controller.play();
startPlaybackTimer();
} else {
controller.pause();
playbackTimer?.cancel();
positionTrackingTimer?.cancel();
}
}
/// Start the playback timer to manage clip duration
void startPlaybackTimer() {
playbackTimer?.cancel();
nextClipCheckTimer?.cancel();
playbackTimer = Timer(Configuration.instance.actualClipPlaybackDuration, () {
if (isDisposed || !isPlaying) return;
onVideoCompleted?.call();
});
startPositionTracking();
}
/// Start tracking the video position
void startPositionTracking() {
positionTrackingTimer?.cancel();
positionTrackingTimer = Timer.periodic(const Duration(milliseconds: 50), (_) {
if (isDisposed || !isPlaying) return;
final controller = currentController;
if (controller != null && controller.value.isInitialized) {
currentPlaybackPosition = controller.value.position;
}
});
}
/// Start checking for the next clip
void startNextClipCheck() {
nextClipCheckTimer?.cancel();
nextClipCheckTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
if (isDisposed || !isPlaying) {
timer.cancel();
return;
}
onQueueUpdate?.call();
});
}
/// Log the current playback status (debug only)
void logPlaybackStatus() {
if (kDebugMode) {
final controller = currentController;
if (controller != null && controller.value.isInitialized) {
final position = controller.value.position;
final duration = controller.value.duration;
debugPrint('Playback status: ${position.inSeconds}s / ${duration.inSeconds}s'
' (${isPlaying ? "playing" : "paused"})');
debugPrint('Current clip: ${currentClip?.seed}, Next controller ready: ${nextController != null}');
}
}
}
/// Initialize a controller for a video clip
Future<VideoPlayerController> initializeController(String videoUrl) async {
final controller = VideoPlayerController.networkUrl(
Uri.parse(videoUrl),
);
await controller.initialize();
// Configure the controller
controller.setLooping(true);
controller.setVolume(0.0);
controller.setPlaybackSpeed(Configuration.instance.clipPlaybackSpeed);
return controller;
}
/// Prepare the controller to be disposed
Future<void> dispose() async {
isDisposed = true;
playbackTimer?.cancel();
nextClipCheckTimer?.cancel();
positionTrackingTimer?.cancel();
await currentController?.dispose();
await nextController?.dispose();
currentController = null;
nextController = null;
}
} |