Skip to content

Commit 4c4bb46

Browse files
authored
[camera_platform_interface] [camera] [camera_android] Add NV21 as an image stream format (#3277)
### Note: this is a re-created PR from flutter/plugins#6985 --- This PR adds NV21 as an image stream format for android devices. This is the format required for things like MLKit. Unfortunately a lot of people tend to implement the yuv->nv21 incorrectly in dart, which results in countless issues of users saying the image stream doesn't work, or that mlkit doesn't work. By allowing the plugin to send NV21 to dart, this will fix all of those yuv conversion issues. Highlights: - Added an abstraction around `ImageReader` called `ImageStreamReader` and moved the image stream logic into this class to clean up the `Camera` class. This allows us to test the image stream handler in isolation. - Added tests for `ImageStreamReader` to make sure it only calls the `removePlaneBufferPadding` function for planes that contain padding. - Added a new utility class called `ImageStreamReaderUtils` which contains the logic for trimming the padding. - Added tests for `ImageStreamReaderUtils` to make sure it only removes padding when a given buffer contains padding to be removed. - There are tests to confirm both that `removePlaneBufferPadding` is only called when padding is present, and to confirm that if `removePlaneBufferPadding` does happen to be called with a buffer containing no padding, it still returns a valid buffer. *List which issues are fixed by this PR. You must list at least one issue.* - flutter/flutter#118350 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
1 parent 3fcf671 commit 4c4bb46

File tree

4 files changed

+35
-3
lines changed

4 files changed

+35
-3
lines changed

packages/camera/camera/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.10.5
2+
3+
* Adds NV21 as an image streaming option for Android.
4+
15
## 0.10.4
26

37
* Allows camera to be switched while video recording.

packages/camera/camera/lib/src/camera_image.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ ImageFormatGroup _asImageFormatGroup(dynamic rawFormat) {
9090
// android.graphics.ImageFormat.JPEG
9191
case 256:
9292
return ImageFormatGroup.jpeg;
93+
// android.graphics.ImageFormat.NV21
94+
case 17:
95+
return ImageFormatGroup.nv21;
9396
}
9497
}
9598

packages/camera/camera/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing
44
Dart.
55
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
66
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
7-
version: 0.10.4
7+
version: 0.10.5
88

99
environment:
1010
sdk: ">=2.18.0 <4.0.0"
@@ -21,9 +21,9 @@ flutter:
2121
default_package: camera_web
2222

2323
dependencies:
24-
camera_android: ^0.10.5
24+
camera_android: ^0.10.7
2525
camera_avfoundation: ^0.9.13
26-
camera_platform_interface: ^2.4.0
26+
camera_platform_interface: ^2.5.0
2727
camera_web: ^0.3.1
2828
flutter:
2929
sdk: flutter

packages/camera/camera/test/camera_image_test.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,30 @@ void main() {
139139
expect(cameraImage.format.group, ImageFormatGroup.yuv420);
140140
});
141141

142+
test('$CameraImage has ImageFormatGroup.nv21 for android', () {
143+
debugDefaultTargetPlatformOverride = TargetPlatform.android;
144+
145+
final CameraImage cameraImage =
146+
CameraImage.fromPlatformData(<dynamic, dynamic>{
147+
'format': 17,
148+
'height': 1,
149+
'width': 4,
150+
'lensAperture': 1.8,
151+
'sensorExposureTime': 9991324,
152+
'sensorSensitivity': 92.0,
153+
'planes': <dynamic>[
154+
<dynamic, dynamic>{
155+
'bytes': Uint8List.fromList(<int>[1, 2, 3, 4]),
156+
'bytesPerPixel': 1,
157+
'bytesPerRow': 4,
158+
'height': 1,
159+
'width': 4
160+
}
161+
]
162+
});
163+
expect(cameraImage.format.group, ImageFormatGroup.nv21);
164+
});
165+
142166
test('$CameraImage has ImageFormatGroup.bgra8888 for iOS', () {
143167
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
144168

@@ -162,6 +186,7 @@ void main() {
162186
});
163187
expect(cameraImage.format.group, ImageFormatGroup.bgra8888);
164188
});
189+
165190
test('$CameraImage has ImageFormatGroup.unknown', () {
166191
final CameraImage cameraImage =
167192
CameraImage.fromPlatformData(<dynamic, dynamic>{

0 commit comments

Comments
 (0)