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 <WebRTC/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 AVCaptureDevicePosition position = 38 _usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack; 39 AVCaptureDevice *device = [self findDeviceForPosition:position]; 40 AVCaptureDeviceFormat *format = [self selectFormatForDevice:device]; 41 42 if (format == nil) { 43 RTCLogError(@"No valid formats for device %@", device); 44 NSAssert(NO, @""); 45 46 return; 47 } 48 49 NSInteger fps = [self selectFpsForFormat:format]; 50 51 [_capturer startCaptureWithDevice:device format:format fps:fps]; 52} 53 54- (void)stopCapture { 55 [_capturer stopCapture]; 56} 57 58- (void)switchCamera { 59 _usingFrontCamera = !_usingFrontCamera; 60 [self startCapture]; 61} 62 63#pragma mark - Private 64 65- (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position { 66 NSArray<AVCaptureDevice *> *captureDevices = 67 [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices]; 68 for (AVCaptureDevice *device in captureDevices) { 69 if (device.position == position) { 70 return device; 71 } 72 } 73 return captureDevices[0]; 74} 75 76- (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device { 77 NSArray<AVCaptureDeviceFormat *> *formats = 78 [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device]; 79 int targetWidth = [_settings currentVideoResolutionWidthFromStore]; 80 int targetHeight = [_settings currentVideoResolutionHeightFromStore]; 81 AVCaptureDeviceFormat *selectedFormat = nil; 82 int currentDiff = INT_MAX; 83 84 for (AVCaptureDeviceFormat *format in formats) { 85 CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription); 86 FourCharCode pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription); 87 int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height); 88 if (diff < currentDiff) { 89 selectedFormat = format; 90 currentDiff = diff; 91 } else if (diff == currentDiff && pixelFormat == [_capturer preferredOutputPixelFormat]) { 92 selectedFormat = format; 93 } 94 } 95 96 return selectedFormat; 97} 98 99- (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format { 100 Float64 maxSupportedFramerate = 0; 101 for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) { 102 maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate); 103 } 104 return fmin(maxSupportedFramerate, kFramerateLimit); 105} 106 107@end 108