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