1*d9f75844SAndroid Build Coastguard Worker/* 2*d9f75844SAndroid Build Coastguard Worker * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard Worker#import "ARDCaptureController.h" 12*d9f75844SAndroid Build Coastguard Worker 13*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/base/RTCLogging.h" 14*d9f75844SAndroid Build Coastguard Worker 15*d9f75844SAndroid Build Coastguard Worker#import "ARDSettingsModel.h" 16*d9f75844SAndroid Build Coastguard Worker 17*d9f75844SAndroid Build Coastguard Workerconst Float64 kFramerateLimit = 30.0; 18*d9f75844SAndroid Build Coastguard Worker 19*d9f75844SAndroid Build Coastguard Worker@implementation ARDCaptureController { 20*d9f75844SAndroid Build Coastguard Worker RTC_OBJC_TYPE(RTCCameraVideoCapturer) * _capturer; 21*d9f75844SAndroid Build Coastguard Worker ARDSettingsModel *_settings; 22*d9f75844SAndroid Build Coastguard Worker BOOL _usingFrontCamera; 23*d9f75844SAndroid Build Coastguard Worker} 24*d9f75844SAndroid Build Coastguard Worker 25*d9f75844SAndroid Build Coastguard Worker- (instancetype)initWithCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)capturer 26*d9f75844SAndroid Build Coastguard Worker settings:(ARDSettingsModel *)settings { 27*d9f75844SAndroid Build Coastguard Worker if (self = [super init]) { 28*d9f75844SAndroid Build Coastguard Worker _capturer = capturer; 29*d9f75844SAndroid Build Coastguard Worker _settings = settings; 30*d9f75844SAndroid Build Coastguard Worker _usingFrontCamera = YES; 31*d9f75844SAndroid Build Coastguard Worker } 32*d9f75844SAndroid Build Coastguard Worker 33*d9f75844SAndroid Build Coastguard Worker return self; 34*d9f75844SAndroid Build Coastguard Worker} 35*d9f75844SAndroid Build Coastguard Worker 36*d9f75844SAndroid Build Coastguard Worker- (void)startCapture { 37*d9f75844SAndroid Build Coastguard Worker [self startCapture:nil]; 38*d9f75844SAndroid Build Coastguard Worker} 39*d9f75844SAndroid Build Coastguard Worker 40*d9f75844SAndroid Build Coastguard Worker- (void)startCapture:(void (^)(NSError *))completion { 41*d9f75844SAndroid Build Coastguard Worker AVCaptureDevicePosition position = 42*d9f75844SAndroid Build Coastguard Worker _usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack; 43*d9f75844SAndroid Build Coastguard Worker AVCaptureDevice *device = [self findDeviceForPosition:position]; 44*d9f75844SAndroid Build Coastguard Worker AVCaptureDeviceFormat *format = [self selectFormatForDevice:device]; 45*d9f75844SAndroid Build Coastguard Worker 46*d9f75844SAndroid Build Coastguard Worker if (format == nil) { 47*d9f75844SAndroid Build Coastguard Worker RTCLogError(@"No valid formats for device %@", device); 48*d9f75844SAndroid Build Coastguard Worker NSAssert(NO, @""); 49*d9f75844SAndroid Build Coastguard Worker 50*d9f75844SAndroid Build Coastguard Worker return; 51*d9f75844SAndroid Build Coastguard Worker } 52*d9f75844SAndroid Build Coastguard Worker 53*d9f75844SAndroid Build Coastguard Worker NSInteger fps = [self selectFpsForFormat:format]; 54*d9f75844SAndroid Build Coastguard Worker 55*d9f75844SAndroid Build Coastguard Worker [_capturer startCaptureWithDevice:device format:format fps:fps completionHandler:completion]; 56*d9f75844SAndroid Build Coastguard Worker} 57*d9f75844SAndroid Build Coastguard Worker 58*d9f75844SAndroid Build Coastguard Worker- (void)stopCapture { 59*d9f75844SAndroid Build Coastguard Worker [_capturer stopCapture]; 60*d9f75844SAndroid Build Coastguard Worker} 61*d9f75844SAndroid Build Coastguard Worker 62*d9f75844SAndroid Build Coastguard Worker- (void)switchCamera { 63*d9f75844SAndroid Build Coastguard Worker _usingFrontCamera = !_usingFrontCamera; 64*d9f75844SAndroid Build Coastguard Worker [self startCapture:nil]; 65*d9f75844SAndroid Build Coastguard Worker} 66*d9f75844SAndroid Build Coastguard Worker 67*d9f75844SAndroid Build Coastguard Worker- (void)switchCamera:(void (^)(NSError *))completion { 68*d9f75844SAndroid Build Coastguard Worker _usingFrontCamera = !_usingFrontCamera; 69*d9f75844SAndroid Build Coastguard Worker [self startCapture:completion]; 70*d9f75844SAndroid Build Coastguard Worker} 71*d9f75844SAndroid Build Coastguard Worker 72*d9f75844SAndroid Build Coastguard Worker#pragma mark - Private 73*d9f75844SAndroid Build Coastguard Worker 74*d9f75844SAndroid Build Coastguard Worker- (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position { 75*d9f75844SAndroid Build Coastguard Worker NSArray<AVCaptureDevice *> *captureDevices = 76*d9f75844SAndroid Build Coastguard Worker [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices]; 77*d9f75844SAndroid Build Coastguard Worker for (AVCaptureDevice *device in captureDevices) { 78*d9f75844SAndroid Build Coastguard Worker if (device.position == position) { 79*d9f75844SAndroid Build Coastguard Worker return device; 80*d9f75844SAndroid Build Coastguard Worker } 81*d9f75844SAndroid Build Coastguard Worker } 82*d9f75844SAndroid Build Coastguard Worker return captureDevices[0]; 83*d9f75844SAndroid Build Coastguard Worker} 84*d9f75844SAndroid Build Coastguard Worker 85*d9f75844SAndroid Build Coastguard Worker- (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device { 86*d9f75844SAndroid Build Coastguard Worker NSArray<AVCaptureDeviceFormat *> *formats = 87*d9f75844SAndroid Build Coastguard Worker [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device]; 88*d9f75844SAndroid Build Coastguard Worker int targetWidth = [_settings currentVideoResolutionWidthFromStore]; 89*d9f75844SAndroid Build Coastguard Worker int targetHeight = [_settings currentVideoResolutionHeightFromStore]; 90*d9f75844SAndroid Build Coastguard Worker AVCaptureDeviceFormat *selectedFormat = nil; 91*d9f75844SAndroid Build Coastguard Worker int currentDiff = INT_MAX; 92*d9f75844SAndroid Build Coastguard Worker 93*d9f75844SAndroid Build Coastguard Worker for (AVCaptureDeviceFormat *format in formats) { 94*d9f75844SAndroid Build Coastguard Worker CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription); 95*d9f75844SAndroid Build Coastguard Worker FourCharCode pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription); 96*d9f75844SAndroid Build Coastguard Worker int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height); 97*d9f75844SAndroid Build Coastguard Worker if (diff < currentDiff) { 98*d9f75844SAndroid Build Coastguard Worker selectedFormat = format; 99*d9f75844SAndroid Build Coastguard Worker currentDiff = diff; 100*d9f75844SAndroid Build Coastguard Worker } else if (diff == currentDiff && pixelFormat == [_capturer preferredOutputPixelFormat]) { 101*d9f75844SAndroid Build Coastguard Worker selectedFormat = format; 102*d9f75844SAndroid Build Coastguard Worker } 103*d9f75844SAndroid Build Coastguard Worker } 104*d9f75844SAndroid Build Coastguard Worker 105*d9f75844SAndroid Build Coastguard Worker return selectedFormat; 106*d9f75844SAndroid Build Coastguard Worker} 107*d9f75844SAndroid Build Coastguard Worker 108*d9f75844SAndroid Build Coastguard Worker- (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format { 109*d9f75844SAndroid Build Coastguard Worker Float64 maxSupportedFramerate = 0; 110*d9f75844SAndroid Build Coastguard Worker for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) { 111*d9f75844SAndroid Build Coastguard Worker maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate); 112*d9f75844SAndroid Build Coastguard Worker } 113*d9f75844SAndroid Build Coastguard Worker return fmin(maxSupportedFramerate, kFramerateLimit); 114*d9f75844SAndroid Build Coastguard Worker} 115*d9f75844SAndroid Build Coastguard Worker 116*d9f75844SAndroid Build Coastguard Worker@end 117