xref: /aosp_15_r20/external/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1/*
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
13#import "sdk/objc/base/RTCLogging.h"
14
15#import "ARDSettingsModel.h"
16
17const Float64 kFramerateLimit = 30.0;
18
19@implementation ARDCaptureController {
20  RTC_OBJC_TYPE(RTCCameraVideoCapturer) * _capturer;
21  ARDSettingsModel *_settings;
22  BOOL _usingFrontCamera;
23}
24
25- (instancetype)initWithCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)capturer
26                        settings:(ARDSettingsModel *)settings {
27  if (self = [super init]) {
28    _capturer = capturer;
29    _settings = settings;
30    _usingFrontCamera = YES;
31  }
32
33  return self;
34}
35
36- (void)startCapture {
37  [self startCapture:nil];
38}
39
40- (void)startCapture:(void (^)(NSError *))completion {
41  AVCaptureDevicePosition position =
42      _usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
43  AVCaptureDevice *device = [self findDeviceForPosition:position];
44  AVCaptureDeviceFormat *format = [self selectFormatForDevice:device];
45
46  if (format == nil) {
47    RTCLogError(@"No valid formats for device %@", device);
48    NSAssert(NO, @"");
49
50    return;
51  }
52
53  NSInteger fps = [self selectFpsForFormat:format];
54
55  [_capturer startCaptureWithDevice:device format:format fps:fps completionHandler:completion];
56}
57
58- (void)stopCapture {
59  [_capturer stopCapture];
60}
61
62- (void)switchCamera {
63  _usingFrontCamera = !_usingFrontCamera;
64  [self startCapture:nil];
65}
66
67- (void)switchCamera:(void (^)(NSError *))completion {
68  _usingFrontCamera = !_usingFrontCamera;
69  [self startCapture:completion];
70}
71
72#pragma mark - Private
73
74- (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position {
75  NSArray<AVCaptureDevice *> *captureDevices =
76      [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices];
77  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 =
87      [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device];
88  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);
95    FourCharCode pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription);
96    int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height);
97    if (diff < currentDiff) {
98      selectedFormat = format;
99      currentDiff = diff;
100    } else if (diff == currentDiff && pixelFormat == [_capturer preferredOutputPixelFormat]) {
101      selectedFormat = format;
102    }
103  }
104
105  return selectedFormat;
106}
107
108- (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format {
109  Float64 maxSupportedFramerate = 0;
110  for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) {
111    maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate);
112  }
113  return fmin(maxSupportedFramerate, kFramerateLimit);
114}
115
116@end
117