camera: add ELinuxCamera dartPluginClass (#81)

Fixed https://github.com/sony/flutter-elinux/issues/211

Signed-off-by: Hidenori Matsubayashi <Hidenori.Matsubayashi@gmail.com>
This commit is contained in:
Hidenori Matsubayashi
2023-08-28 12:37:20 +00:00
committed by GitHub
parent 96106f35e7
commit 57f3aa88bf
9 changed files with 800 additions and 5 deletions
+3
View File
@@ -1,3 +1,6 @@
## 0.3.2
* Add ELinuxCamera (camera dartPluginClass for eLinux) for flutter 3.13.
## 0.3.1
* Update for flutter official camera plugin v0.10.5+3
+36 -2
View File
@@ -86,6 +86,12 @@ class CameraPlugin : public flutter::Plugin {
void HandleTakePictureCall(
const flutter::EncodableValue* message,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
void HandleGetMinExposureOffsetCall(
const flutter::EncodableValue* message,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
void HandleGetMaxExposureOffsetCall(
const flutter::EncodableValue* message,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
void HandleStartImageStreamCall(
const flutter::EncodableValue* message,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
@@ -169,9 +175,9 @@ void CameraPlugin::HandleMethodCall(
} else if (!method_name.compare(kCameraChannelApiSetExposurePoint)) {
result->NotImplemented();
} else if (!method_name.compare(kCameraChannelApiGetMinExposureOffset)) {
result->NotImplemented();
HandleGetMinExposureOffsetCall(method_call.arguments(), std::move(result));
} else if (!method_name.compare(kCameraChannelApiGetMaxExposureOffset)) {
result->NotImplemented();
HandleGetMaxExposureOffsetCall(method_call.arguments(), std::move(result));
} else if (!method_name.compare(kCameraChannelApiGetExposureOffsetStepSize)) {
result->NotImplemented();
} else if (!method_name.compare(kCameraChannelApiSetExposureOffset)) {
@@ -308,6 +314,34 @@ void CameraPlugin::HandleTakePictureCall(
});
}
void CameraPlugin::HandleGetMinExposureOffsetCall(
const flutter::EncodableValue* message,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
if (!camera_) {
result->Error("Not found an active camera",
"Check for creating a camera device");
return;
}
// TODO: Implement exposure control support
double value = 0.0;
result->Success(flutter::EncodableValue(value));
}
void CameraPlugin::HandleGetMaxExposureOffsetCall(
const flutter::EncodableValue* message,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
if (!camera_) {
result->Error("Not found an active camera",
"Check for creating a camera device");
return;
}
// TODO: Implement exposure control support
double value = 0.0;
result->Success(flutter::EncodableValue(value));
}
void CameraPlugin::HandleStartImageStreamCall(
const flutter::EncodableValue* message,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
@@ -8,7 +8,7 @@
#include <flutter/standard_method_codec.h>
namespace {
constexpr char kChannelName[] = "flutter.io/cameraPlugin/camera";
constexpr char kChannelName[] = "plugins.flutter.io/camera/camera";
constexpr char kChannelMethodInitialized[] = "initialized";
}; // namespace
@@ -8,7 +8,7 @@
#include <flutter/standard_method_codec.h>
namespace {
constexpr char kChannelName[] = "flutter.io/cameraPlugin/device";
constexpr char kChannelName[] = "plugins.flutter.io/camera/fromPlatform";
constexpr char kChannelMethodOrientationChanged[] = "orientation_changed";
constexpr char kOrientation[] = "orientation";
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2023 Sony Group Corporation. All rights reserved.
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export 'src/elinux_camera.dart';
+645
View File
@@ -0,0 +1,645 @@
// Copyright 2023 Sony Group Corporation. All rights reserved.
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:math';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:stream_transform/stream_transform.dart';
import 'type_conversion.dart';
import 'utils.dart';
const MethodChannel _channel =
MethodChannel('plugins.flutter.io/camera');
/// The ELinux implementation of [CameraPlatform] that uses method channels.
class ELinuxCamera extends CameraPlatform {
/// Registers this class as the default instance of [CameraPlatform].
static void registerWith() {
CameraPlatform.instance = ELinuxCamera();
}
final Map<int, MethodChannel> _channels = <int, MethodChannel>{};
/// The name of the channel that device events from the platform side are
/// sent on.
@visibleForTesting
static const String deviceEventChannelName =
'plugins.flutter.io/camera/fromPlatform';
/// The controller we need to broadcast the different events coming
/// from handleMethodCall, specific to camera events.
///
/// It is a `broadcast` because multiple controllers will connect to
/// different stream views of this Controller.
/// This is only exposed for test purposes. It shouldn't be used by clients of
/// the plugin as it may break or change at any time.
@visibleForTesting
final StreamController<CameraEvent> cameraEventStreamController =
StreamController<CameraEvent>.broadcast();
/// The controller we need to broadcast the different events coming
/// from handleMethodCall, specific to general device events.
///
/// It is a `broadcast` because multiple controllers will connect to
/// different stream views of this Controller.
late final StreamController<DeviceEvent> _deviceEventStreamController =
_createDeviceEventStreamController();
StreamController<DeviceEvent> _createDeviceEventStreamController() {
// Set up the method handler lazily.
const MethodChannel channel = MethodChannel(deviceEventChannelName);
channel.setMethodCallHandler(_handleDeviceMethodCall);
return StreamController<DeviceEvent>.broadcast();
}
// The stream to receive frames from the native code.
StreamSubscription<dynamic>? _platformImageStreamSubscription;
// The stream for vending frames to platform interface clients.
StreamController<CameraImageData>? _frameStreamController;
Stream<CameraEvent> _cameraEvents(int cameraId) =>
cameraEventStreamController.stream
.where((CameraEvent event) => event.cameraId == cameraId);
@override
Future<List<CameraDescription>> availableCameras() async {
try {
final List<Map<dynamic, dynamic>>? cameras = await _channel
.invokeListMethod<Map<dynamic, dynamic>>('availableCameras');
if (cameras == null) {
return <CameraDescription>[];
}
return cameras.map((Map<dynamic, dynamic> camera) {
return CameraDescription(
name: camera['name']! as String,
lensDirection:
parseCameraLensDirection(camera['lensFacing']! as String),
sensorOrientation: camera['sensorOrientation']! as int,
);
}).toList();
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}
@override
Future<int> createCamera(
CameraDescription cameraDescription,
ResolutionPreset? resolutionPreset, {
bool enableAudio = false,
}) async {
try {
final Map<String, dynamic>? reply = await _channel
.invokeMapMethod<String, dynamic>('create', <String, dynamic>{
'cameraName': cameraDescription.name,
'resolutionPreset': resolutionPreset != null
? _serializeResolutionPreset(resolutionPreset)
: null,
'enableAudio': enableAudio,
});
return reply!['cameraId']! as int;
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}
@override
Future<void> initializeCamera(
int cameraId, {
ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown,
}) {
_channels.putIfAbsent(cameraId, () {
final MethodChannel channel =
MethodChannel('plugins.flutter.io/camera/camera$cameraId');
channel.setMethodCallHandler(
(MethodCall call) => handleCameraMethodCall(call, cameraId));
return channel;
});
final Completer<void> completer = Completer<void>();
onCameraInitialized(cameraId).first.then((CameraInitializedEvent value) {
completer.complete();
});
_channel.invokeMapMethod<String, dynamic>(
'initialize',
<String, dynamic>{
'cameraId': cameraId,
'imageFormatGroup': imageFormatGroup.name(),
},
).catchError(
// TODO(srawlins): This should return a value of the future's type. This
// will fail upcoming analysis checks with
// https://github.com/flutter/flutter/issues/105750.
// ignore: body_might_complete_normally_catch_error
(Object error, StackTrace stackTrace) {
if (error is! PlatformException) {
// ignore: only_throw_errors
throw error;
}
completer.completeError(
CameraException(error.code, error.message),
stackTrace,
);
},
);
return completer.future;
}
@override
Future<void> dispose(int cameraId) async {
if (_channels.containsKey(cameraId)) {
final MethodChannel? cameraChannel = _channels[cameraId];
cameraChannel?.setMethodCallHandler(null);
_channels.remove(cameraId);
}
await _channel.invokeMethod<void>(
'dispose',
<String, dynamic>{'cameraId': cameraId},
);
}
@override
Stream<CameraInitializedEvent> onCameraInitialized(int cameraId) {
return _cameraEvents(cameraId).whereType<CameraInitializedEvent>();
}
@override
Stream<CameraResolutionChangedEvent> onCameraResolutionChanged(int cameraId) {
return _cameraEvents(cameraId).whereType<CameraResolutionChangedEvent>();
}
@override
Stream<CameraClosingEvent> onCameraClosing(int cameraId) {
return _cameraEvents(cameraId).whereType<CameraClosingEvent>();
}
@override
Stream<CameraErrorEvent> onCameraError(int cameraId) {
return _cameraEvents(cameraId).whereType<CameraErrorEvent>();
}
@override
Stream<VideoRecordedEvent> onVideoRecordedEvent(int cameraId) {
return _cameraEvents(cameraId).whereType<VideoRecordedEvent>();
}
@override
Stream<DeviceOrientationChangedEvent> onDeviceOrientationChanged() {
return _deviceEventStreamController.stream
.whereType<DeviceOrientationChangedEvent>();
}
@override
Future<void> lockCaptureOrientation(
int cameraId,
DeviceOrientation orientation,
) async {
await _channel.invokeMethod<String>(
'lockCaptureOrientation',
<String, dynamic>{
'cameraId': cameraId,
'orientation': serializeDeviceOrientation(orientation)
},
);
}
@override
Future<void> unlockCaptureOrientation(int cameraId) async {
await _channel.invokeMethod<String>(
'unlockCaptureOrientation',
<String, dynamic>{'cameraId': cameraId},
);
}
@override
Future<XFile> takePicture(int cameraId) async {
final String? path = await _channel.invokeMethod<String>(
'takePicture',
<String, dynamic>{'cameraId': cameraId},
);
if (path == null) {
throw CameraException(
'INVALID_PATH',
'The platform "$defaultTargetPlatform" did not return a path while reporting success. The platform should always return a valid path or report an error.',
);
}
return XFile(path);
}
@override
Future<void> prepareForVideoRecording() =>
_channel.invokeMethod<void>('prepareForVideoRecording');
@override
Future<void> startVideoRecording(int cameraId,
{Duration? maxVideoDuration}) async {
return startVideoCapturing(
VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration));
}
@override
Future<void> startVideoCapturing(VideoCaptureOptions options) async {
await _channel.invokeMethod<void>(
'startVideoRecording',
<String, dynamic>{
'cameraId': options.cameraId,
'maxVideoDuration': options.maxDuration?.inMilliseconds,
'enableStream': options.streamCallback != null,
},
);
if (options.streamCallback != null) {
_installStreamController().stream.listen(options.streamCallback);
_startStreamListener();
}
}
@override
Future<XFile> stopVideoRecording(int cameraId) async {
final String? path = await _channel.invokeMethod<String>(
'stopVideoRecording',
<String, dynamic>{'cameraId': cameraId},
);
if (path == null) {
throw CameraException(
'INVALID_PATH',
'The platform "$defaultTargetPlatform" did not return a path while reporting success. The platform should always return a valid path or report an error.',
);
}
return XFile(path);
}
@override
Future<void> pauseVideoRecording(int cameraId) => _channel.invokeMethod<void>(
'pauseVideoRecording',
<String, dynamic>{'cameraId': cameraId},
);
@override
Future<void> resumeVideoRecording(int cameraId) =>
_channel.invokeMethod<void>(
'resumeVideoRecording',
<String, dynamic>{'cameraId': cameraId},
);
@override
Stream<CameraImageData> onStreamedFrameAvailable(int cameraId,
{CameraImageStreamOptions? options}) {
_installStreamController(onListen: _onFrameStreamListen);
return _frameStreamController!.stream;
}
StreamController<CameraImageData> _installStreamController(
{Function()? onListen}) {
_frameStreamController = StreamController<CameraImageData>(
onListen: onListen ?? () {},
onPause: _onFrameStreamPauseResume,
onResume: _onFrameStreamPauseResume,
onCancel: _onFrameStreamCancel,
);
return _frameStreamController!;
}
void _onFrameStreamListen() {
_startPlatformStream();
}
Future<void> _startPlatformStream() async {
await _channel.invokeMethod<void>('startImageStream');
_startStreamListener();
}
void _startStreamListener() {
const EventChannel cameraEventChannel =
EventChannel('plugins.flutter.io/camera/imageStream');
_platformImageStreamSubscription =
cameraEventChannel.receiveBroadcastStream().listen((dynamic imageData) {
_frameStreamController!
.add(cameraImageFromPlatformData(imageData as Map<dynamic, dynamic>));
});
}
FutureOr<void> _onFrameStreamCancel() async {
await _channel.invokeMethod<void>('stopImageStream');
await _platformImageStreamSubscription?.cancel();
_platformImageStreamSubscription = null;
_frameStreamController = null;
}
void _onFrameStreamPauseResume() {
throw CameraException('InvalidCall',
'Pause and resume are not supported for onStreamedFrameAvailable');
}
@override
Future<void> setFlashMode(int cameraId, FlashMode mode) =>
_channel.invokeMethod<void>(
'setFlashMode',
<String, dynamic>{
'cameraId': cameraId,
'mode': _serializeFlashMode(mode),
},
);
@override
Future<void> setExposureMode(int cameraId, ExposureMode mode) =>
_channel.invokeMethod<void>(
'setExposureMode',
<String, dynamic>{
'cameraId': cameraId,
'mode': serializeExposureMode(mode),
},
);
@override
Future<void> setExposurePoint(int cameraId, Point<double>? point) {
assert(point == null || point.x >= 0 && point.x <= 1);
assert(point == null || point.y >= 0 && point.y <= 1);
return _channel.invokeMethod<void>(
'setExposurePoint',
<String, dynamic>{
'cameraId': cameraId,
'reset': point == null,
'x': point?.x,
'y': point?.y,
},
);
}
@override
Future<double> getMinExposureOffset(int cameraId) async {
final double? minExposureOffset = await _channel.invokeMethod<double>(
'getMinExposureOffset',
<String, dynamic>{'cameraId': cameraId},
);
return minExposureOffset!;
}
@override
Future<double> getMaxExposureOffset(int cameraId) async {
final double? maxExposureOffset = await _channel.invokeMethod<double>(
'getMaxExposureOffset',
<String, dynamic>{'cameraId': cameraId},
);
return maxExposureOffset!;
}
@override
Future<double> getExposureOffsetStepSize(int cameraId) async {
final double? stepSize = await _channel.invokeMethod<double>(
'getExposureOffsetStepSize',
<String, dynamic>{'cameraId': cameraId},
);
return stepSize!;
}
@override
Future<double> setExposureOffset(int cameraId, double offset) async {
final double? appliedOffset = await _channel.invokeMethod<double>(
'setExposureOffset',
<String, dynamic>{
'cameraId': cameraId,
'offset': offset,
},
);
return appliedOffset!;
}
@override
Future<void> setFocusMode(int cameraId, FocusMode mode) =>
_channel.invokeMethod<void>(
'setFocusMode',
<String, dynamic>{
'cameraId': cameraId,
'mode': serializeFocusMode(mode),
},
);
@override
Future<void> setFocusPoint(int cameraId, Point<double>? point) {
assert(point == null || point.x >= 0 && point.x <= 1);
assert(point == null || point.y >= 0 && point.y <= 1);
return _channel.invokeMethod<void>(
'setFocusPoint',
<String, dynamic>{
'cameraId': cameraId,
'reset': point == null,
'x': point?.x,
'y': point?.y,
},
);
}
@override
Future<double> getMaxZoomLevel(int cameraId) async {
final double? maxZoomLevel = await _channel.invokeMethod<double>(
'getMaxZoomLevel',
<String, dynamic>{'cameraId': cameraId},
);
return maxZoomLevel!;
}
@override
Future<double> getMinZoomLevel(int cameraId) async {
final double? minZoomLevel = await _channel.invokeMethod<double>(
'getMinZoomLevel',
<String, dynamic>{'cameraId': cameraId},
);
return minZoomLevel!;
}
@override
Future<void> setZoomLevel(int cameraId, double zoom) async {
try {
await _channel.invokeMethod<double>(
'setZoomLevel',
<String, dynamic>{
'cameraId': cameraId,
'zoom': zoom,
},
);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}
@override
Future<void> pausePreview(int cameraId) async {
await _channel.invokeMethod<double>(
'pausePreview',
<String, dynamic>{'cameraId': cameraId},
);
}
@override
Future<void> resumePreview(int cameraId) async {
await _channel.invokeMethod<double>(
'resumePreview',
<String, dynamic>{'cameraId': cameraId},
);
}
@override
Future<void> setDescriptionWhileRecording(
CameraDescription description) async {
await _channel.invokeMethod<double>(
'setDescriptionWhileRecording',
<String, dynamic>{
'cameraName': description.name,
},
);
}
@override
Widget buildPreview(int cameraId) {
return Texture(textureId: cameraId);
}
/// Returns the flash mode as a String.
String _serializeFlashMode(FlashMode flashMode) {
switch (flashMode) {
case FlashMode.off:
return 'off';
case FlashMode.auto:
return 'auto';
case FlashMode.always:
return 'always';
case FlashMode.torch:
return 'torch';
}
// The enum comes from a different package, which could get a new value at
// any time, so provide a fallback that ensures this won't break when used
// with a version that contains new values. This is deliberately outside
// the switch rather than a `default` so that the linter will flag the
// switch as needing an update.
// ignore: dead_code
return 'off';
}
/// Returns the resolution preset as a String.
String _serializeResolutionPreset(ResolutionPreset resolutionPreset) {
switch (resolutionPreset) {
case ResolutionPreset.max:
return 'max';
case ResolutionPreset.ultraHigh:
return 'ultraHigh';
case ResolutionPreset.veryHigh:
return 'veryHigh';
case ResolutionPreset.high:
return 'high';
case ResolutionPreset.medium:
return 'medium';
case ResolutionPreset.low:
return 'low';
}
// The enum comes from a different package, which could get a new value at
// any time, so provide a fallback that ensures this won't break when used
// with a version that contains new values. This is deliberately outside
// the switch rather than a `default` so that the linter will flag the
// switch as needing an update.
// ignore: dead_code
return 'max';
}
/// Converts messages received from the native platform into device events.
Future<dynamic> _handleDeviceMethodCall(MethodCall call) async {
switch (call.method) {
case 'orientation_changed':
final Map<String, Object?> arguments = _getArgumentDictionary(call);
_deviceEventStreamController.add(DeviceOrientationChangedEvent(
deserializeDeviceOrientation(arguments['orientation']! as String)));
break;
default:
throw MissingPluginException();
}
}
/// Converts messages received from the native platform into camera events.
///
/// This is only exposed for test purposes. It shouldn't be used by clients of
/// the plugin as it may break or change at any time.
@visibleForTesting
Future<dynamic> handleCameraMethodCall(MethodCall call, int cameraId) async {
switch (call.method) {
case 'initialized':
final Map<String, Object?> arguments = _getArgumentDictionary(call);
cameraEventStreamController.add(CameraInitializedEvent(
cameraId,
arguments['previewWidth']! as double,
arguments['previewHeight']! as double,
deserializeExposureMode(arguments['exposureMode']! as String),
arguments['exposurePointSupported']! as bool,
deserializeFocusMode(arguments['focusMode']! as String),
arguments['focusPointSupported']! as bool,
));
break;
case 'resolution_changed':
final Map<String, Object?> arguments = _getArgumentDictionary(call);
cameraEventStreamController.add(CameraResolutionChangedEvent(
cameraId,
arguments['captureWidth']! as double,
arguments['captureHeight']! as double,
));
break;
case 'camera_closing':
cameraEventStreamController.add(CameraClosingEvent(
cameraId,
));
break;
case 'video_recorded':
final Map<String, Object?> arguments = _getArgumentDictionary(call);
cameraEventStreamController.add(VideoRecordedEvent(
cameraId,
XFile(arguments['path']! as String),
arguments['maxVideoDuration'] != null
? Duration(milliseconds: arguments['maxVideoDuration']! as int)
: null,
));
break;
case 'error':
final Map<String, Object?> arguments = _getArgumentDictionary(call);
cameraEventStreamController.add(CameraErrorEvent(
cameraId,
arguments['description']! as String,
));
break;
default:
throw MissingPluginException();
}
}
/// Returns the arguments of [call] as typed string-keyed Map.
///
/// This does not do any type validation, so is only safe to call if the
/// arguments are known to be a map.
Map<String, Object?> _getArgumentDictionary(MethodCall call) {
return (call.arguments as Map<Object?, Object?>).cast<String, Object?>();
}
}
@@ -0,0 +1,49 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'package:camera_platform_interface/camera_platform_interface.dart';
/// Converts method channel call [data] for `receivedImageStreamData` to a
/// [CameraImageData].
CameraImageData cameraImageFromPlatformData(Map<dynamic, dynamic> data) {
return CameraImageData(
format: _cameraImageFormatFromPlatformData(data['format']),
height: data['height'] as int,
width: data['width'] as int,
lensAperture: data['lensAperture'] as double?,
sensorExposureTime: data['sensorExposureTime'] as int?,
sensorSensitivity: data['sensorSensitivity'] as double?,
planes: List<CameraImagePlane>.unmodifiable(
(data['planes'] as List<dynamic>).map<CameraImagePlane>(
(dynamic planeData) => _cameraImagePlaneFromPlatformData(
planeData as Map<dynamic, dynamic>))));
}
CameraImageFormat _cameraImageFormatFromPlatformData(dynamic data) {
return CameraImageFormat(_imageFormatGroupFromPlatformData(data), raw: data);
}
ImageFormatGroup _imageFormatGroupFromPlatformData(dynamic data) {
switch (data) {
case 35: // android.graphics.ImageFormat.YUV_420_888
return ImageFormatGroup.yuv420;
case 256: // android.graphics.ImageFormat.JPEG
return ImageFormatGroup.jpeg;
case 17: // android.graphics.ImageFormat.NV21
return ImageFormatGroup.nv21;
}
return ImageFormatGroup.unknown;
}
CameraImagePlane _cameraImagePlaneFromPlatformData(Map<dynamic, dynamic> data) {
return CameraImagePlane(
bytes: data['bytes'] as Uint8List,
bytesPerPixel: data['bytesPerPixel'] as int?,
bytesPerRow: data['bytesPerRow'] as int,
height: data['height'] as int?,
width: data['width'] as int?);
}
+56
View File
@@ -0,0 +1,56 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/services.dart';
/// Parses a string into a corresponding CameraLensDirection.
CameraLensDirection parseCameraLensDirection(String string) {
switch (string) {
case 'front':
return CameraLensDirection.front;
case 'back':
return CameraLensDirection.back;
case 'external':
return CameraLensDirection.external;
}
throw ArgumentError('Unknown CameraLensDirection value');
}
/// Returns the device orientation as a String.
String serializeDeviceOrientation(DeviceOrientation orientation) {
switch (orientation) {
case DeviceOrientation.portraitUp:
return 'portraitUp';
case DeviceOrientation.portraitDown:
return 'portraitDown';
case DeviceOrientation.landscapeRight:
return 'landscapeRight';
case DeviceOrientation.landscapeLeft:
return 'landscapeLeft';
}
// The enum comes from a different package, which could get a new value at
// any time, so provide a fallback that ensures this won't break when used
// with a version that contains new values. This is deliberately outside
// the switch rather than a `default` so that the linter will flag the
// switch as needing an update.
// ignore: dead_code
return 'portraitUp';
}
/// Returns the device orientation for a given String.
DeviceOrientation deserializeDeviceOrientation(String str) {
switch (str) {
case 'portraitUp':
return DeviceOrientation.portraitUp;
case 'portraitDown':
return DeviceOrientation.portraitDown;
case 'landscapeRight':
return DeviceOrientation.landscapeRight;
case 'landscapeLeft':
return DeviceOrientation.landscapeLeft;
default:
throw ArgumentError('"$str" is not a valid DeviceOrientation value');
}
}
+3 -1
View File
@@ -2,7 +2,7 @@ name: camera_elinux
description: A Flutter plugin for getting information about and controlling the
camera on eLinux. Supports previewing the camera feed, capturing images, capturing video,
and streaming image buffers to dart.
version: 0.3.1
version: 0.3.2
homepage: https://github.com/sony/flutter-elinux-plugins
repository: https://github.com/sony/flutter-elinux-plugins/tree/main/packages/camera
@@ -11,6 +11,7 @@ environment:
flutter: ">=3.3.0"
dependencies:
camera_platform_interface: ^2.5.0
flutter:
sdk: flutter
@@ -19,3 +20,4 @@ flutter:
platforms:
elinux:
pluginClass: CameraElinuxPlugin
dartPluginClass: ELinuxCamera