diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 2fc4d7ba2ee1..797d053b5e2d 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.21+4 + +* Migrates `updateOrientation` and `setCaptureSessionPreset` methods to Swift. +* Removes `FLTCam` class. + ## 0.9.21+3 * Removes code for versions of iOS older than 13.0. diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift index a1641a6be51d..fb3b6a86d638 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift @@ -9,7 +9,7 @@ import CoreMotion import camera_avfoundation_objc #endif -final class DefaultCamera: FLTCam, Camera { +final class DefaultCamera: NSObject, Camera { var dartAPI: FCPCameraEventApi? var onFrameAvailable: (() -> Void)? @@ -23,16 +23,6 @@ final class DefaultCamera: FLTCam, Camera { private(set) var isPreviewPaused = false - override var deviceOrientation: UIDeviceOrientation { - get { super.deviceOrientation } - set { - guard newValue != super.deviceOrientation else { return } - - super.deviceOrientation = newValue - updateOrientation() - } - } - var minimumExposureOffset: CGFloat { CGFloat(captureDevice.minExposureTargetBias) } var maximumExposureOffset: CGFloat { CGFloat(captureDevice.maxExposureTargetBias) } var minimumAvailableZoomFactor: CGFloat { captureDevice.minAvailableVideoZoomFactor } @@ -53,6 +43,9 @@ final class DefaultCamera: FLTCam, Camera { private let mediaSettings: FCPPlatformMediaSettings private let mediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper + private let videoCaptureSession: FLTCaptureSession + private let audioCaptureSession: FLTCaptureSession + /// A wrapper for AVCaptureDevice creation to allow for dependency injection in tests. private let captureDeviceFactory: CaptureDeviceFactory private let audioCaptureDeviceFactory: AudioCaptureDeviceFactory @@ -60,11 +53,24 @@ final class DefaultCamera: FLTCam, Camera { private let assetWriterFactory: AssetWriterFactory private let inputPixelBufferAdaptorFactory: InputPixelBufferAdaptorFactory + /// A wrapper for CMVideoFormatDescriptionGetDimensions. + /// Allows for alternate implementations in tests. + private let videoDimensionsForFormat: VideoDimensionsForFormat + private let deviceOrientationProvider: FLTDeviceOrientationProviding + private let motionManager = CMMotionManager() + + private(set) var captureDevice: FLTCaptureDevice + // Setter exposed for tests. + var captureVideoOutput: FLTCaptureVideoDataOutput + // Setter exposed for tests. + var capturePhotoOutput: FLTCapturePhotoOutput + private var captureVideoInput: FLTCaptureInput private var videoWriter: FLTAssetWriter? private var videoWriterInput: FLTAssetWriterInput? private var audioWriterInput: FLTAssetWriterInput? + private var assetWriterPixelBufferAdaptor: FLTAssetWriterInputPixelBufferAdaptor? private var videoAdaptor: FLTAssetWriterInputPixelBufferAdaptor? /// A dictionary to retain all in-progress FLTSavePhotoDelegates. The key of the dictionary is the @@ -76,11 +82,20 @@ final class DefaultCamera: FLTCam, Camera { private var imageStreamHandler: FLTImageStreamHandler? + private var previewSize: CGSize? + var deviceOrientation: UIDeviceOrientation { + didSet { + guard deviceOrientation != oldValue else { return } + updateOrientation() + } + } + /// Tracks the latest pixel buffer sent from AVFoundation's sample buffer delegate callback. /// Used to deliver the latest pixel buffer to the flutter engine via the `copyPixelBuffer` API. private var latestPixelBuffer: CVPixelBuffer? private var videoRecordingPath: String? + private var isRecording = false private var isRecordingPaused = false private var isFirstVideoSample = false private var videoIsDisconnected = false @@ -103,6 +118,8 @@ final class DefaultCamera: FLTCam, Camera { /// https://github.com/flutter/plugins/pull/4520#discussion_r766335637 private var maxStreamingPendingFramesCount = 4 + private var fileFormat = FCPPlatformImageFileFormat.jpeg + private var lockedCaptureOrientation = UIDeviceOrientation.unknown private var exposureMode = FCPPlatformExposureMode.auto private var focusMode = FCPPlatformFocusMode.auto private var flashMode: FCPPlatformFlashMode @@ -146,24 +163,19 @@ final class DefaultCamera: FLTCam, Camera { captureSessionQueue = configuration.captureSessionQueue mediaSettings = configuration.mediaSettings mediaSettingsAVWrapper = configuration.mediaSettingsWrapper + videoCaptureSession = configuration.videoCaptureSession + audioCaptureSession = configuration.audioCaptureSession captureDeviceFactory = configuration.captureDeviceFactory audioCaptureDeviceFactory = configuration.audioCaptureDeviceFactory captureDeviceInputFactory = configuration.captureDeviceInputFactory assetWriterFactory = configuration.assetWriterFactory inputPixelBufferAdaptorFactory = configuration.inputPixelBufferAdaptorFactory + videoDimensionsForFormat = configuration.videoDimensionsForFormat deviceOrientationProvider = configuration.deviceOrientationProvider - let captureDevice = captureDeviceFactory(configuration.initialCameraName) + captureDevice = captureDeviceFactory(configuration.initialCameraName) flashMode = captureDevice.hasFlash ? .auto : .off - super.init() - - videoCaptureSession = configuration.videoCaptureSession - audioCaptureSession = configuration.audioCaptureSession - videoDimensionsForFormat = configuration.videoDimensionsForFormat - - self.captureDevice = captureDevice - capturePhotoOutput = FLTDefaultCapturePhotoOutput(photoOutput: AVCapturePhotoOutput()) capturePhotoOutput.highResolutionCaptureEnabled = true @@ -178,6 +190,8 @@ final class DefaultCamera: FLTCam, Camera { videoFormat: videoFormat, captureDeviceInputFactory: configuration.captureDeviceInputFactory) + super.init() + captureVideoOutput.setSampleBufferDelegate(self, queue: captureSessionQueue) videoCaptureSession.addInputWithNoConnections(captureVideoInput) @@ -196,11 +210,6 @@ final class DefaultCamera: FLTCam, Camera { mediaSettingsAVWrapper.beginConfiguration(for: videoCaptureSession) defer { mediaSettingsAVWrapper.commitConfiguration(for: videoCaptureSession) } - // Possible values for presets are hard-coded in FLT interface having - // corresponding AVCaptureSessionPreset counterparts. - // If _resolutionPreset is not supported by camera there is - // fallback to lower resolution presets. - // If none can be selected there is error condition. try setCaptureSessionPreset(mediaSettings.resolutionPreset) FLTSelectBestFormatForRequestedFrameRate( @@ -225,6 +234,110 @@ final class DefaultCamera: FLTCam, Camera { updateOrientation() } + // Possible values for presets are hard-coded in FLT interface having + // corresponding AVCaptureSessionPreset counterparts. + // If _resolutionPreset is not supported by camera there is + // fallback to lower resolution presets. + // If none can be selected there is error condition. + private func setCaptureSessionPreset( + _ resolutionPreset: FCPPlatformResolutionPreset + ) throws { + switch resolutionPreset { + case .max: + if let bestFormat = highestResolutionFormat(forCaptureDevice: captureDevice) { + videoCaptureSession.sessionPreset = .inputPriority + do { + try captureDevice.lockForConfiguration() + // Set the best device format found and finish the device configuration. + captureDevice.activeFormat = bestFormat + captureDevice.unlockForConfiguration() + break + } + } + fallthrough + case .ultraHigh: + if videoCaptureSession.canSetSessionPreset(.hd4K3840x2160) { + videoCaptureSession.sessionPreset = .hd4K3840x2160 + break + } + if videoCaptureSession.canSetSessionPreset(.high) { + videoCaptureSession.sessionPreset = .high + break + } + fallthrough + case .veryHigh: + if videoCaptureSession.canSetSessionPreset(.hd1920x1080) { + videoCaptureSession.sessionPreset = .hd1920x1080 + break + } + fallthrough + case .high: + if videoCaptureSession.canSetSessionPreset(.hd1280x720) { + videoCaptureSession.sessionPreset = .hd1280x720 + break + } + fallthrough + case .medium: + if videoCaptureSession.canSetSessionPreset(.vga640x480) { + videoCaptureSession.sessionPreset = .vga640x480 + break + } + fallthrough + case .low: + if videoCaptureSession.canSetSessionPreset(.cif352x288) { + videoCaptureSession.sessionPreset = .cif352x288 + break + } + fallthrough + default: + if videoCaptureSession.canSetSessionPreset(.low) { + videoCaptureSession.sessionPreset = .low + } else { + throw NSError( + domain: NSCocoaErrorDomain, + code: URLError.unknown.rawValue, + userInfo: [ + NSLocalizedDescriptionKey: "No capture session available for current capture session." + ]) + } + } + + let size = videoDimensionsForFormat(captureDevice.activeFormat) + previewSize = CGSize(width: CGFloat(size.width), height: CGFloat(size.height)) + audioCaptureSession.sessionPreset = videoCaptureSession.sessionPreset + } + + /// Finds the highest available resolution in terms of pixel count for the given device. + /// Preferred are formats with the same subtype as current activeFormat. + private func highestResolutionFormat(forCaptureDevice captureDevice: FLTCaptureDevice) + -> FLTCaptureDeviceFormat? + { + let preferredSubType = CMFormatDescriptionGetMediaSubType( + captureDevice.activeFormat.formatDescription) + var bestFormat: FLTCaptureDeviceFormat? = nil + var maxPixelCount: UInt = 0 + var isBestSubTypePreferred = false + + for format in captureDevice.formats { + let resolution = videoDimensionsForFormat(format) + let height = UInt(resolution.height) + let width = UInt(resolution.width) + let pixelCount = height * width + let subType = CMFormatDescriptionGetMediaSubType(format.formatDescription) + let isSubTypePreferred = subType == preferredSubType + + if pixelCount > maxPixelCount + || (pixelCount == maxPixelCount && isSubTypePreferred && !isBestSubTypePreferred) + { + bestFormat = format + maxPixelCount = pixelCount + isBestSubTypePreferred = isSubTypePreferred + } + } + + return bestFormat + } + func setUpCaptureSessionForAudioIfNeeded() { // Don't setup audio twice or we will lose the audio. guard !mediaSettings.enableAudio || !isAudioSetup else { return } @@ -315,8 +428,9 @@ final class DefaultCamera: FLTCam, Camera { // Get all the state on the current thread, not the main thread. let state = FCPPlatformCameraState.make( withPreviewSize: FCPPlatformSize.make( - withWidth: Double(previewSize.width), - height: Double(previewSize.height) + // previewSize is set during init, so it will never be nil. + withWidth: previewSize!.width, + height: previewSize!.height ), exposureMode: exposureMode, focusMode: focusMode, @@ -621,6 +735,45 @@ final class DefaultCamera: FLTCam, Camera { return file } + private func updateOrientation() { + guard !isRecording else { return } + + let orientation = + (lockedCaptureOrientation != .unknown) + ? lockedCaptureOrientation + : deviceOrientation + + updateOrientation(orientation, forCaptureOutput: capturePhotoOutput) + updateOrientation(orientation, forCaptureOutput: captureVideoOutput) + } + + private func updateOrientation( + _ orientation: UIDeviceOrientation, forCaptureOutput captureOutput: FLTCaptureOutput + ) { + if let connection = captureOutput.connection(withMediaType: .video), + connection.isVideoOrientationSupported + { + connection.videoOrientation = videoOrientation(forDeviceOrientation: orientation) + } + } + + private func videoOrientation(forDeviceOrientation deviceOrientation: UIDeviceOrientation) + -> AVCaptureVideoOrientation + { + switch deviceOrientation { + case .portrait: + return .portrait + case .landscapeLeft: + return .landscapeRight + case .landscapeRight: + return .landscapeLeft + case .portraitUpsideDown: + return .portraitUpsideDown + default: + return .portrait + } + } + func lockCaptureOrientation(_ pigeonOrientation: FCPPlatformDeviceOrientation) { let orientation = FCPGetUIDeviceOrientationForPigeonDeviceOrientation(pigeonOrientation) if lockedCaptureOrientation != orientation { diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCam.m deleted file mode 100644 index c8da28502ce9..000000000000 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCam.m +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "./include/camera_avfoundation/FLTCam.h" -#import "./include/camera_avfoundation/FLTCam_Test.h" - -@import Flutter; -#import - -#import "./include/camera_avfoundation/FLTCaptureConnection.h" -#import "./include/camera_avfoundation/FLTCaptureDevice.h" -#import "./include/camera_avfoundation/FLTDeviceOrientationProviding.h" -#import "./include/camera_avfoundation/FLTEventChannel.h" -#import "./include/camera_avfoundation/FLTFormatUtils.h" -#import "./include/camera_avfoundation/FLTImageStreamHandler.h" -#import "./include/camera_avfoundation/FLTSavePhotoDelegate.h" -#import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" -#import "./include/camera_avfoundation/QueueUtils.h" -#import "./include/camera_avfoundation/messages.g.h" - -@interface FLTCam () -@end - -@implementation FLTCam -- (void)updateOrientation { - if (_isRecording) { - return; - } - - UIDeviceOrientation orientation = (_lockedCaptureOrientation != UIDeviceOrientationUnknown) - ? _lockedCaptureOrientation - : _deviceOrientation; - - [self updateOrientation:orientation forCaptureOutput:_capturePhotoOutput]; - [self updateOrientation:orientation forCaptureOutput:_captureVideoOutput]; -} - -- (void)updateOrientation:(UIDeviceOrientation)orientation - forCaptureOutput:(NSObject *)captureOutput { - if (!captureOutput) { - return; - } - - NSObject *connection = - [captureOutput connectionWithMediaType:AVMediaTypeVideo]; - if (connection && connection.isVideoOrientationSupported) { - connection.videoOrientation = [self getVideoOrientationForDeviceOrientation:orientation]; - } -} - -- (AVCaptureVideoOrientation)getVideoOrientationForDeviceOrientation: - (UIDeviceOrientation)deviceOrientation { - if (deviceOrientation == UIDeviceOrientationPortrait) { - return AVCaptureVideoOrientationPortrait; - } else if (deviceOrientation == UIDeviceOrientationLandscapeLeft) { - // Note: device orientation is flipped compared to video orientation. When UIDeviceOrientation - // is landscape left the video orientation should be landscape right. - return AVCaptureVideoOrientationLandscapeRight; - } else if (deviceOrientation == UIDeviceOrientationLandscapeRight) { - // Note: device orientation is flipped compared to video orientation. When UIDeviceOrientation - // is landscape right the video orientation should be landscape left. - return AVCaptureVideoOrientationLandscapeLeft; - } else if (deviceOrientation == UIDeviceOrientationPortraitUpsideDown) { - return AVCaptureVideoOrientationPortraitUpsideDown; - } else { - return AVCaptureVideoOrientationPortrait; - } -} - -- (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset - withError:(NSError **)error { - switch (resolutionPreset) { - case FCPPlatformResolutionPresetMax: { - NSObject *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]; - break; - } - } - } - case FCPPlatformResolutionPresetUltraHigh: - if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset3840x2160]) { - _videoCaptureSession.sessionPreset = AVCaptureSessionPreset3840x2160; - break; - } - if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) { - _videoCaptureSession.sessionPreset = AVCaptureSessionPresetHigh; - break; - } - case FCPPlatformResolutionPresetVeryHigh: - if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset1920x1080]) { - _videoCaptureSession.sessionPreset = AVCaptureSessionPreset1920x1080; - break; - } - case FCPPlatformResolutionPresetHigh: - if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) { - _videoCaptureSession.sessionPreset = AVCaptureSessionPreset1280x720; - break; - } - case FCPPlatformResolutionPresetMedium: - if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) { - _videoCaptureSession.sessionPreset = AVCaptureSessionPreset640x480; - break; - } - case FCPPlatformResolutionPresetLow: - if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset352x288]) { - _videoCaptureSession.sessionPreset = AVCaptureSessionPreset352x288; - break; - } - default: - if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPresetLow]) { - _videoCaptureSession.sessionPreset = AVCaptureSessionPresetLow; - } else { - if (error != nil) { - *error = - [NSError errorWithDomain:NSCocoaErrorDomain - code:NSURLErrorUnknown - userInfo:@{ - NSLocalizedDescriptionKey : - @"No capture session available for current capture session." - }]; - } - return NO; - } - } - CMVideoDimensions size = self.videoDimensionsForFormat(_captureDevice.activeFormat); - _previewSize = CGSizeMake(size.width, size.height); - _audioCaptureSession.sessionPreset = _videoCaptureSession.sessionPreset; - return YES; -} - -/// Finds the highest available resolution in terms of pixel count for the given device. -/// Preferred are formats with the same subtype as current activeFormat. -- (NSObject *)highestResolutionFormatForCaptureDevice: - (NSObject *)captureDevice { - FourCharCode preferredSubType = - CMFormatDescriptionGetMediaSubType(_captureDevice.activeFormat.formatDescription); - NSObject *bestFormat = nil; - NSUInteger maxPixelCount = 0; - BOOL isBestSubTypePreferred = NO; - for (NSObject *format in _captureDevice.formats) { - CMVideoDimensions res = self.videoDimensionsForFormat(format); - NSUInteger height = res.height; - NSUInteger width = res.width; - NSUInteger pixelCount = height * width; - FourCharCode subType = CMFormatDescriptionGetMediaSubType(format.formatDescription); - BOOL isSubTypePreferred = subType == preferredSubType; - if (pixelCount > maxPixelCount || - (pixelCount == maxPixelCount && isSubTypePreferred && !isBestSubTypePreferred)) { - bestFormat = format; - maxPixelCount = pixelCount; - isBestSubTypePreferred = isSubTypePreferred; - } - } - return bestFormat; -} - -@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam.h deleted file mode 100644 index 667445ec8a31..000000000000 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import AVFoundation; -@import Foundation; -@import Flutter; -@import CoreMotion; - -#import "CameraProperties.h" -#import "FLTCamConfiguration.h" -#import "FLTCamMediaSettingsAVWrapper.h" -#import "FLTCaptureDevice.h" -#import "FLTDeviceOrientationProviding.h" -#import "FLTImageStreamHandler.h" -#import "messages.g.h" - -NS_ASSUME_NONNULL_BEGIN - -/// A class that manages camera's state and performs camera operations. -@interface FLTCam : NSObject - -// captureDevice is assignable for the Swift DefaultCamera subclass -@property(strong, nonatomic) NSObject *captureDevice; -@property(readonly, nonatomic) CGSize previewSize; -@property(assign, nonatomic) FCPPlatformImageFileFormat fileFormat; - -// Properties exposed for the Swift DefaultCamera subclass -@property(assign, nonatomic) BOOL isRecording; -// videoCaptureSession is assignable for the Swift DefaultCamera subclass -@property(strong, nonatomic) NSObject *videoCaptureSession; -// audioCaptureSession is assignable for the Swift DefaultCamera subclass -@property(strong, nonatomic) NSObject *audioCaptureSession; -@property(assign, nonatomic) UIDeviceOrientation lockedCaptureOrientation; -@property(assign, nonatomic) UIDeviceOrientation deviceOrientation; -@property(nonatomic) CMMotionManager *motionManager; -@property(strong, nonatomic) NSObject *captureVideoInput; -/// A wrapper for CMVideoFormatDescriptionGetDimensions. -/// Allows for alternate implementations in tests. -@property(nonatomic, copy) VideoDimensionsForFormat videoDimensionsForFormat; - -// Methods exposed for the Swift DefaultCamera subclass -- (void)updateOrientation; - -- (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset - withError:(NSError **)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam_Test.h deleted file mode 100644 index f88d88524ea0..000000000000 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam_Test.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "FLTCam.h" -#import "FLTCaptureConnection.h" -#import "FLTCaptureDevice.h" -#import "FLTCapturePhotoOutput.h" -#import "FLTCaptureVideoDataOutput.h" -#import "FLTDeviceOrientationProviding.h" -#import "FLTImageStreamHandler.h" -#import "FLTSavePhotoDelegate.h" - -// APIs exposed for unit testing. -@interface FLTCam () - -/// The output for video capturing. -@property(strong, nonatomic) NSObject *captureVideoOutput; - -/// The output for photo capturing. Exposed setter for unit tests. -@property(strong, nonatomic) NSObject *capturePhotoOutput; - -@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/camera_avfoundation.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/camera_avfoundation.h index 599b313defd6..d19cd0c5c708 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/camera_avfoundation.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/camera_avfoundation.h @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "FLTCam.h" #import "FLTCamConfiguration.h" #import "FLTCameraDeviceDiscovering.h" #import "FLTCameraPermissionManager.h" diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index e4f44045e432..4603ead66599 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ 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.21+3 +version: 0.9.21+4 environment: sdk: ^3.9.0