initCameras method
Initialize cameras instances. 初始化相机实例
Implementation
Future<void> initCameras([CameraDescription? cameraDescription]) async {
// Save the current controller to a local variable.
final CameraController? c = innerController;
// Dispose at last to avoid disposed usage with assertions.
if (c != null) {
innerController = null;
await c.dispose();
}
// Then request a new frame to unbind the controller from elements.
safeSetState(() {
maxAvailableZoom = 1;
minAvailableZoom = 1;
currentZoom = 1;
baseZoom = 1;
// Meanwhile, cancel the existed exposure point and mode display.
exposureModeDisplayTimer?.cancel();
exposurePointDisplayTimer?.cancel();
lastExposurePoint.value = null;
if (currentExposureOffset.value != 0) {
currentExposureOffset.value = 0;
}
});
// **IMPORTANT**: Push methods into a post frame callback, which ensures the
// controller has already unbind from widgets.
ambiguate(WidgetsBinding.instance)?.addPostFrameCallback((_) async {
// When the [cameraDescription] is null, which means this is the first
// time initializing cameras, so available cameras should be fetched.
if (cameraDescription == null) {
cameras = await availableCameras();
}
// After cameras fetched, judge again with the list is empty or not to
// ensure there is at least an available camera for use.
if (cameraDescription == null && cameras.isEmpty) {
handleErrorWithHandler(
CameraException(
'No CameraDescription found.',
'No cameras are available in the controller.',
),
pickerConfig.onError,
);
}
initFlashModesForCameras();
final int preferredIndex = cameras.indexWhere(
(CameraDescription e) =>
e.lensDirection == pickerConfig.preferredLensDirection,
);
final int index;
if (preferredIndex != -1 && c == null) {
index = preferredIndex;
currentCameraIndex = preferredIndex;
} else {
index = currentCameraIndex;
}
// Initialize the controller with the given resolution preset.
final CameraController newController = CameraController(
cameraDescription ?? cameras[index],
pickerConfig.resolutionPreset,
enableAudio: enableAudio,
imageFormatGroup: pickerConfig.imageFormatGroup,
);
try {
final Stopwatch stopwatch = Stopwatch()..start();
await newController.initialize();
stopwatch.stop();
realDebugPrint("${stopwatch.elapsed} for controller's initialization.");
// Call recording preparation first.
if (shouldPrepareForVideoRecording) {
stopwatch
..reset()
..start();
await newController.prepareForVideoRecording();
stopwatch.stop();
realDebugPrint("${stopwatch.elapsed} for recording's preparation.");
}
// Then call other asynchronous methods.
stopwatch
..reset()
..start();
await Future.wait(
<Future<void>>[
if (pickerConfig.lockCaptureOrientation != null)
newController
.lockCaptureOrientation(pickerConfig.lockCaptureOrientation),
newController
.getExposureOffsetStepSize()
.then((double value) => exposureStep = value),
newController
.getMaxExposureOffset()
.then((double value) => maxAvailableExposureOffset = value),
newController
.getMinExposureOffset()
.then((double value) => minAvailableExposureOffset = value),
newController
.getMaxZoomLevel()
.then((double value) => maxAvailableZoom = value),
newController
.getMinZoomLevel()
.then((double value) => minAvailableZoom = value),
if (pickerConfig.preferredFlashMode != FlashMode.auto)
newController.setFlashMode(pickerConfig.preferredFlashMode),
],
eagerError: true,
);
stopwatch.stop();
realDebugPrint("${stopwatch.elapsed} for config's update.");
innerController = newController;
} catch (e, s) {
handleErrorWithHandler(e, pickerConfig.onError, s: s);
} finally {
safeSetState(() {});
}
});
}