Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
01ad812
Set higher resolution when using max preset
sergeidesenko Jul 30, 2023
5f5cabc
Merge remote-tracking branch 'upstream/main' into camera_avfoundation…
sergeidesenko Oct 27, 2023
f9f302f
chore: update changelog
sergeidesenko Oct 27, 2023
e5a33f6
chore: update changelog and pubspec
sergeidesenko Oct 27, 2023
d3ce411
refactor: add comments
sergeidesenko Oct 27, 2023
5813f25
chore: update pubspec
sergeidesenko Oct 27, 2023
60e043a
feat(tests): add convenience method for camera init
sergeidesenko Jan 22, 2024
9830404
feat(tests): add tests for setting resolutionPresets
sergeidesenko Jan 22, 2024
87b0c59
chore(tests): add tests file to .pbxproj
sergeidesenko Jan 22, 2024
0c29019
chore: fix formatting for updated files
sergeidesenko Jan 22, 2024
ae0210f
fix: don't update the changelog
sergeidesenko Jan 31, 2024
0c8b21a
refactor: remove todo and renaming
sergeidesenko Jan 31, 2024
37ffaa7
Merge remote-tracking branch 'upstream/main' into camera_avfoundation…
sergeidesenko Jan 31, 2024
70deac4
Merge branch 'main' into camera_avfoundation-max-resolution
sergeidesenko Feb 2, 2024
0fe1ac7
feat: add tests for different resolution presets
sergeidesenko Feb 2, 2024
c314755
refactor: update comment
sergeidesenko Feb 2, 2024
ec1b896
refactor: change tests to use DI
sergeidesenko Feb 2, 2024
5e6f1f5
refactor: rename method
sergeidesenko Feb 2, 2024
decce1e
refactor: rename method
sergeidesenko Feb 2, 2024
832cc7b
refactor: cleaner DI
sergeidesenko Feb 13, 2024
ddfe778
refactor: update comments
sergeidesenko Feb 21, 2024
5c01c8c
refactor: update comment to match arguments
sergeidesenko Feb 21, 2024
0c40901
refactor: rename types
sergeidesenko Feb 22, 2024
42e9cfa
Merge branch 'main' into camera_avfoundation-max-resolution
sergeidesenko Mar 1, 2024
8e019b3
refactor: address code review
sergeidesenko Mar 1, 2024
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
4 changes: 4 additions & 0 deletions packages/camera/camera_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.9.14+1

* Fixes bug where max resolution preset does not produce highest available resolution on iOS.

## 0.9.14

* Adds support to HEIF format.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
CEF6611A2B5E36A500D33FD4 /* CameraSessionPresetsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CEF661192B5E36A500D33FD4 /* CameraSessionPresetsTests.m */; };
E01EE4A82799F3A5008C1950 /* QueueUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E01EE4A72799F3A5008C1950 /* QueueUtilsTests.m */; };
E032F250279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E032F24F279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m */; };
E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E04F108527A87CA600573D0C /* FLTSavePhotoDelegateTests.m */; };
Expand Down Expand Up @@ -89,6 +90,7 @@
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9C5CC6CAD53AD388B2694F3A /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
A24F9E418BA48BCC7409B117 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
CEF661192B5E36A500D33FD4 /* CameraSessionPresetsTests.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = CameraSessionPresetsTests.m; sourceTree = "<group>"; };
E01EE4A72799F3A5008C1950 /* QueueUtilsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QueueUtilsTests.m; sourceTree = "<group>"; };
E032F24F279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraCaptureSessionQueueRaceConditionTests.m; sourceTree = "<group>"; };
E04F108527A87CA600573D0C /* FLTSavePhotoDelegateTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTSavePhotoDelegateTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -151,6 +153,7 @@
E0F95E3C27A32AB900699390 /* CameraPropertiesTests.m */,
788A065927B0E02900533D74 /* StreamingTest.m */,
43ED1536282570DE00EB00DE /* AvailableCamerasTest.m */,
CEF661192B5E36A500D33FD4 /* CameraSessionPresetsTests.m */,
);
path = RunnerTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -451,6 +454,7 @@
F6EE622F2710A6FC00905E4A /* MockFLTThreadSafeFlutterResult.m in Sources */,
E0CDBAC227CD9729002561D9 /* CameraTestUtils.m in Sources */,
334733EA2668111C00DCC49E /* CameraOrientationTests.m in Sources */,
CEF6611A2B5E36A500D33FD4 /* CameraSessionPresetsTests.m in Sources */,
E032F250279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m in Sources */,
788A065A27B0E02900533D74 /* StreamingTest.m in Sources */,
E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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 camera_avfoundation;
@import camera_avfoundation.Test;

@import AVFoundation;
@import XCTest;
#import <OCMock/OCMock.h>
#import "CameraTestUtils.h"

/// Includes test cases related to resolution presets setting operations for FLTCam class.
@interface FLTCamSessionPresetsTest : XCTestCase
@end

@implementation FLTCamSessionPresetsTest

- (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset {
NSString *expectedPreset = AVCaptureSessionPresetInputPriority;

id videoSessionMock = OCMClassMock([AVCaptureSession class]);
OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]);

id captureFormatMock = OCMClassMock([AVCaptureDeviceFormat class]);
id captureDeviceMock = OCMClassMock([AVCaptureDevice class]);
OCMStub([captureDeviceMock formats]).andReturn(@[ captureFormatMock ]);

OCMExpect([captureDeviceMock activeFormat]).andReturn(captureFormatMock);
OCMExpect([captureDeviceMock lockForConfiguration:NULL]).andReturn(YES);
OCMExpect([videoSessionMock setSessionPreset:expectedPreset]);

FLTCreateCamWithVideoDimensionsForFormat(videoSessionMock, @"max", captureDeviceMock,
^CMVideoDimensions(AVCaptureDeviceFormat *format) {
CMVideoDimensions videoDimensions;
videoDimensions.width = 1;
videoDimensions.height = 1;
return videoDimensions;
});

OCMVerifyAll(captureDeviceMock);
OCMVerifyAll(videoSessionMock);
}

- (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset {
NSString *expectedPreset = AVCaptureSessionPreset3840x2160;

id videoSessionMock = OCMClassMock([AVCaptureSession class]);
OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]);

// Make sure that setting resolution preset for session always succeeds.
OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);

OCMExpect([videoSessionMock setSessionPreset:expectedPreset]);

FLTCreateCamWithVideoCaptureSession(videoSessionMock, @"max");

OCMVerifyAll(videoSessionMock);
}

- (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset {
NSString *expectedPreset = AVCaptureSessionPreset3840x2160;

id videoSessionMock = OCMClassMock([AVCaptureSession class]);
OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]);

// Make sure that setting resolution preset for session always succeeds.
OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);

// Expect that setting "ultraHigh" resolutionPreset correctly updates videoCaptureSession.
OCMExpect([videoSessionMock setSessionPreset:expectedPreset]);

FLTCreateCamWithVideoCaptureSession(videoSessionMock, @"ultraHigh");

OCMVerifyAll(videoSessionMock);
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ NS_ASSUME_NONNULL_BEGIN
/// @return an FLTCam object.
extern FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue);

/// Creates an `FLTCam` with a given captureSession and resolutionPreset
/// @param captureSession AVCaptureSession for video
/// @param resolutionPreset preset for camera's captureSession resolution
/// @return an FLTCam object.
extern FLTCam *FLTCreateCamWithVideoCaptureSession(AVCaptureSession *captureSession,
NSString *resolutionPreset);

/// Creates an `FLTCam` with a given captureSession and resolutionPreset.
/// Allows to inject a capture device and a block to compute the video dimensions.
/// @param captureSession AVCaptureSession for video
/// @param resolutionPreset preset for camera's captureSession resolution
/// @param captureDevice AVCaptureDevice to be used
/// @param videoDimensionsForFormat custom code to determine video dimensions
/// @return an FLTCam object.
extern FLTCam *FLTCreateCamWithVideoDimensionsForFormat(
AVCaptureSession *captureSession, NSString *resolutionPreset, AVCaptureDevice *captureDevice,
VideoDimensionsForFormat videoDimensionsForFormat);

/// Creates a test sample buffer.
/// @return a test sample buffer.
extern CMSampleBufferRef FLTCreateTestSampleBuffer(void);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
.andReturn(inputMock);

id videoSessionMock = OCMClassMock([AVCaptureSession class]);
OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); // no-op
OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]);
OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);

id audioSessionMock = OCMClassMock([AVCaptureSession class]);
OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); // no-op
OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]);
OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);

return [[FLTCam alloc] initWithCameraName:@"camera"
Expand All @@ -29,6 +29,51 @@
error:nil];
}

FLTCam *FLTCreateCamWithVideoCaptureSession(AVCaptureSession *captureSession,
NSString *resolutionPreset) {
id inputMock = OCMClassMock([AVCaptureDeviceInput class]);
OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]])
.andReturn(inputMock);

id audioSessionMock = OCMClassMock([AVCaptureSession class]);
OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]);
OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);

return [[FLTCam alloc] initWithCameraName:@"camera"
resolutionPreset:resolutionPreset
enableAudio:true
orientation:UIDeviceOrientationPortrait
videoCaptureSession:captureSession
audioCaptureSession:audioSessionMock
captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL)
error:nil];
}

FLTCam *FLTCreateCamWithVideoDimensionsForFormat(
AVCaptureSession *captureSession, NSString *resolutionPreset, AVCaptureDevice *captureDevice,
VideoDimensionsForFormat videoDimensionsForFormat) {
id inputMock = OCMClassMock([AVCaptureDeviceInput class]);
OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]])
.andReturn(inputMock);

id audioSessionMock = OCMClassMock([AVCaptureSession class]);
OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]);
OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);

return
[[FLTCam alloc] initWithResolutionPreset:resolutionPreset
enableAudio:true
orientation:UIDeviceOrientationPortrait
videoCaptureSession:captureSession
audioCaptureSession:audioSessionMock
captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL)
captureDeviceFactory:^AVCaptureDevice *(void) {
return captureDevice;
}
videoDimensionsForFormat:videoDimensionsForFormat
error:nil];
}

CMSampleBufferRef FLTCreateTestSampleBuffer(void) {
CVPixelBufferRef pixelBuffer;
CVPixelBufferCreate(kCFAllocatorDefault, 100, 100, kCVPixelFormatType_32BGRA, NULL, &pixelBuffer);
Expand Down
1 change: 1 addition & 0 deletions packages/camera/camera_avfoundation/ios/Classes/FLTCam.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
orientation:(UIDeviceOrientation)orientation
captureSessionQueue:(dispatch_queue_t)captureSessionQueue
error:(NSError **)error;

- (void)start;
- (void)stop;
- (void)setDeviceOrientation:(UIDeviceOrientation)orientation;
Expand Down
72 changes: 69 additions & 3 deletions packages/camera/camera_avfoundation/ios/Classes/FLTCam.m
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ @interface FLTCam () <AVCaptureVideoDataOutputSampleBufferDelegate,
/// Videos are written to disk by `videoAdaptor` on an internal queue managed by AVFoundation.
@property(strong, nonatomic) dispatch_queue_t photoIOQueue;
@property(assign, nonatomic) UIDeviceOrientation deviceOrientation;
/// A wrapper for CMVideoFormatDescriptionGetDimensions.
/// Allows for alternate implementations in tests.
@property(nonatomic, copy) VideoDimensionsForFormat videoDimensionsForFormat;
/// A wrapper for AVCaptureDevice creation to allow for dependency injection in tests.
@property(nonatomic, copy) CaptureDeviceFactory captureDeviceFactory;
@end

@implementation FLTCam
Expand Down Expand Up @@ -116,6 +121,30 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
audioCaptureSession:(AVCaptureSession *)audioCaptureSession
captureSessionQueue:(dispatch_queue_t)captureSessionQueue
error:(NSError **)error {
return [self initWithResolutionPreset:resolutionPreset
enableAudio:enableAudio
orientation:orientation
videoCaptureSession:videoCaptureSession
audioCaptureSession:videoCaptureSession
captureSessionQueue:captureSessionQueue
captureDeviceFactory:^AVCaptureDevice *(void) {
return [AVCaptureDevice deviceWithUniqueID:cameraName];
}
videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) {
return CMVideoFormatDescriptionGetDimensions(format.formatDescription);
}
error:error];
}

- (instancetype)initWithResolutionPreset:(NSString *)resolutionPreset
enableAudio:(BOOL)enableAudio
orientation:(UIDeviceOrientation)orientation
videoCaptureSession:(AVCaptureSession *)videoCaptureSession
audioCaptureSession:(AVCaptureSession *)audioCaptureSession
captureSessionQueue:(dispatch_queue_t)captureSessionQueue
captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory
videoDimensionsForFormat:(VideoDimensionsForFormat)videoDimensionsForFormat
error:(NSError **)error {
self = [super init];
NSAssert(self, @"super init cannot be nil");
_resolutionPreset = FLTGetFLTResolutionPresetForString(resolutionPreset);
Expand All @@ -136,7 +165,9 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
_photoIOQueue = dispatch_queue_create("io.flutter.camera.photoIOQueue", NULL);
_videoCaptureSession = videoCaptureSession;
_audioCaptureSession = audioCaptureSession;
_captureDevice = [AVCaptureDevice deviceWithUniqueID:cameraName];
_captureDeviceFactory = captureDeviceFactory;
_captureDevice = captureDeviceFactory();
_videoDimensionsForFormat = videoDimensionsForFormat;
_flashMode = _captureDevice.hasFlash ? FLTFlashModeAuto : FLTFlashModeOff;
_exposureMode = FLTExposureModeAuto;
_focusMode = FLTFocusModeAuto;
Expand Down Expand Up @@ -366,7 +397,24 @@ - (NSString *)getTemporaryFilePathWithExtension:(NSString *)extension

- (BOOL)setCaptureSessionPreset:(FLTResolutionPreset)resolutionPreset withError:(NSError **)error {
switch (resolutionPreset) {
case FLTResolutionPresetMax:
case FLTResolutionPresetMax: {
AVCaptureDeviceFormat *bestFormat =
[self highestResolutionFormatForCaptureDevice:_captureDevice];
if (bestFormat) {
_videoCaptureSession.sessionPreset = AVCaptureSessionPresetInputPriority;
if ([_captureDevice lockForConfiguration:NULL]) {
// Set the best device format found and finish the device configuration.
_captureDevice.activeFormat = bestFormat;
[_captureDevice unlockForConfiguration];

// Set the preview size based on values from the current capture device.
_previewSize =
CGSizeMake(_captureDevice.activeFormat.highResolutionStillImageDimensions.width,
_captureDevice.activeFormat.highResolutionStillImageDimensions.height);
break;
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This should be after the code below, enclosing the entire case implementation, otherwise the indentation is very confusing.

Copy link
Contributor Author

@sergeidesenko sergeidesenko Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed everything
In this case I decided to just remove everything related to AVCaptureSessionPreset3840x2160, since it was just a repetition of the next case (FLTResolutionPresetUltraHigh). Now it's more in line with other cases

Out of curiosity - what's your definition of nit in this context? I thought these are not compulsory

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally use it to indicate that something is a very small change. I wasn't aware there was a doc that equated it with being optional; I'll stop using it given that.

case FLTResolutionPresetUltraHigh:
if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset3840x2160]) {
_videoCaptureSession.sessionPreset = AVCaptureSessionPreset3840x2160;
Expand Down Expand Up @@ -422,6 +470,24 @@ - (BOOL)setCaptureSessionPreset:(FLTResolutionPreset)resolutionPreset withError:
return YES;
}

/// Finds the highest available resolution in terms of pixel count for the given device.
- (AVCaptureDeviceFormat *)highestResolutionFormatForCaptureDevice:
(AVCaptureDevice *)captureDevice {
AVCaptureDeviceFormat *bestFormat = nil;
NSUInteger maxPixelCount = 0;
for (AVCaptureDeviceFormat *format in _captureDevice.formats) {
CMVideoDimensions res = self.videoDimensionsForFormat(format);
NSUInteger height = res.height;
NSUInteger width = res.width;
NSUInteger pixelCount = height * width;
if (pixelCount > maxPixelCount) {
maxPixelCount = pixelCount;
bestFormat = format;
}
}
return bestFormat;
}

- (void)captureOutput:(AVCaptureOutput *)output
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection {
Expand Down Expand Up @@ -935,7 +1001,7 @@ - (void)setDescriptionWhileRecording:(NSString *)cameraName
return;
}

_captureDevice = [AVCaptureDevice deviceWithUniqueID:cameraName];
_captureDevice = self.captureDeviceFactory();

Comment on lines -938 to 1005
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hellohuanlin you are probably right, this line is causing camera not updating.
Reverting this one line would fix it, I think, and wouldn't break the tests that depend on captureDeviceFactory to work. Unfortunately, I don't think I have enough bandwidth right now to go through with a new pr, which again will require writing new tests and going through a code review.

Would you consider just reverting this pr altogether?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be reverted, the cameraName should just be a parameter to the factory method. I missed in review that it was no longer using the local name.

AVCaptureConnection *oldConnection =
[_captureVideoOutput connectionWithMediaType:AVMediaTypeVideo];
Expand Down
21 changes: 21 additions & 0 deletions packages/camera/camera_avfoundation/ios/Classes/FLTCam_Test.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
#import "FLTCam.h"
#import "FLTSavePhotoDelegate.h"

/// Determines the video dimensions (width and height) for a given capture device format.
/// Used in tests to mock CMVideoFormatDescriptionGetDimensions.
typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *);

/// Factory block returning an AVCaptureDevice.
/// Used in tests to inject a device into FLTCam.
typedef AVCaptureDevice * (^CaptureDeviceFactory)(void);

@interface FLTImageStreamHandler : NSObject <FlutterStreamHandler>

/// The queue on which `eventSink` property should be accessed.
Expand Down Expand Up @@ -55,6 +63,19 @@
captureSessionQueue:(dispatch_queue_t)captureSessionQueue
error:(NSError **)error;

/// Initializes a camera instance.
/// Allows for testing with specified resolution, audio preference, orientation,
/// and direct access to capture sessions and blocks.
- (instancetype)initWithResolutionPreset:(NSString *)resolutionPreset
enableAudio:(BOOL)enableAudio
orientation:(UIDeviceOrientation)orientation
videoCaptureSession:(AVCaptureSession *)videoCaptureSession
audioCaptureSession:(AVCaptureSession *)audioCaptureSession
captureSessionQueue:(dispatch_queue_t)captureSessionQueue
captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory
videoDimensionsForFormat:(VideoDimensionsForFormat)videoDimensionsForFormat
error:(NSError **)error;

/// Start streaming images.
- (void)startImageStreamWithMessenger:(NSObject<FlutterBinaryMessenger> *)messenger
imageStreamHandler:(FLTImageStreamHandler *)imageStreamHandler;
Expand Down
3 changes: 2 additions & 1 deletion packages/camera/camera_avfoundation/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: camera_avfoundation
description: iOS implementation of the camera plugin.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.9.14

version: 0.9.14+1

environment:
sdk: ^3.2.3
Expand Down