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

Commit e282dfb

Browse files
authored
[camera] Fix ImageStream ImageFormatGroup is Ignored in iOS (#4519)
1 parent eb6e912 commit e282dfb

File tree

4 files changed

+70
-7
lines changed

4 files changed

+70
-7
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.9.4+8
2+
3+
* Fixes a bug where ImageFormatGroup was ignored in `startImageStream` on iOS.
4+
15
## 0.9.4+7
26

37
* Fixes a crash in iOS when passing null queue pointer into AVFoundation API due to race condition.

packages/camera/camera/example/integration_test/camera_test.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,4 +240,56 @@ void main() {
240240
},
241241
skip: !Platform.isAndroid,
242242
);
243+
244+
/// Start streaming with specifying the ImageFormatGroup.
245+
Future<CameraImage> startStreaming(List<CameraDescription> cameras,
246+
ImageFormatGroup? imageFormatGroup) async {
247+
final CameraController controller = CameraController(
248+
cameras.first,
249+
ResolutionPreset.low,
250+
enableAudio: false,
251+
imageFormatGroup: imageFormatGroup,
252+
);
253+
254+
await controller.initialize();
255+
final _completer = Completer<CameraImage>();
256+
257+
await controller.startImageStream((CameraImage image) {
258+
if (!_completer.isCompleted) {
259+
Future(() async {
260+
await controller.stopImageStream();
261+
await controller.dispose();
262+
}).then((value) {
263+
_completer.complete(image);
264+
});
265+
}
266+
});
267+
return _completer.future;
268+
}
269+
270+
testWidgets(
271+
'iOS image streaming with imageFormatGroup',
272+
(WidgetTester tester) async {
273+
final List<CameraDescription> cameras = await availableCameras();
274+
if (cameras.isEmpty) {
275+
return;
276+
}
277+
278+
var _image = await startStreaming(cameras, null);
279+
expect(_image, isNotNull);
280+
expect(_image.format.group, ImageFormatGroup.bgra8888);
281+
expect(_image.planes.length, 1);
282+
283+
_image = await startStreaming(cameras, ImageFormatGroup.yuv420);
284+
expect(_image, isNotNull);
285+
expect(_image.format.group, ImageFormatGroup.yuv420);
286+
expect(_image.planes.length, 2);
287+
288+
_image = await startStreaming(cameras, ImageFormatGroup.bgra8888);
289+
expect(_image, isNotNull);
290+
expect(_image.format.group, ImageFormatGroup.bgra8888);
291+
expect(_image.planes.length, 1);
292+
},
293+
skip: !Platform.isIOS,
294+
);
243295
}

packages/camera/camera/ios/Classes/CameraPlugin.m

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,8 @@ @interface FLTCam : NSObject <FlutterTexture,
355355
@property(assign, nonatomic) CMTime lastAudioSampleTime;
356356
@property(assign, nonatomic) CMTime videoTimeOffset;
357357
@property(assign, nonatomic) CMTime audioTimeOffset;
358+
// Format used for video and image streaming.
359+
@property(assign, nonatomic) FourCharCode videoFormat;
358360
@property(nonatomic) CMMotionManager *motionManager;
359361
@property AVAssetWriterInputPixelBufferAdaptor *videoAdaptor;
360362
@end
@@ -365,8 +367,6 @@ @implementation FLTCam {
365367
dispatch_queue_t _captureSessionQueue;
366368
UIDeviceOrientation _deviceOrientation;
367369
}
368-
// Format used for video and image streaming.
369-
FourCharCode videoFormat = kCVPixelFormatType_32BGRA;
370370
NSString *const errorMethod = @"error";
371371

372372
- (instancetype)initWithCameraName:(NSString *)cameraName
@@ -391,6 +391,7 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
391391
_focusMode = FocusModeAuto;
392392
_lockedCaptureOrientation = UIDeviceOrientationUnknown;
393393
_deviceOrientation = orientation;
394+
_videoFormat = kCVPixelFormatType_32BGRA;
394395

395396
NSError *localError = nil;
396397
_captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice
@@ -403,7 +404,7 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
403404

404405
_captureVideoOutput = [AVCaptureVideoDataOutput new];
405406
_captureVideoOutput.videoSettings =
406-
@{(NSString *)kCVPixelBufferPixelFormatTypeKey : @(videoFormat)};
407+
@{(NSString *)kCVPixelBufferPixelFormatTypeKey : @(_videoFormat)};
407408
[_captureVideoOutput setAlwaysDiscardsLateVideoFrames:YES];
408409
[_captureVideoOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
409410

@@ -441,6 +442,12 @@ - (void)stop {
441442
[_captureSession stopRunning];
442443
}
443444

445+
- (void)setVideoFormat:(OSType)videoFormat {
446+
_videoFormat = videoFormat;
447+
_captureVideoOutput.videoSettings =
448+
@{(NSString *)kCVPixelBufferPixelFormatTypeKey : @(videoFormat)};
449+
}
450+
444451
- (void)setDeviceOrientation:(UIDeviceOrientation)orientation {
445452
if (_deviceOrientation == orientation) {
446453
return;
@@ -680,7 +687,7 @@ - (void)captureOutput:(AVCaptureOutput *)output
680687
NSMutableDictionary *imageBuffer = [NSMutableDictionary dictionary];
681688
imageBuffer[@"width"] = [NSNumber numberWithUnsignedLong:imageWidth];
682689
imageBuffer[@"height"] = [NSNumber numberWithUnsignedLong:imageHeight];
683-
imageBuffer[@"format"] = @(videoFormat);
690+
imageBuffer[@"format"] = @(_videoFormat);
684691
imageBuffer[@"planes"] = planes;
685692
imageBuffer[@"lensAperture"] = [NSNumber numberWithFloat:[_captureDevice lensAperture]];
686693
Float64 exposureDuration = CMTimeGetSeconds([_captureDevice exposureDuration]);
@@ -1246,7 +1253,7 @@ - (BOOL)setupWriterForPath:(NSString *)path {
12461253
_videoAdaptor = [AVAssetWriterInputPixelBufferAdaptor
12471254
assetWriterInputPixelBufferAdaptorWithAssetWriterInput:_videoWriterInput
12481255
sourcePixelBufferAttributes:@{
1249-
(NSString *)kCVPixelBufferPixelFormatTypeKey : @(videoFormat)
1256+
(NSString *)kCVPixelBufferPixelFormatTypeKey : @(_videoFormat)
12501257
}];
12511258

12521259
NSParameterAssert(_videoWriterInput);
@@ -1464,7 +1471,7 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call
14641471
NSUInteger cameraId = ((NSNumber *)argsMap[@"cameraId"]).unsignedIntegerValue;
14651472
if ([@"initialize" isEqualToString:call.method]) {
14661473
NSString *videoFormatValue = ((NSString *)argsMap[@"imageFormatGroup"]);
1467-
videoFormat = getVideoFormatFromString(videoFormatValue);
1474+
[_camera setVideoFormat:getVideoFormatFromString(videoFormatValue)];
14681475

14691476
__weak CameraPlugin *weakSelf = self;
14701477
_camera.onFrameAvailable = ^{

packages/camera/camera/pubspec.yaml

Lines changed: 1 addition & 1 deletion
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/plugins/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.9.4+7
7+
version: 0.9.4+8
88

99
environment:
1010
sdk: ">=2.14.0 <3.0.0"

0 commit comments

Comments
 (0)