-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Steps to reproduce
- Create an app that depends on the
video_playerplugin and is enabled for macOS - Put two valid video files in known paths
- Run the following app on macOS, replacing the fake video paths below with your real video paths
- Select either of the two videos (represented by placeholder widgets) in the list view
- Click the main area above the list view to play the video
- Select the other video in the list view
import 'dart:io' as io;
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(const MaterialApp(
title: 'Issue reproduction',
home: IssueHome(
videos: <String>[
'/path/to/first/video.mp4',
'/path/to/second/video.mp4',
],
),
));
}
class IssueHome extends StatefulWidget {
const IssueHome({super.key, required this.videos});
final List<String> videos;
@override
State<IssueHome> createState() => _IssueHomeState();
}
class _IssueHomeState extends State<IssueHome> {
int? selectedIndex;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: selectedIndex == null
? Container()
: VideoArea(item: widget.videos[selectedIndex!]),
),
const Divider(height: 1),
SizedBox(
height: 175,
child: ListView.builder(
itemExtent: 175,
scrollDirection: Axis.horizontal,
itemCount: widget.videos.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () => setState(() => selectedIndex = index),
child: ItemSelector(
index: index,
isSelected: selectedIndex == index,
),
);
},
),
),
],
),
);
}
}
class ItemSelector extends StatelessWidget {
ItemSelector({
required this.index,
required this.isSelected,
}) : super(key: ValueKey<int>(index));
final int index;
final bool isSelected;
@override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.passthrough,
children: <Widget>[
Placeholder(
child: Text(index.toString()),
),
if (isSelected)
DecoratedBox(
decoration: BoxDecoration(border: Border.all(width: 10, color: Colors.white)),
child: const ColoredBox(color: Color(0x440000ff)),
),
],
);
}
}
class VideoArea extends StatefulWidget {
const VideoArea({
super.key,
required this.item,
});
final String item;
@override
State<VideoArea> createState() => _VideoAreaState();
}
class _VideoAreaState extends State<VideoArea> {
late VideoPlayerController _videoController;
void _handlePlayPauseVideo() {
setState(() {
if (_videoController.value.isPlaying) {
_videoController.pause();
} else {
_videoController.play();
}
});
}
void _initializeVideoController() {
_videoController = VideoPlayerController.file(io.File(widget.item));
_videoController.setLooping(true);
_videoController.initialize().then((void _) {
setState(() {});
});
}
@override
void initState() {
super.initState();
_initializeVideoController();
}
@override
void didUpdateWidget(covariant VideoArea oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.item != oldWidget.item) {
_videoController.pause();
_videoController.dispose();
_initializeVideoController();
}
}
@override
void dispose() {
_videoController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!_videoController.value.isInitialized) {
return Container();
} else {
return GestureDetector(
onTap: _handlePlayPauseVideo,
child: Center(
child: AspectRatio(
aspectRatio: _videoController.value.aspectRatio,
child: VideoPlayer(_videoController),
),
),
);
}
}
}Expected behavior
When you select a video from the list view, you expect to see the first frame of the video rendered as a preview.
Actual behavior
When you select a video from the list view, the main video area remains white with no video preview.... until you switch application windows, at which point the video preview shows.
This can be seen in the following screen capture:
Diagnosis
The following line triggers a repaint in Flutter:
_videoController.initialize().then((void _) {
setState(() {});
});... but that repaint isn't causing the surface associated with the native video player plugin to also repaint. Note that this does not seem to be an off-by-one-frame issue between Flutter and the video player plugin, because the issue still exists even if I register some forced frames like so:
_videoController.initialize().then((void _) {
setState(() {});
SchedulerBinding.instance.scheduleForcedFrame();
SchedulerBinding.instance.scheduleFrameCallback((timeStamp) {
setState(() {});
SchedulerBinding.instance.scheduleForcedFrame();
SchedulerBinding.instance.scheduleFrameCallback((timeStamp) {
setState(() {});
});
});
});Info
macOS version: Sonoma 14.1 (23B2073)
video_player plugin version: 2.8.1
video_player_avfoundation plugin version: 2.5.3.
$ flutter doctor -v
[✓] Flutter (Channel main, 3.18.0-18.0.pre.46, on macOS 14.1 23B2073 darwin-arm64, locale en-US)
• Flutter version 3.18.0-18.0.pre.46 on channel main at /Users/tvolkert/project/flutter/flutter
• Upstream repository [email protected]:flutter/flutter.git
• Framework revision 7c9c1705e8 (2 days ago), 2023-12-29 07:40:37 -0500
• Engine revision ea4fb2cb94
• Dart version 3.3.0 (build 3.3.0-272.0.dev)
• DevTools version 2.31.0-dev.0
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
• Android SDK at /Users/tvolkert/Library/Android/sdk
• Platform android-34, build-tools 34.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15A507
• CocoaPods version 1.14.3
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2023.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
[✓] VS Code (version 1.85.0)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.80.0
