Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[camera] Implemented ImageStream ImageFormat setting for Dart and Android #3359

Merged
merged 57 commits into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
0a971a6
Implemented ImageStream ImageFormat setting for Dart and Android
danielroek Dec 21, 2020
9773fea
Fixed formatting and toString test
danielroek Dec 21, 2020
db6c88a
Apply suggestions from code review
danielroek Dec 21, 2020
fa71493
Removed imageStreamImageFormat from CameraValue
danielroek Dec 21, 2020
e94b474
Removed imageStreamImageFormat from CameraValue
danielroek Dec 21, 2020
ccd0225
Removed imageStreamImageFormat from CameraValue
danielroek Dec 21, 2020
fa0c685
fixed formatting
danielroek Dec 21, 2020
39bd9d1
fixed formatting
danielroek Dec 21, 2020
288684f
fixed formatting
danielroek Dec 21, 2020
b1ddd57
WIP: iOS implementation
danielroek Dec 21, 2020
332c2ba
Imaplemented suggested changes, added tests.
danielroek Dec 22, 2020
9188fab
iOS switch case videoFormat
anniek-valk Dec 22, 2020
a9ca829
Added imageFormatGroup to initialize
danielroek Dec 22, 2020
ec6aa45
Apply suggestions from code review
danielroek Dec 22, 2020
56f77ec
Added period to sentence
danielroek Dec 22, 2020
ecea347
Moved ImageFormatGroup to platform_interface; Added extension to conv…
danielroek Dec 23, 2020
ac23632
Fixed test
danielroek Dec 23, 2020
4eea926
Separated Android and iOS in name extension
danielroek Dec 23, 2020
9a86d26
Clarified returns on name extension
danielroek Dec 23, 2020
d5bc2a8
Merge branch 'image_stream_image_format_platform_interface' into imag…
danielroek Dec 23, 2020
f4e152f
updated Android implementation to support String output
danielroek Dec 23, 2020
7f06e79
removed getOrDefault
danielroek Dec 23, 2020
c887e9d
Updated camera implementation to use ImageFormatGroupName; Updated to…
danielroek Dec 23, 2020
18336f9
removed unused import
danielroek Dec 23, 2020
cf6345c
Export image_format_group.dart in types.dart
danielroek Dec 23, 2020
81799a7
Changed enum values to lowercase
danielroek Dec 23, 2020
6acd3ed
Merge branch 'image_stream_image_format_platform_interface' into imag…
danielroek Dec 23, 2020
ab15e89
Added ImageFormatGroup test
danielroek Dec 23, 2020
098fd76
Fixed formatting
danielroek Dec 23, 2020
6b65ed1
made enum strings lowercase
danielroek Dec 23, 2020
f8d9e4c
Removed target platform switch.
danielroek Dec 23, 2020
8936a7f
Fixed formatting
danielroek Dec 23, 2020
bece2b7
Merge branch 'image_stream_image_format_platform_interface' into imag…
danielroek Dec 23, 2020
71f77f4
Updated Android implementation
danielroek Dec 23, 2020
2b6751b
Updated iOS implementation
danielroek Dec 23, 2020
7e65ac1
updated log message for unsupported ImageFormatGroup
danielroek Dec 23, 2020
5f1a17c
Updated Android implementation
danielroek Dec 23, 2020
18efce6
fixed period in docs
danielroek Dec 23, 2020
06ec92d
Switch change to if-statement
anniek-valk Dec 23, 2020
be3bb3d
Moved switching videoFormat to method in iOS
Dec 24, 2020
b0a67fc
Implemented feedback
Dec 24, 2020
0e04029
fixed formatting
Dec 24, 2020
fb90463
Merge branch 'master' into image_stream_image_format
danielroek Dec 24, 2020
375396c
fixed mistakingly removed bracket
Dec 24, 2020
5ec0af9
fixed formatting
Dec 24, 2020
b0d603c
Merge remote-tracking branch 'origin/master' into image_stream_image_…
danielroek Jan 4, 2021
793e52d
Merge branch 'image_stream_image_format_platform_interface' into imag…
danielroek Jan 4, 2021
7953820
Updated version
danielroek Jan 4, 2021
8ea2454
Updated version
danielroek Jan 4, 2021
f904cbf
fixed formatting
danielroek Jan 4, 2021
90f816c
Merge remote-tracking branch 'origin/master' into image_stream_image_…
danielroek Jan 5, 2021
c6d2e78
Merge remote-tracking branch 'flutter/master' into image_stream_image…
danielroek Jan 5, 2021
5593116
Update version number
mvanbeusekom Jan 7, 2021
0a3e8d6
Update version number
mvanbeusekom Jan 7, 2021
ef1b551
Merge branch 'master' into image_stream_image_format
danielroek Jan 8, 2021
23e7753
Define TAG correctly
mvanbeusekom Jan 11, 2021
4de722d
Merge branch 'master' into image_stream_image_format
mvanbeusekom Jan 11, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,14 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {
}

@SuppressLint("MissingPermission")
public void open() throws CameraAccessException {
public void open(Integer imageStreamImageFormat) throws CameraAccessException {
danielroek marked this conversation as resolved.
Show resolved Hide resolved
pictureImageReader =
ImageReader.newInstance(
captureSize.getWidth(), captureSize.getHeight(), ImageFormat.JPEG, 2);

ImageReader.newInstance(
captureSize.getWidth(), captureSize.getHeight(), ImageFormat.JPEG, 2);
// Used to steam image byte data to dart side.
imageStreamReader =
ImageReader.newInstance(
previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
ImageReader.newInstance(
previewSize.getWidth(), previewSize.getHeight(), imageStreamImageFormat != null? imageStreamImageFormat : ImageFormat.YUV_420_888, 2);

cameraManager.openCamera(
cameraName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
{
if (camera != null) {
try {
camera.open();
camera.open(call.argument("imageStreamImageFormat"));
danielroek marked this conversation as resolved.
Show resolved Hide resolved
result.success(null);
} catch (Exception e) {
handleException(e, result);
Expand Down
1 change: 1 addition & 0 deletions packages/camera/camera/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ class _CameraExampleHomeState extends State<CameraExampleHome>
cameraDescription,
ResolutionPreset.medium,
enableAudio: enableAudio,
imageStreamImageFormat: ImageFormatGroup.jpeg
danielroek marked this conversation as resolved.
Show resolved Hide resolved
);

// If the controller is updated then update the UI.
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ flutter:
uses-material-design: true

environment:
sdk: ">=2.0.0-dev.28.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"
danielroek marked this conversation as resolved.
Show resolved Hide resolved
flutter: ">=1.9.1+hotfix.4 <2.0.0"
30 changes: 25 additions & 5 deletions packages/camera/camera/lib/src/camera_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class CameraValue {
this.isTakingPicture,
this.isStreamingImages,
bool isRecordingPaused,
this.imageStreamImageFormat,
}) : _isRecordingPaused = isRecordingPaused;

/// Creates a new camera controller state for an uninitialized controller.
Expand Down Expand Up @@ -86,6 +87,11 @@ class CameraValue {
/// When true [errorDescription] describes the error.
bool get hasError => errorDescription != null;

/// The [ImageFormatGroup] describes the output of the raw image format.
///
/// When null the imageFormat will fallback to the platforms default
final ImageFormatGroup imageStreamImageFormat;

/// Creates a modified copy of the object.
///
/// Explicitly specified fields get the specified value, all other fields get
Expand All @@ -98,6 +104,7 @@ class CameraValue {
String errorDescription,
Size previewSize,
bool isRecordingPaused,
ImageFormatGroup imageStreamImageFormat,
}) {
return CameraValue(
isInitialized: isInitialized ?? this.isInitialized,
Expand All @@ -107,6 +114,8 @@ class CameraValue {
isTakingPicture: isTakingPicture ?? this.isTakingPicture,
isStreamingImages: isStreamingImages ?? this.isStreamingImages,
isRecordingPaused: isRecordingPaused ?? _isRecordingPaused,
imageStreamImageFormat:
imageStreamImageFormat ?? this.imageStreamImageFormat,
);
}

Expand All @@ -117,7 +126,8 @@ class CameraValue {
'isInitialized: $isInitialized, '
'errorDescription: $errorDescription, '
'previewSize: $previewSize, '
'isStreamingImages: $isStreamingImages)';
'isStreamingImages: $isStreamingImages, '
'imageStreamImageFormat: $imageStreamImageFormat)';
}
}

Expand All @@ -134,6 +144,7 @@ class CameraController extends ValueNotifier<CameraValue> {
this.description,
this.resolutionPreset, {
this.enableAudio = true,
this.imageStreamImageFormat,
danielroek marked this conversation as resolved.
Show resolved Hide resolved
}) : super(const CameraValue.uninitialized());

/// The properties of the camera device controlled by this controller.
Expand All @@ -150,6 +161,11 @@ class CameraController extends ValueNotifier<CameraValue> {
/// Whether to include audio when recording a video.
final bool enableAudio;

/// The [ImageFormatGroup] describes the output of the raw image format.
///
/// When null the imageFormat will fallback to the platforms default
danielroek marked this conversation as resolved.
Show resolved Hide resolved
final ImageFormatGroup imageStreamImageFormat;
danielroek marked this conversation as resolved.
Show resolved Hide resolved

int _cameraId;
bool _isDisposed = false;
StreamSubscription<dynamic> _imageStreamSubscription;
Expand Down Expand Up @@ -190,12 +206,16 @@ class CameraController extends ValueNotifier<CameraValue> {
);
}).first;

await CameraPlatform.instance.initializeCamera(_cameraId);
await CameraPlatform.instance.initializeCamera(
_cameraId,
imageStreamImageFormat:
imageFormatGroupAsIntegerValue(imageStreamImageFormat),
danielroek marked this conversation as resolved.
Show resolved Hide resolved
);

value = value.copyWith(
isInitialized: true,
previewSize: await previewSize,
);
isInitialized: true,
previewSize: await previewSize,
imageStreamImageFormat: imageStreamImageFormat);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
Expand Down
45 changes: 43 additions & 2 deletions packages/camera/camera/lib/src/camera_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ enum ImageFormatGroup {
/// On iOS, this is `kCVPixelFormatType_32BGRA`. See
/// https://developer.apple.com/documentation/corevideo/1563591-pixel_format_identifiers/kcvpixelformattype_32bgra?language=objc
bgra8888,

/// 32-big RGB image encoded into JPEG bytes.
///
/// On Android, this is `android.graphics.ImageFormat.JPEG`. See
/// https://developer.android.com/reference/android/graphics/ImageFormat#JPEG
jpeg,
}

/// Describes how pixels are represented in an image.
Expand All @@ -86,9 +92,13 @@ class ImageFormat {

ImageFormatGroup _asImageFormatGroup(dynamic rawFormat) {
if (defaultTargetPlatform == TargetPlatform.android) {
switch (rawFormat) {
// android.graphics.ImageFormat.YUV_420_888
if (rawFormat == 35) {
return ImageFormatGroup.yuv420;
case 35:
return ImageFormatGroup.yuv420;
// android.graphics.ImageFormat.JPEG
case 256:
return ImageFormatGroup.jpeg;
}
}

Expand All @@ -106,6 +116,37 @@ ImageFormatGroup _asImageFormatGroup(dynamic rawFormat) {
return ImageFormatGroup.unknown;
}

/// Converts [ImageFormatGroup] to integer definition of the raw format
int imageFormatGroupAsIntegerValue(ImageFormatGroup imageFormatGroup) {
if (defaultTargetPlatform == TargetPlatform.iOS) {
switch (imageFormatGroup) {
// kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
case ImageFormatGroup.yuv420:
return 875704438;
// kCVPixelFormatType_32BGRA
case ImageFormatGroup.bgra8888:
return 1111970369;
case ImageFormatGroup.jpeg:
case ImageFormatGroup.unknown:
return 0;
}
} else if (defaultTargetPlatform == TargetPlatform.android) {
switch (imageFormatGroup) {
// kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
case ImageFormatGroup.yuv420:
return 35;
// kCVPixelFormatType_32BGRA
case ImageFormatGroup.bgra8888:
case ImageFormatGroup.unknown:
return 0;
case ImageFormatGroup.jpeg:
return 256;
}
}
// unknown ImageFormatGroup or unsupported platform
return 0;
}

danielroek marked this conversation as resolved.
Show resolved Hide resolved
/// A single complete image buffer from the platform camera.
///
/// This class allows for direct application access to the pixel data of an
Expand Down
5 changes: 3 additions & 2 deletions packages/camera/camera/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera
dependencies:
flutter:
sdk: flutter
camera_platform_interface: ^1.0.0
camera_platform_interface:
path: ../camera_platform_interface

dev_dependencies:
path_provider: ^0.5.0
Expand All @@ -31,5 +32,5 @@ flutter:
pluginClass: CameraPlugin

environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"
danielroek marked this conversation as resolved.
Show resolved Hide resolved
flutter: ">=1.12.13+hotfix.5"
18 changes: 18 additions & 0 deletions packages/camera/camera/test/camera_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,24 @@ void main() {
)));
});
});

test('imageFormat can be set', () async {
CameraController cameraController = CameraController(
CameraDescription(
name: 'cam',
lensDirection: CameraLensDirection.back,
sensorOrientation: 90),
ResolutionPreset.max,
imageStreamImageFormat: ImageFormatGroup.jpeg,
);

await cameraController.initialize();
expect(cameraController.value.imageStreamImageFormat, ImageFormatGroup.jpeg);
});

// test('imageFormat throws $CameraException when uninitialized', () {
// //TODO
// });
danielroek marked this conversation as resolved.
Show resolved Hide resolved
}

class MockCameraPlatform extends Mock
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera/test/camera_value_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ void main() {
);

expect(cameraValue.toString(),
'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false)');
'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, imageStreamImageFormat: null)');
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:async';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:camera_platform_interface/src/utils/utils.dart';
import 'package:cross_file/cross_file.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
Expand Down Expand Up @@ -75,7 +76,7 @@ class MethodChannelCamera extends CameraPlatform {
}

@override
Future<void> initializeCamera(int cameraId) {
Future<void> initializeCamera(int cameraId, {int imageStreamImageFormat}) {
danielroek marked this conversation as resolved.
Show resolved Hide resolved
_channels.putIfAbsent(cameraId, () {
final channel = MethodChannel('flutter.io/cameraPlugin/camera$cameraId');
channel.setMethodCallHandler(
Expand All @@ -93,6 +94,7 @@ class MethodChannelCamera extends CameraPlatform {
'initialize',
<String, dynamic>{
'cameraId': cameraId,
'imageStreamImageFormat': imageStreamImageFormat,
danielroek marked this conversation as resolved.
Show resolved Hide resolved
},
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ abstract class CameraPlatform extends PlatformInterface {
}

/// Initializes the camera on the device.
Future<void> initializeCamera(int cameraId) {
Future<void> initializeCamera(int cameraId, {int imageStreamImageFormat}) {
danielroek marked this conversation as resolved.
Show resolved Hide resolved
throw UnimplementedError('initializeCamera() is not implemented.');
}

Expand Down