I’ve taken a file object which I received from the Flutter camera library. Then passed that file into the Flutter video_player controller. Something like this.
_controller = VideoPlayerController.file(widget.video!);
When I do that the video shows completely blank. If I include timestamps it does seem to know roughly the length of the video but nothing plays – no audio nothing. I’ve been able to get it to work just fine in the exact same file if I replace the call to .file with a call to .networkUrl and pass in a known working video. I would think that it should take a file object without too much issue.
I’ve also tried using a different library, Chewie. Although I wasn’t expecting much considering is uses video_player under the hood. It also didn’t work just as I expected but I wasn’t sure what else to try.
There are no errors logged to the terminal.
Edit to add more code context:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:revvy/utils/getEnv.dart';
import 'package:revvy/utils/styles.dart';
import 'package:revvy/utils/svgs.dart';
import 'package:revvy/widgets/BouncingButton.dart';
import 'package:video_player/video_player.dart';
import 'package:visibility_detector/visibility_detector.dart';
final String S3_BASE_URL = getEnv('S3_BASE_URL');
class VideoPlayerWidget extends StatefulWidget {
final File? video;
final String videoKey;
final bool displayProgress;
final bool tapToPlay;
const VideoPlayerWidget({Key? key, this.video, this.videoKey = '', this.displayProgress = false, this.tapToPlay = false}) : super(key: key);
@override
VideoPlayerWidgetState createState() => VideoPlayerWidgetState();
}
class VideoPlayerWidgetState extends State<VideoPlayerWidget> {
late VideoPlayerController _controller;
late Future<void> _initializeVideoPlayerFuture;
double volume = 0;
double prevVisibleFraction = 0.0;
@override
void initState() {
if (widget.video == null) {
String url = '$S3_BASE_URL/${widget.videoKey}';
Uri uri = Uri.parse(url);
_controller = VideoPlayerController.networkUrl(uri);
} else {
_controller = VideoPlayerController.file(widget.video!);
}
_initializeVideoPlayerFuture = _controller.initialize();
_controller.setVolume(1);
_controller.setLooping(true);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
void setState(VoidCallback fn) {
if (mounted) {
super.setState(fn);
}
}
@override
Widget build(BuildContext context) {
final query = MediaQuery.of(context);
final double width = query.size.width;
final double height = query.size.height;
return Container(
color: Colors.black,
width: width,
height: height,
child: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Stack(
children: [
ClipRect(
clipBehavior: Clip.hardEdge,
child: SizedBox.expand(
child: FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: GestureDetector(
onTap: () {
if (widget.tapToPlay) {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
}
},
child: VideoPlayer(_controller),
),
)
)
),
),
Positioned(
bottom: 132,
left: CONTENT_SPACING_3,
right: CONTENT_SPACING_3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (!widget.tapToPlay) (
BouncingButton(
onPress: () {
setState(() {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
});
},
child: SizedBox(
width: ICON_SIZE_LG,
height: ICON_SIZE_LG,
child: SvgPicture.string(_controller.value.isPlaying ? faPauseSolid : faPlaySolid, color: Colors.white)
),
)
) else (
const SizedBox()
),
if (widget.displayProgress) (
SizedBox(
width: width - 200,
child: VideoProgressIndicator(
_controller,
allowScrubbing: true,
),
)
),
if (widget.displayProgress) (
ValueListenableBuilder(
valueListenable: _controller,
builder: (context, VideoPlayerValue value, child) {
final currentTime = value.position.toString();
final duration = _controller.value.duration.toString();
String formatVideoTime(time) {
final values = time.split(':');
return '0:' + values[2].split('.')[0];
}
return Text('${formatVideoTime(currentTime)}/${formatVideoTime(duration)}', style: const TextStyle(fontSize: FONT_SIZE_MD, color: Colors.white));
},
)
),
]
)
),
]
);
} else {
// If the VideoPlayerController is still initializing, show a
// loading spinner.
return Center(
child: LoadingAnimationWidget.prograssiveDots(
color: COLOR_PRIMARY,
size: 64,
),
);
}
},
)
);
}
}
2
Answers
You need to initialize the video player.
_controller = VideoPlayerController.file(widget.video!))..initialize()
Please look at the example code in the documentation.