|  | /* | 
|  | *  Copyright 2017 The WebRTC Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #import "ARDCaptureController.h" | 
|  |  | 
|  | #import "sdk/objc/base/RTCLogging.h" | 
|  |  | 
|  | #import "ARDSettingsModel.h" | 
|  |  | 
|  | const Float64 kFramerateLimit = 30.0; | 
|  |  | 
|  | @implementation ARDCaptureController { | 
|  | RTC_OBJC_TYPE(RTCCameraVideoCapturer) * _capturer; | 
|  | ARDSettingsModel *_settings; | 
|  | BOOL _usingFrontCamera; | 
|  | } | 
|  |  | 
|  | - (instancetype)initWithCapturer: | 
|  | (RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)capturer | 
|  | settings:(ARDSettingsModel *)settings { | 
|  | self = [super init]; | 
|  | if (self) { | 
|  | _capturer = capturer; | 
|  | _settings = settings; | 
|  | _usingFrontCamera = YES; | 
|  | } | 
|  | return self; | 
|  | } | 
|  |  | 
|  | - (void)startCapture { | 
|  | [self startCapture:nil]; | 
|  | } | 
|  |  | 
|  | - (void)startCapture:(void (^)(NSError *))completion { | 
|  | AVCaptureDevicePosition position = _usingFrontCamera ? | 
|  | AVCaptureDevicePositionFront : | 
|  | AVCaptureDevicePositionBack; | 
|  | AVCaptureDevice *device = [self findDeviceForPosition:position]; | 
|  | AVCaptureDeviceFormat *format = [self selectFormatForDevice:device]; | 
|  |  | 
|  | if (format == nil) { | 
|  | RTCLogError(@"No valid formats for device %@", device); | 
|  | NSAssert(NO, @""); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | NSInteger fps = [self selectFpsForFormat:format]; | 
|  |  | 
|  | [_capturer startCaptureWithDevice:device | 
|  | format:format | 
|  | fps:fps | 
|  | completionHandler:completion]; | 
|  | } | 
|  |  | 
|  | - (void)stopCapture { | 
|  | [_capturer stopCapture]; | 
|  | } | 
|  |  | 
|  | - (void)switchCamera { | 
|  | _usingFrontCamera = !_usingFrontCamera; | 
|  | [self startCapture:nil]; | 
|  | } | 
|  |  | 
|  | - (void)switchCamera:(void (^)(NSError *))completion { | 
|  | _usingFrontCamera = !_usingFrontCamera; | 
|  | [self startCapture:completion]; | 
|  | } | 
|  |  | 
|  | #pragma mark - Private | 
|  |  | 
|  | - (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position { | 
|  | NSArray<AVCaptureDevice *> *captureDevices = | 
|  | [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices]; | 
|  | for (AVCaptureDevice *device in captureDevices) { | 
|  | if (device.position == position) { | 
|  | return device; | 
|  | } | 
|  | } | 
|  | return captureDevices[0]; | 
|  | } | 
|  |  | 
|  | - (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device { | 
|  | NSArray<AVCaptureDeviceFormat *> *formats = | 
|  | [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device]; | 
|  | int targetWidth = [_settings currentVideoResolutionWidthFromStore]; | 
|  | int targetHeight = [_settings currentVideoResolutionHeightFromStore]; | 
|  | AVCaptureDeviceFormat *selectedFormat = nil; | 
|  | int currentDiff = INT_MAX; | 
|  |  | 
|  | for (AVCaptureDeviceFormat *format in formats) { | 
|  | CMVideoDimensions dimension = | 
|  | CMVideoFormatDescriptionGetDimensions(format.formatDescription); | 
|  | FourCharCode pixelFormat = | 
|  | CMFormatDescriptionGetMediaSubType(format.formatDescription); | 
|  | int diff = abs(targetWidth - dimension.width) + | 
|  | abs(targetHeight - dimension.height); | 
|  | if (diff < currentDiff) { | 
|  | selectedFormat = format; | 
|  | currentDiff = diff; | 
|  | } else if (diff == currentDiff && | 
|  | pixelFormat == [_capturer preferredOutputPixelFormat]) { | 
|  | selectedFormat = format; | 
|  | } | 
|  | } | 
|  |  | 
|  | return selectedFormat; | 
|  | } | 
|  |  | 
|  | - (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format { | 
|  | Float64 maxSupportedFramerate = 0; | 
|  | for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) { | 
|  | maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate); | 
|  | } | 
|  | return fmin(maxSupportedFramerate, kFramerateLimit); | 
|  | } | 
|  |  | 
|  | @end |