-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Closed
Labels
c: performanceRelates to speed or footprint issues (see "perf:" labels)Relates to speed or footprint issues (see "perf:" labels)packageflutter/packages repository. See also p: labels.flutter/packages repository. See also p: labels.
Description
Hi, I'm using camera plugin to capture video and my code basically all the same from plugin example code except I added animationController so that I can stop recording after 15 seconds.
The problem is when I run on real Iphone device, app will crush. It happens in some cases. Right after start recording, in progress, right after finish recording.
I checked Xcode device console and it says video recording processes were called on main thread not background.
Is this plugin error or I should do some modifications?
Here is screenshot for Xcode. Even 100MB, app crash.

Code:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:path_provider/path_provider.dart';
import 'package:video_player/video_player.dart';
import 'countdown.dart';
import 'video_edit.dart';
class CaptureVideo extends StatefulWidget {
@override
CaptureVideoState createState() {
return new CaptureVideoState();
}
}
class CaptureVideoState extends State<CaptureVideo>
with TickerProviderStateMixin {
List<CameraDescription> _cameraDescriptions;
CameraController _cameraController;
VideoPlayerController _videoController;
AnimationController _animationController;
String imagePath;
String videoPath;
VoidCallback videoPlayerListener;
bool _isSelfie = false;
bool _isRecorded = false;
bool _isRecording = false;
bool _isReady = false;
@override
void initState() {
super.initState();
_setupCameras();
}
Future<void> _setupCameras() async {
try {
_cameraDescriptions = await availableCameras();
_cameraController =
new CameraController(_cameraDescriptions[0], ResolutionPreset.high);
await _cameraController.initialize();
} on CameraException catch (_) {
// do something on error.
}
if (!mounted) return;
setState(() {
_isReady = true;
});
_animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 15),
);
}
@override
void deactivate() {
_videoController?.setVolume(0.0);
_videoController?.removeListener(videoPlayerListener);
super.deactivate();
}
@override
void dispose() {
_cameraController?.dispose();
_animationController?.dispose();
_videoController?.dispose();
super.dispose();
}
String timestamp() => new DateTime.now().millisecondsSinceEpoch.toString();
Future _changeDirection(CameraDescription cameraDescription) async {
await _cameraController.dispose();
_cameraController =
new CameraController(cameraDescription, ResolutionPreset.high);
_cameraController.addListener(() {
if (mounted) setState(() {});
if (_cameraController.value.hasError) {
print(_cameraController.value.errorDescription);
}
try {
await _cameraController.initialize();
} on CameraException catch (e) {
print(e);
}
if (mounted) {
setState(() {});
}
});
}
_toSelfie() {
_changeDirection(_cameraDescriptions[1]);
}
_toForward() {
_changeDirection(_cameraDescriptions[0]);
}
void onVideoRecordButtonPressed() {
startVideoRecording().then((String filePath) {
if (mounted) setState(() {});
if (filePath != null) print('Saving video to $filePath');
});
}
void onStopButtonPressed() {
stopVideoRecording().then((_) {
if (mounted) setState(() {});
print('Video recorded to: $videoPath');
});
}
Future<String> startVideoRecording() async {
if (!_cameraController.value.isInitialized) {
print('Error: select a camera first.');
return null;
}
final Directory extDir = await getTemporaryDirectory();
final String dirPath = '${extDir.path}/Movies/flutter_test';
await new Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.mp4';
if (_cameraController.value.isRecordingVideo) {
// A recording is already started, do nothing.
return null;
}
try {
videoPath = filePath;
await _cameraController.startVideoRecording(filePath);
_animationController.forward(from: 0.0).then((_) {
onStopButtonPressed();
setState(() {
_isRecorded = true;
});
});
} on CameraException catch (e) {
print(e);
return null;
}
return filePath;
}
Future<void> stopVideoRecording() async {
if (!_cameraController.value.isRecordingVideo) {
return null;
}
try {
await _cameraController.stopVideoRecording();
_animationController.stop();
setState(() {
_isRecorded = true;
});
} on CameraException catch (e) {
print(e);
return null;
}
await _startVideoPlayer();
}
Future<void> _startVideoPlayer() async {
final VideoPlayerController vcontroller =
new VideoPlayerController.file(new File(videoPath));
videoPlayerListener = () {
if (_videoController != null && _videoController.value.size != null) {
// Refreshing the state to update video player with the correct ratio.
if (mounted) setState(() {});
_videoController.removeListener(videoPlayerListener);
}
};
vcontroller.addListener(videoPlayerListener);
await vcontroller.setLooping(true);
await vcontroller.initialize();
await _videoController?.dispose();
if (mounted) {
setState(() {
imagePath = null;
_videoController = vcontroller;
});
}
await vcontroller.play();
}
_startVideoRecordingCoountDown() {
onVideoRecordButtonPressed();
}
_stopVideoRecordingCountDown() {
onStopButtonPressed();
setState(() {
_animationController.stop();
_isRecorded = true;
});
}
Widget _recordingView() {
return new Stack(
children: <Widget>[
new AspectRatio(
aspectRatio: _cameraController.value.aspectRatio,
child: new CameraPreview(_cameraController),
),
!_isRecording
? new Align(
alignment: Alignment.topLeft,
child: new Container(
child: new FloatingActionButton(
heroTag: 'start',
backgroundColor: Colors.black.withOpacity(0.001),
elevation: 50.0,
child: new Center(child: new Icon(Icons.clear, size: 28.0)),
onPressed: () {
Navigator.of(context).pop();
},
),
),
)
: new Container(),
new Align(
alignment: new Alignment(0.0, 1.0),
child: new Container(
margin: const EdgeInsets.only(bottom: 10.0),
child: new FloatingActionButton(
elevation: 30.0,
backgroundColor: Colors.white,
foregroundColor: Colors.amber,
child: _animationController.isAnimating
? new Countdown(
animation: new StepTween(
begin: 16,
end: 0,
).animate(_animationController),
)
: new Icon(Icons.play_arrow),
onPressed: () {
setState(() {
_isRecording = true;
});
!_animationController.isAnimating
? _startVideoRecordingCoountDown()
: _stopVideoRecordingCountDown();
},
),
),
),
!_isRecording
? new Align(
alignment: Alignment.bottomRight,
child: new Container(
margin: const EdgeInsets.only(right: 15.0, bottom: 10.0),
child: new FloatingActionButton(
elevation: 50.0,
backgroundColor: Colors.black.withOpacity(0.001),
child: new Icon(Icons.cached, size: 35.0),
onPressed: () {
setState(() {
_isSelfie ? _toForward() : _toSelfie();
_isSelfie ? _isSelfie = false : _isSelfie = true;
});
},
),
),
)
: new Container(),
],
fit: StackFit.expand,
);
}
@override
Widget build(BuildContext context) {
if (!_isReady) {
return new Container(color: Colors.black);
}
return new Scaffold(
resizeToAvoidBottomPadding: false,
backgroundColor: Colors.black,
body: !_isRecorded ? _recordingView() : VideoEdit(_videoController),
);
}
}Metadata
Metadata
Assignees
Labels
c: performanceRelates to speed or footprint issues (see "perf:" labels)Relates to speed or footprint issues (see "perf:" labels)packageflutter/packages repository. See also p: labels.flutter/packages repository. See also p: labels.