blob: 26cce9fdaa04f2b5ed31c19c7d0cc6c2a17c7ed0 [file] [log] [blame]
sakalc522e752017-04-05 12:17:48 -07001/*
2 * Copyright 2017 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#import "ARDCaptureController.h"
12
Mirko Bonadei19640aa2020-10-19 16:12:43 +020013#import "sdk/objc/base/RTCLogging.h"
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020014
sakalc522e752017-04-05 12:17:48 -070015#import "ARDSettingsModel.h"
16
Kári Tristan Helgason293865c2018-05-30 09:59:38 +020017const Float64 kFramerateLimit = 30.0;
18
sakalc522e752017-04-05 12:17:48 -070019@implementation ARDCaptureController {
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020020 RTC_OBJC_TYPE(RTCCameraVideoCapturer) * _capturer;
sakalc522e752017-04-05 12:17:48 -070021 ARDSettingsModel *_settings;
22 BOOL _usingFrontCamera;
23}
24
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020025- (instancetype)initWithCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)capturer
sakalc522e752017-04-05 12:17:48 -070026 settings:(ARDSettingsModel *)settings {
Peter Hanspersd9b64cd2018-01-12 16:16:18 +010027 if (self = [super init]) {
sakalc522e752017-04-05 12:17:48 -070028 _capturer = capturer;
29 _settings = settings;
30 _usingFrontCamera = YES;
31 }
32
33 return self;
34}
35
36- (void)startCapture {
dharmeshf824ef82020-07-20 14:40:28 +053037 [self startCapture:nil];
38}
39
40- (void)startCapture:(void (^)(NSError *))completion {
sakalc522e752017-04-05 12:17:48 -070041 AVCaptureDevicePosition position =
42 _usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
43 AVCaptureDevice *device = [self findDeviceForPosition:position];
44 AVCaptureDeviceFormat *format = [self selectFormatForDevice:device];
Peter Hanspersd92e0b52017-10-23 14:30:25 +020045
46 if (format == nil) {
47 RTCLogError(@"No valid formats for device %@", device);
48 NSAssert(NO, @"");
49
50 return;
51 }
52
sakalea12f4c2017-05-05 00:45:30 -070053 NSInteger fps = [self selectFpsForFormat:format];
sakalc522e752017-04-05 12:17:48 -070054
dharmeshf824ef82020-07-20 14:40:28 +053055 [_capturer startCaptureWithDevice:device format:format fps:fps completionHandler:completion];
sakalc522e752017-04-05 12:17:48 -070056}
57
58- (void)stopCapture {
59 [_capturer stopCapture];
60}
61
62- (void)switchCamera {
63 _usingFrontCamera = !_usingFrontCamera;
dharmeshf824ef82020-07-20 14:40:28 +053064 [self startCapture:nil];
65}
66
67- (void)switchCamera:(void (^)(NSError *))completion {
68 _usingFrontCamera = !_usingFrontCamera;
69 [self startCapture:completion];
sakalc522e752017-04-05 12:17:48 -070070}
71
72#pragma mark - Private
73
74- (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position {
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020075 NSArray<AVCaptureDevice *> *captureDevices =
76 [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices];
sakalc522e752017-04-05 12:17:48 -070077 for (AVCaptureDevice *device in captureDevices) {
78 if (device.position == position) {
79 return device;
80 }
81 }
82 return captureDevices[0];
83}
84
85- (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device {
86 NSArray<AVCaptureDeviceFormat *> *formats =
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020087 [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device];
sakalc522e752017-04-05 12:17:48 -070088 int targetWidth = [_settings currentVideoResolutionWidthFromStore];
89 int targetHeight = [_settings currentVideoResolutionHeightFromStore];
90 AVCaptureDeviceFormat *selectedFormat = nil;
91 int currentDiff = INT_MAX;
92
93 for (AVCaptureDeviceFormat *format in formats) {
94 CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
Anders Carlsson7dad2552017-11-15 15:59:50 +010095 FourCharCode pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription);
sakalc522e752017-04-05 12:17:48 -070096 int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height);
97 if (diff < currentDiff) {
98 selectedFormat = format;
99 currentDiff = diff;
Anders Carlsson7dad2552017-11-15 15:59:50 +0100100 } else if (diff == currentDiff && pixelFormat == [_capturer preferredOutputPixelFormat]) {
101 selectedFormat = format;
sakalc522e752017-04-05 12:17:48 -0700102 }
103 }
104
sakalc522e752017-04-05 12:17:48 -0700105 return selectedFormat;
106}
107
sakalea12f4c2017-05-05 00:45:30 -0700108- (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format {
Kári Tristan Helgason293865c2018-05-30 09:59:38 +0200109 Float64 maxSupportedFramerate = 0;
sakalc522e752017-04-05 12:17:48 -0700110 for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) {
Kári Tristan Helgason293865c2018-05-30 09:59:38 +0200111 maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate);
sakalc522e752017-04-05 12:17:48 -0700112 }
Kári Tristan Helgason293865c2018-05-30 09:59:38 +0200113 return fmin(maxSupportedFramerate, kFramerateLimit);
sakalc522e752017-04-05 12:17:48 -0700114}
115
116@end