Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
11966fa
[camera] Add support for Torch and Auto Exposure
NeKoFu Aug 8, 2019
841d3f3
[camera] set auto exposure trigger when turn on or off the torch
NeKoFu Aug 10, 2019
77fffa0
[camera] increment version in pubspec.yaml
NeKoFu Aug 10, 2019
2680f8d
[camera] update changelog
NeKoFu Aug 10, 2019
8afa990
Merge branch 'master' into camera_torch
NeKoFu Aug 10, 2019
ab961e9
[camera] fix format for default value
NeKoFu Aug 10, 2019
3e284a9
Merge branch 'camera_torch' of https://github.com/NeKoFu/plugins.git
NeKoFu Aug 10, 2019
664f566
[camera] remove commented code and fix format
NeKoFu Aug 10, 2019
cf1986d
[camera] fix format
NeKoFu Aug 10, 2019
9301cab
[camera] fix space characters
NeKoFu Aug 10, 2019
f5566ac
[camera] fix format
NeKoFu Aug 10, 2019
1111074
[camera] delete a blank line for the pleasure of the CI
NeKoFu Aug 10, 2019
21f1ddf
[camera] refactor ios code
NeKoFu Aug 10, 2019
de89946
[camera] fix ios code format
NeKoFu Aug 10, 2019
d2b876f
[camera] fix ios code
NeKoFu Aug 10, 2019
4c18d55
[camera] delete a blank line for the pleasure of the CI
NeKoFu Aug 10, 2019
6d4ef41
[camera] fix iOS mistakes like default value for the setTorchMode and…
NeKoFu Aug 11, 2019
81d35ae
[camera] resolve merge conflit
NeKoFu Aug 11, 2019
dd8f6f3
[camera] fix iOS code
NeKoFu Aug 11, 2019
02d9b40
[camera] Merge branch 'camera_torch'
NeKoFu Aug 11, 2019
1d8d34a
[camera] fix enum to choose Exposure
NeKoFu Aug 11, 2019
5b622cf
[camera] fix float casting in iOS code
NeKoFu Aug 11, 2019
05adac8
[camera] Update example
NeKoFu Aug 11, 2019
4605961
[camera] Fix format
NeKoFu Aug 11, 2019
7b64146
[camera] Replace the term 'Torch' by 'Flash'
NeKoFu Aug 16, 2019
8741890
[camera] Fix format
NeKoFu Aug 16, 2019
9724679
[camera] Fix format
NeKoFu Aug 16, 2019
cb6bc8a
Merge branch 'camera_torch' of https://github.com/NeKoFu/plugins.git
NeKoFu Aug 16, 2019
7d62af2
Merge branch 'master' into camera_torch
NeKoFu Aug 16, 2019
36ddfd6
[camera] Fix format again
NeKoFu Aug 16, 2019
44fb024
Merge branch 'camera_torch' of https://github.com/NeKoFu/plugins.git
NeKoFu Aug 16, 2019
fea203b
[camera] Fix iOS error, the iOS SDK use the term "Torch"
NeKoFu Aug 16, 2019
904c8f7
Merge branch 'master' into camera_torch
NeKoFu Aug 20, 2019
3fe609a
[camera] Control flash and focus mode
NeKoFu Sep 25, 2019
c39a6e2
[camera] Fix partial enlightenment
NeKoFu Sep 25, 2019
b2da249
Merge branch 'master' of https://github.com/flutter/plugins into flut…
NeKoFu Sep 26, 2019
4541a72
Merge branch 'flutter-master'
NeKoFu Sep 26, 2019
b03555d
Merge branch 'master' into camera_torch
NeKoFu Sep 26, 2019
7bb389c
[camera] Fix missing import and increment version
NeKoFu Sep 26, 2019
74b5a48
Merge branch 'master' into camera_torch
NeKoFu Sep 26, 2019
0f80b95
[camera] Fix continuous autofocus mode
NeKoFu Oct 8, 2019
0dccb8e
Merge branch 'camera_torch' of https://github.com/NeKoFu/plugins.git
NeKoFu Oct 8, 2019
fccf0f2
Merge branch 'master' of https://github.com/flutter/plugins into flut…
NeKoFu Nov 3, 2019
51e7ca6
Merge branch 'flutter-master'
NeKoFu Nov 3, 2019
16d5689
Merge branch 'master' into camera_torch
NeKoFu Nov 3, 2019
316869a
Merge fix
NeKoFu Nov 3, 2019
47aedeb
Merge commit 'fc45624236b8789ea2fc776a7b254cd16e9dc926'
NeKoFu Apr 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/camera/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## 0.5.3

* Added new quality presets.
* Now all quality presets can be used to control image capture quality.
* Add support for Torch and Auto Exposure

## 0.5.2+2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public class Camera {
private final Size captureSize;
private final Size previewSize;
private final boolean enableAudio;
private final boolean enableTorch;
private final boolean enableAE;

private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSession;
Expand Down Expand Up @@ -76,14 +78,18 @@ public Camera(
final FlutterView flutterView,
final String cameraName,
final String resolutionPreset,
final boolean enableAudio)
final boolean enableAudio,
final boolean enableTorch,
final boolean enableAE)
throws CameraAccessException {
if (activity == null) {
throw new IllegalStateException("No activity available!");
}

this.cameraName = cameraName;
this.enableAudio = enableAudio;
this.enableTorch = enableTorch;
this.enableAE = enableAE;
this.flutterTexture = flutterView.createSurfaceTexture();
this.cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
orientationEventListener =
Expand Down Expand Up @@ -319,6 +325,16 @@ private void createCaptureSession(
}
}

// Torch
captureRequestBuilder.set(
CaptureRequest.FLASH_MODE,
enableTorch ? CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);

// Auto Exposure
captureRequestBuilder.set(
CaptureRequest.CONTROL_AE_MODE,
enableAE ? CaptureRequest.CONTROL_AE_MODE_ON : CaptureRequest.CONTROL_AE_MODE_OFF);

// Prepare the callback
CameraCaptureSession.StateCallback callback =
new CameraCaptureSession.StateCallback() {
Expand All @@ -332,6 +348,7 @@ public void onConfigured(@NonNull CameraCaptureSession session) {
cameraCaptureSession = session;
captureRequestBuilder.set(
CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
if (onSuccessCallback != null) {
onSuccessCallback.run();
Expand Down Expand Up @@ -443,6 +460,42 @@ private void setImageStreamImageAvailableListener(final EventChannel.EventSink i
null);
}

// Torch
public void setTorchMode(@NonNull final Result result, boolean enable) {
setTorchMode(result, enable, 1.0);
}

public void setTorchMode(@NonNull final Result result, boolean enable, double level) {
try {
captureRequestBuilder.set(
CaptureRequest.FLASH_MODE,
enable ? CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);

captureRequestBuilder.set(
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);

cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
result.success(null);
} catch (Exception e) {
result.error("cameraTorchFailed", e.getMessage(), null);
}
}

public void setAEMode(@NonNull final Result result, boolean enable) {
try {
// Auto Exposure
captureRequestBuilder.set(
CaptureRequest.CONTROL_AE_MODE,
enable ? CaptureRequest.CONTROL_AE_MODE_ON : CaptureRequest.CONTROL_AE_MODE_OFF);

cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
result.success(null);
} catch (Exception e) {
result.error("cameraAEFailed", e.getMessage(), null);
}
}

private void sendEvent(EventType eventType) {
sendEvent(eventType, null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.flutter.plugins.camera;

import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.os.Build;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -44,7 +45,17 @@ private void instantiateCamera(MethodCall call, Result result) throws CameraAcce
String cameraName = call.argument("cameraName");
String resolutionPreset = call.argument("resolutionPreset");
boolean enableAudio = call.argument("enableAudio");
camera = new Camera(registrar.activity(), view, cameraName, resolutionPreset, enableAudio);
boolean enableTorch = call.argument("enableTorch");
boolean enableAE = call.argument("enableAE");
camera =
new Camera(
registrar.activity(),
view,
cameraName,
resolutionPreset,
enableAudio,
enableTorch,
enableAE);

EventChannel cameraEventChannel =
new EventChannel(
Expand Down Expand Up @@ -128,6 +139,31 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
}
break;
}
case "torchOn":
{
camera.setTorchMode(result, true, call.argument("level"));
break;
}
case "torchOff":
{
camera.setTorchMode(result, false);
break;
}
case "hasTorch":
{
result.success(hasTorch());
break;
}
case "aeOn":
{
camera.setAEMode(result, true);
break;
}
case "aeOff":
{
camera.setAEMode(result, false);
break;
}
case "dispose":
{
if (camera != null) {
Expand All @@ -142,6 +178,14 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
}
}

private boolean hasTorch() {
return registrar
.context()
.getApplicationContext()
.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
}

// We move catching CameraAccessException out of onMethodCall because it causes a crash
// on plugin registration for sdks incompatible with Camera2 (< 21). We want this plugin to
// to be able to compile with <21 sdks for apps that want the camera and support earlier version.
Expand Down
41 changes: 40 additions & 1 deletion packages/camera/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
VideoPlayerController videoController;
VoidCallback videoPlayerListener;
bool enableAudio = true;
bool enableTorch = false;

@override
void initState() {
Expand Down Expand Up @@ -96,7 +97,12 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
),
),
_captureControlRowWidget(),
_toggleAudioWidget(),
Row(
children: <Widget>[
_toggleAudioWidget(),
_toggleTorchWidget(),
],
),
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
Expand Down Expand Up @@ -152,6 +158,39 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
);
}

/// Display the Torch Switch
Widget _toggleTorchWidget() {
return Padding(
padding: const EdgeInsets.only(left: 25),
child: Row(
children: <Widget>[
const Text('Enable Torch:'),
Switch(value: enableTorch, onChanged: _toggleTorch),
],
),
);
}

/// Toggle Torch
Future<void> _toggleTorch(bool value) async {
bool hasTorch = false;

if (controller != null) {
hasTorch = await controller.hasTorch;
}

if (hasTorch) {
enableTorch = value;
if (enableTorch) {
controller.torchOn();
} else {
controller.torchOff();
}
}

setState(() {});
}

/// Display the thumbnail of the captured image or video.
Widget _thumbnailWidget() {
return Expanded(
Expand Down
75 changes: 75 additions & 0 deletions packages/camera/ios/Classes/CameraPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ @interface FLTCam : NSObject <FlutterTexture,
@property(readonly, nonatomic) int64_t textureId;
@property(nonatomic, copy) void (^onFrameAvailable)();
@property BOOL enableAudio;
@property BOOL enableTorch;
@property BOOL enableAE;
@property(nonatomic) FlutterEventChannel *eventChannel;
@property(nonatomic) FLTImageStreamHandler *imageStreamHandler;
@property(nonatomic) FlutterEventSink eventSink;
Expand All @@ -183,6 +185,8 @@ @interface FLTCam : NSObject <FlutterTexture,
- (instancetype)initWithCameraName:(NSString *)cameraName
resolutionPreset:(NSString *)resolutionPreset
enableAudio:(BOOL)enableAudio
enableTorch:(BOOL)enableTorch
enableAE:(BOOL)enableAE
dispatchQueue:(dispatch_queue_t)dispatchQueue
error:(NSError **)error;

Expand All @@ -193,6 +197,9 @@ - (void)stopVideoRecordingWithResult:(FlutterResult)result;
- (void)startImageStreamWithMessenger:(NSObject<FlutterBinaryMessenger> *)messenger;
- (void)stopImageStream;
- (void)captureToFile:(NSString *)filename result:(FlutterResult)result;
- (void)setTorchMode:(BOOL)enable level:(float)level;
- (void)setTorchMode:(BOOL)enable;
- (void)setAEMode:(BOOL)enable;
@end

@implementation FLTCam {
Expand All @@ -204,6 +211,8 @@ @implementation FLTCam {
- (instancetype)initWithCameraName:(NSString *)cameraName
resolutionPreset:(NSString *)resolutionPreset
enableAudio:(BOOL)enableAudio
enableTorch:(BOOL)enableTorch
enableAE:(BOOL)enableAE
dispatchQueue:(dispatch_queue_t)dispatchQueue
error:(NSError **)error {
self = [super init];
Expand Down Expand Up @@ -249,6 +258,15 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
[_motionManager startAccelerometerUpdates];

[self setCaptureSessionPreset:_resolutionPreset];

if (enableTorch) {
[self setTorchMode:enableTorch];
}

if (enableAE) {
[self setAEMode:enableAE];
}

return self;
}

Expand Down Expand Up @@ -578,6 +596,44 @@ - (void)stopImageStream {
}
}

- (bool)hasTorch {
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
return ([device hasTorch] && [device hasFlash]);
}

- (void)setTorchMode:(BOOL)enable {
[self setTorchMode:enable level:1.0];
}

- (void)setTorchMode:(BOOL)enable level:(float)level {
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if ([device hasTorch] && [device hasFlash]) {
[device lockForConfiguration:nil];
if (enable) {
NSError *error = nil;
float acceptedLevel =
(level < AVCaptureMaxAvailableTorchLevel ? level : AVCaptureMaxAvailableTorchLevel);
NSLog(@"FLash level: %f", acceptedLevel);
[device setTorchModeOnWithLevel:acceptedLevel error:&error];
} else {
[device setTorchMode:AVCaptureTorchModeOff];
}
[device unlockForConfiguration];
}
}

- (void)setAEMode:(BOOL)enable {
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
[device lockForConfiguration:nil];
if (enable) {
int exposure = AVCaptureExposureModeContinuousAutoExposure;
if (exposure && [device isExposureModeSupported:exposure]) device.exposureMode = exposure;
} else {
device.exposureMode = AVCaptureExposureModeAutoExpose;
}
[device unlockForConfiguration];
}

- (BOOL)setupWriterForPath:(NSString *)path {
NSError *error = nil;
NSURL *outputURL;
Expand Down Expand Up @@ -734,10 +790,14 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re
NSString *cameraName = call.arguments[@"cameraName"];
NSString *resolutionPreset = call.arguments[@"resolutionPreset"];
NSNumber *enableAudio = call.arguments[@"enableAudio"];
NSNumber *enableTorch = call.arguments[@"enableTorch"];
NSNumber *enableAE = call.arguments[@"enableAE"];
NSError *error;
FLTCam *cam = [[FLTCam alloc] initWithCameraName:cameraName
resolutionPreset:resolutionPreset
enableAudio:[enableAudio boolValue]
enableTorch:[enableTorch boolValue]
enableAE:[enableAE boolValue]
dispatchQueue:_dispatchQueue
error:&error];
if (error) {
Expand Down Expand Up @@ -773,6 +833,21 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re
} else if ([@"stopImageStream" isEqualToString:call.method]) {
[_camera stopImageStream];
result(nil);
} else if ([@"hasTorch" isEqualToString:call.method]) {
result([NSNumber numberWithBool:[_camera hasTorch]]);
} else if ([@"torchOn" isEqualToString:call.method]) {
NSNumber *level = call.arguments[@"level"];
[_camera setTorchMode:true level:[level floatValue]];
result(nil);
} else if ([@"torchOff" isEqualToString:call.method]) {
[_camera setTorchMode:false];
result(nil);
} else if ([@"aeOn" isEqualToString:call.method]) {
[_camera setAEMode:true];
result(nil);
} else if ([@"aeOff" isEqualToString:call.method]) {
[_camera setAEMode:false];
result(nil);
} else {
NSDictionary *argsMap = call.arguments;
NSUInteger textureId = ((NSNumber *)argsMap[@"textureId"]).unsignedIntegerValue;
Expand Down
Loading