Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/video_player/video_player/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.9.4

* Reduces the position update interval from 500ms to 100ms.

## 2.9.3

* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
Expand Down
3 changes: 1 addition & 2 deletions packages/video_player/video_player/lib/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -585,10 +585,9 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
if (value.isPlaying) {
await _videoPlayerPlatform.play(_textureId);

// Cancel previous timer.
_timer?.cancel();
_timer = Timer.periodic(
const Duration(milliseconds: 500),
const Duration(milliseconds: 100),
(Timer timer) async {
if (_isDisposed) {
return;
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/video_player/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for displaying inline video with other Flutter
widgets on Android, iOS, and web.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.9.3
version: 2.9.4

environment:
sdk: ^3.4.0
Expand Down
74 changes: 74 additions & 0 deletions packages/video_player/video_player/test/video_player_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,45 @@ void main() {
});

group('caption', () {
test('works when position updates', () async {
final VideoPlayerController controller =
VideoPlayerController.networkUrl(
_localhostUri,
closedCaptionFile: _loadClosedCaption(),
);

await controller.initialize();
await controller.play();

// Optionally record caption changes for later verification.
final Map<int, String> recordedCaptions = <int, String>{};

controller.addListener(() {
// Record the caption for the current position (in milliseconds).
final int ms = controller.value.position.inMilliseconds;
recordedCaptions[ms] = controller.value.caption.text;
});

const Duration updateInterval = Duration(milliseconds: 100);
const int totalDurationMs = 350;

// Simulate continuous playback by incrementing in 50ms steps.
for (int ms = 0; ms <= totalDurationMs; ms += 50) {
fakeVideoPlayerPlatform._positions[controller.textureId] =
Duration(milliseconds: ms);
await Future<void>.delayed(updateInterval);
}

// Now, given your closed caption file and the 100ms update interval,
// you expect:
// • at 100ms: caption should be 'one'
// • at 250ms: no caption (i.e. '')
// • at 300ms: caption should be 'two'
expect(recordedCaptions[100], 'one');
expect(recordedCaptions[250], '');
expect(recordedCaptions[300], 'two');
});

test('works when seeking', () async {
final VideoPlayerController controller =
VideoPlayerController.networkUrl(
Expand Down Expand Up @@ -995,6 +1034,41 @@ void main() {
});
});

test('updates position', () async {
final VideoPlayerController controller = VideoPlayerController.networkUrl(
_localhostUri,
videoPlayerOptions: VideoPlayerOptions(),
);

await controller.initialize();

const Duration updatesInterval = Duration(milliseconds: 100);

final List<Duration> positions = <Duration>[];
final Completer<void> intervalUpdateCompleter = Completer<void>();

// Listen for position updates
controller.addListener(() {
positions.add(controller.value.position);
if (positions.length >= 3 && !intervalUpdateCompleter.isCompleted) {
intervalUpdateCompleter.complete();
}
});
await controller.play();
for (int i = 0; i < 3; i++) {
await Future<void>.delayed(updatesInterval);
fakeVideoPlayerPlatform._positions[controller.textureId] =
Duration(milliseconds: i * updatesInterval.inMilliseconds);
}

// Wait for at least 3 position updates
await intervalUpdateCompleter.future;

// Verify that the intervals between updates are approximately correct
expect(positions[1] - positions[0], greaterThanOrEqualTo(updatesInterval));
expect(positions[2] - positions[1], greaterThanOrEqualTo(updatesInterval));
});

group('DurationRange', () {
test('uses given values', () {
const Duration start = Duration(seconds: 2);
Expand Down