Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 #endif | 23 #endif |
| 24 | 24 |
| 25 #include "libyuv/rotate.h" | 25 #include "libyuv/rotate.h" |
| 26 | 26 |
| 27 #include "webrtc/base/bind.h" | 27 #include "webrtc/base/bind.h" |
| 28 #include "webrtc/base/checks.h" | 28 #include "webrtc/base/checks.h" |
| 29 #include "webrtc/base/thread.h" | 29 #include "webrtc/base/thread.h" |
| 30 #include "webrtc/common_video/include/corevideo_frame_buffer.h" | 30 #include "webrtc/common_video/include/corevideo_frame_buffer.h" |
| 31 #include "webrtc/common_video/rotation.h" | 31 #include "webrtc/common_video/rotation.h" |
| 32 | 32 |
| 33 struct AVCaptureSessionPresetResolution { | 33 // TODO(denicija): add support for higher frame rates. |
| 34 NSString *sessionPreset; | 34 // See http://crbug/webrtc/6355 for more info. |
| 35 int width; | 35 static const int kFramesPerSecond = 30; |
| 36 int height; | |
| 37 }; | |
| 38 | 36 |
| 39 #if TARGET_OS_IPHONE | 37 static inline BOOL IsMediaSubTypeSupported(FourCharCode mediaSubType) { |
|
tkchin_webrtc
2016/10/05 17:33:12
odd to have so many static fns as opposed to havin
| |
| 40 static const AVCaptureSessionPresetResolution kAvailablePresets[] = { | 38 return (mediaSubType == kCVPixelFormatType_420YpCbCr8PlanarFullRange || |
| 41 { AVCaptureSessionPreset352x288, 352, 288}, | 39 mediaSubType == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange); |
| 42 { AVCaptureSessionPreset640x480, 640, 480}, | 40 } |
| 43 { AVCaptureSessionPreset1280x720, 1280, 720}, | |
| 44 { AVCaptureSessionPreset1920x1080, 1920, 1080}, | |
| 45 }; | |
| 46 #else // macOS | |
| 47 static const AVCaptureSessionPresetResolution kAvailablePresets[] = { | |
| 48 { AVCaptureSessionPreset320x240, 320, 240}, | |
| 49 { AVCaptureSessionPreset352x288, 352, 288}, | |
| 50 { AVCaptureSessionPreset640x480, 640, 480}, | |
| 51 { AVCaptureSessionPreset960x540, 960, 540}, | |
| 52 { AVCaptureSessionPreset1280x720, 1280, 720}, | |
| 53 }; | |
| 54 #endif | |
| 55 | 41 |
| 56 // Mapping from cricket::VideoFormat to AVCaptureSession presets. | 42 static inline BOOL IsFrameRateWithinRange(int fps, AVFrameRateRange* range) { |
|
tkchin_webrtc
2016/10/05 17:33:12
nit: *range
daniela-webrtc
2016/10/06 08:40:03
Done.
| |
| 57 static NSString *GetSessionPresetForVideoFormat( | 43 return range.minFrameRate <= fps && range.maxFrameRate >= fps; |
| 58 const cricket::VideoFormat& format) { | 44 } |
| 59 for (const auto preset : kAvailablePresets) { | 45 |
| 60 // Check both orientations | 46 // Returns filtered array of device formats based on predefined constraints our |
| 61 if ((format.width == preset.width && format.height == preset.height) || | 47 // stack imposes. |
| 62 (format.width == preset.height && format.height == preset.width)) { | 48 static NSArray<AVCaptureDeviceFormat *> *GetEligibleDeviceFormats( |
| 63 return preset.sessionPreset; | 49 const AVCaptureDevice *device, |
| 50 int supportedFps) { | |
| 51 NSMutableArray<AVCaptureDeviceFormat *> *eligibleDeviceFormats = | |
| 52 [NSMutableArray array]; | |
| 53 | |
| 54 for (AVCaptureDeviceFormat *format in device.formats) { | |
| 55 // Filter out subTypes that we currently don't support in the stack | |
| 56 FourCharCode mediaSubType = | |
| 57 CMFormatDescriptionGetMediaSubType(format.formatDescription); | |
| 58 if (!IsMediaSubTypeSupported(mediaSubType)) { | |
| 59 continue; | |
| 60 } | |
| 61 | |
| 62 // Filter out frame rate ranges that we currently don't support in the stack | |
| 63 for (AVFrameRateRange *frameRateRange in format | |
| 64 .videoSupportedFrameRateRanges) { | |
|
tkchin_webrtc
2016/10/05 17:33:12
nit: don't split properties across lines
if it doe
daniela-webrtc
2016/10/06 08:40:03
Done.
| |
| 65 if (IsFrameRateWithinRange(supportedFps, frameRateRange)) { | |
| 66 [eligibleDeviceFormats addObject:format]; | |
| 67 break; | |
| 68 } | |
| 64 } | 69 } |
| 65 } | 70 } |
| 66 // If no matching preset is found, use a default one. | 71 |
| 67 return AVCaptureSessionPreset640x480; | 72 return [eligibleDeviceFormats copy]; |
|
tkchin_webrtc
2016/10/05 17:33:12
safety is fine, but probably not needed. fine to l
| |
| 73 } | |
| 74 | |
| 75 // Mapping from cricket::VideoFormat to AVCaptureDeviceFormat. | |
| 76 static AVCaptureDeviceFormat *GetDeviceFormatForVideoFormat( | |
| 77 const AVCaptureDevice *device, | |
| 78 const cricket::VideoFormat& videoFormat) { | |
|
tkchin_webrtc
2016/10/05 17:33:12
be consistent in where you place & and *
ObjC conv
daniela-webrtc
2016/10/06 08:40:03
Done.
| |
| 79 AVCaptureDeviceFormat *desiredDeviceFormat = nil; | |
| 80 NSArray<AVCaptureDeviceFormat *>* eligibleFormats = | |
|
tkchin_webrtc
2016/10/05 17:33:12
nit: *eligibleFormats
daniela-webrtc
2016/10/06 08:40:03
Done.
| |
| 81 GetEligibleDeviceFormats(device, videoFormat.framerate()); | |
| 82 | |
| 83 for (AVCaptureDeviceFormat *deviceFormat in eligibleFormats) { | |
| 84 CMVideoDimensions dimension = | |
| 85 CMVideoFormatDescriptionGetDimensions(deviceFormat.formatDescription); | |
| 86 FourCharCode mediaSubType = | |
| 87 CMFormatDescriptionGetMediaSubType(deviceFormat.formatDescription); | |
| 88 | |
| 89 if (videoFormat.width == dimension.width && | |
| 90 videoFormat.height == dimension.height) { | |
| 91 if (mediaSubType == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { | |
| 92 // This is the preferred format so no need to wait for better option. | |
| 93 return deviceFormat; | |
| 94 } else { | |
| 95 // This is good candidate, but let's wait for something better. | |
| 96 desiredDeviceFormat = deviceFormat; | |
| 97 } | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 return desiredDeviceFormat; | |
| 102 } | |
| 103 | |
| 104 // Mapping from AVCaptureDeviceFormat to cricket::VideoFormat for given input | |
| 105 // device. | |
| 106 static std::set<cricket::VideoFormat> GetSupportedVideoFormatsForDevice( | |
| 107 AVCaptureDevice *device) { | |
| 108 std::set<cricket::VideoFormat> supportedFormats; | |
| 109 | |
| 110 NSArray<AVCaptureDeviceFormat *> *eligibleFormats = | |
| 111 GetEligibleDeviceFormats(device, kFramesPerSecond); | |
| 112 | |
| 113 for (AVCaptureDeviceFormat *deviceFormat in eligibleFormats) { | |
| 114 CMVideoDimensions dimension = | |
| 115 CMVideoFormatDescriptionGetDimensions(deviceFormat.formatDescription); | |
| 116 cricket::VideoFormat format = cricket::VideoFormat( | |
| 117 dimension.width, dimension.height, | |
| 118 cricket::VideoFormat::FpsToInterval(kFramesPerSecond), | |
| 119 cricket::FOURCC_NV12); | |
| 120 supportedFormats.insert(format); | |
| 121 } | |
| 122 | |
| 123 return supportedFormats; | |
| 124 } | |
| 125 | |
| 126 // Sets device format for the provided capture device. Returns YES/NO depending on success. | |
| 127 // TODO(denicija): When this file is split this static method should be reconsid ered. | |
| 128 // Perhaps adding a category on AVCaptureDevice would be better. | |
| 129 static BOOL SetFormatForCaptureDevice(AVCaptureDevice* device, | |
|
tkchin_webrtc
2016/10/05 17:33:12
ditto * placement throughout the fn
daniela-webrtc
2016/10/06 08:40:03
Done.
| |
| 130 AVCaptureSession* session, | |
| 131 const cricket::VideoFormat& format) { | |
| 132 | |
|
tkchin_webrtc
2016/10/05 17:33:12
nit: remove blank line
| |
| 133 AVCaptureDeviceFormat* deviceFormat = | |
| 134 GetDeviceFormatForVideoFormat(device, format); | |
| 135 const int fps = cricket::VideoFormat::IntervalToFps(format.interval); | |
| 136 | |
| 137 NSError* error = nil; | |
| 138 BOOL success = YES; | |
|
tkchin_webrtc
2016/10/05 17:33:11
nit: set this to NO and modify it to YES to save o
daniela-webrtc
2016/10/06 08:40:03
Since there are different code paths that can caus
| |
| 139 [session beginConfiguration]; | |
| 140 if ([device lockForConfiguration:&error]) { | |
| 141 @try { | |
| 142 device.activeFormat = deviceFormat; | |
| 143 device.activeVideoMinFrameDuration = CMTimeMake(1, fps); | |
| 144 } @catch (NSException* exception) { | |
| 145 RTCLogError( | |
| 146 @"Exception occured while setting active format!\n User info:%@", | |
|
tkchin_webrtc
2016/10/05 17:33:12
nit: make the errors as short as possible
e.g. Fai
daniela-webrtc
2016/10/06 08:40:03
Done.
| |
| 147 exception.userInfo); | |
| 148 success = NO; | |
| 149 } | |
| 150 | |
| 151 [device unlockForConfiguration]; | |
| 152 } else { | |
| 153 RTCLogError( | |
| 154 @"Error occured while locking device %@. Underlying error: %@", | |
| 155 device, error.userInfo); | |
| 156 success = NO; | |
| 157 } | |
| 158 [session commitConfiguration]; | |
| 159 | |
| 160 return success; | |
| 68 } | 161 } |
| 69 | 162 |
| 70 // This class used to capture frames using AVFoundation APIs on iOS. It is meant | 163 // This class used to capture frames using AVFoundation APIs on iOS. It is meant |
| 71 // to be owned by an instance of AVFoundationVideoCapturer. The reason for this | 164 // to be owned by an instance of AVFoundationVideoCapturer. The reason for this |
| 72 // because other webrtc objects own cricket::VideoCapturer, which is not | 165 // because other webrtc objects own cricket::VideoCapturer, which is not |
| 73 // ref counted. To prevent bad behavior we do not expose this class directly. | 166 // ref counted. To prevent bad behavior we do not expose this class directly. |
| 74 @interface RTCAVFoundationVideoCapturerInternal : NSObject | 167 @interface RTCAVFoundationVideoCapturerInternal : NSObject |
| 75 <AVCaptureVideoDataOutputSampleBufferDelegate> | 168 <AVCaptureVideoDataOutputSampleBufferDelegate> |
| 76 | 169 |
| 77 @property(nonatomic, readonly) AVCaptureSession *captureSession; | 170 @property(nonatomic, readonly) AVCaptureSession *captureSession; |
| 78 @property(nonatomic, readonly) dispatch_queue_t frameQueue; | 171 @property(nonatomic, readonly) dispatch_queue_t frameQueue; |
| 79 @property(nonatomic, readonly) BOOL canUseBackCamera; | 172 @property(nonatomic, readonly) BOOL canUseBackCamera; |
| 80 @property(nonatomic, assign) BOOL useBackCamera; // Defaults to NO. | 173 @property(nonatomic, assign) BOOL useBackCamera; // Defaults to NO. |
| 81 @property(nonatomic, assign) BOOL isRunning; // Whether the capture session is running. | 174 @property(nonatomic, assign) BOOL isRunning; // Whether the capture session is running. |
| 82 @property(atomic, assign) BOOL hasStarted; // Whether we have an unmatched star t. | 175 @property(atomic, assign) BOOL hasStarted; // Whether we have an unmatched star t. |
| 83 | 176 |
| 84 // We keep a pointer back to AVFoundationVideoCapturer to make callbacks on it | 177 // We keep a pointer back to AVFoundationVideoCapturer to make callbacks on it |
| 85 // when we receive frames. This is safe because this object should be owned by | 178 // when we receive frames. This is safe because this object should be owned by |
| 86 // it. | 179 // it. |
| 87 - (instancetype)initWithCapturer:(webrtc::AVFoundationVideoCapturer *)capturer; | 180 - (instancetype)initWithCapturer:(webrtc::AVFoundationVideoCapturer *)capturer; |
| 88 - (AVCaptureDevice *)getActiveCaptureDevice; | 181 - (AVCaptureDevice *)getActiveCaptureDevice; |
|
tkchin_webrtc
2016/10/05 17:33:11
I don't recall this bit of code. We don't prefix a
daniela-webrtc
2016/10/06 08:40:03
I noticed that as well, so that's why I renamed th
| |
| 89 | 182 |
| 183 - (nullable AVCaptureDevice *)frontCaptureDevice; | |
|
tkchin_webrtc
2016/10/05 17:33:12
I'm surprised this isn't throwing warnings at you
| |
| 184 - (nullable AVCaptureDevice *)backCaptureDevice; | |
| 185 | |
| 90 // Starts and stops the capture session asynchronously. We cannot do this | 186 // Starts and stops the capture session asynchronously. We cannot do this |
| 91 // synchronously without blocking a WebRTC thread. | 187 // synchronously without blocking a WebRTC thread. |
| 92 - (void)start; | 188 - (void)start; |
| 93 - (void)stop; | 189 - (void)stop; |
| 94 | 190 |
| 95 @end | 191 @end |
| 96 | 192 |
| 97 @implementation RTCAVFoundationVideoCapturerInternal { | 193 @implementation RTCAVFoundationVideoCapturerInternal { |
| 98 // Keep pointers to inputs for convenience. | 194 // Keep pointers to inputs for convenience. |
| 99 AVCaptureDeviceInput *_frontCameraInput; | 195 AVCaptureDeviceInput *_frontCameraInput; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 } | 264 } |
| 169 | 265 |
| 170 - (AVCaptureSession *)captureSession { | 266 - (AVCaptureSession *)captureSession { |
| 171 return _captureSession; | 267 return _captureSession; |
| 172 } | 268 } |
| 173 | 269 |
| 174 - (AVCaptureDevice *)getActiveCaptureDevice { | 270 - (AVCaptureDevice *)getActiveCaptureDevice { |
| 175 return self.useBackCamera ? _backCameraInput.device : _frontCameraInput.device ; | 271 return self.useBackCamera ? _backCameraInput.device : _frontCameraInput.device ; |
| 176 } | 272 } |
| 177 | 273 |
| 274 - (AVCaptureDevice *)frontCaptureDevice { | |
| 275 return _frontCameraInput.device; | |
| 276 } | |
| 277 | |
| 278 - (AVCaptureDevice *)backCaptureDevice { | |
| 279 return _backCameraInput.device; | |
| 280 } | |
| 281 | |
| 178 - (dispatch_queue_t)frameQueue { | 282 - (dispatch_queue_t)frameQueue { |
| 179 if (!_frameQueue) { | 283 if (!_frameQueue) { |
| 180 _frameQueue = | 284 _frameQueue = |
| 181 dispatch_queue_create("org.webrtc.avfoundationvideocapturer.video", | 285 dispatch_queue_create("org.webrtc.avfoundationvideocapturer.video", |
| 182 DISPATCH_QUEUE_SERIAL); | 286 DISPATCH_QUEUE_SERIAL); |
| 183 dispatch_set_target_queue( | 287 dispatch_set_target_queue( |
| 184 _frameQueue, | 288 _frameQueue, |
| 185 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)); | 289 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)); |
| 186 } | 290 } |
| 187 return _frameQueue; | 291 return _frameQueue; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 | 323 |
| 220 - (BOOL)isRunning { | 324 - (BOOL)isRunning { |
| 221 rtc::CritScope cs(&_crit); | 325 rtc::CritScope cs(&_crit); |
| 222 return _isRunning; | 326 return _isRunning; |
| 223 } | 327 } |
| 224 | 328 |
| 225 - (void)setIsRunning:(BOOL)isRunning { | 329 - (void)setIsRunning:(BOOL)isRunning { |
| 226 rtc::CritScope cs(&_crit); | 330 rtc::CritScope cs(&_crit); |
| 227 _isRunning = isRunning; | 331 _isRunning = isRunning; |
| 228 } | 332 } |
| 229 | 333 |
|
daniela-webrtc
2016/10/06 08:40:03
This is from the rebase
| |
| 230 // Called from WebRTC thread. | 334 // Called from WebRTC thread. |
| 231 - (void)start { | 335 - (void)start { |
| 232 if (self.hasStarted) { | 336 if (self.hasStarted) { |
| 233 return; | 337 return; |
| 234 } | 338 } |
| 235 self.hasStarted = YES; | 339 self.hasStarted = YES; |
| 236 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession | 340 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession |
| 237 block:^{ | 341 block:^{ |
| 238 #if TARGET_OS_IPHONE | 342 #if TARGET_OS_IPHONE |
| 239 // Default to portrait orientation on iPhone. This will be reset in | 343 // Default to portrait orientation on iPhone. This will be reset in |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 519 if (!backCameraInput) { | 623 if (!backCameraInput) { |
| 520 RTCLogError(@"Failed to create front camera input: %@", | 624 RTCLogError(@"Failed to create front camera input: %@", |
| 521 error.localizedDescription); | 625 error.localizedDescription); |
| 522 return nil; | 626 return nil; |
| 523 } | 627 } |
| 524 _backCameraInput = backCameraInput; | 628 _backCameraInput = backCameraInput; |
| 525 } | 629 } |
| 526 return _backCameraInput; | 630 return _backCameraInput; |
| 527 } | 631 } |
| 528 | 632 |
| 529 - (void)setMinFrameDuration:(CMTime)minFrameDuration | |
| 530 forDevice:(AVCaptureDevice *)device { | |
| 531 NSError *error = nil; | |
| 532 if (![device lockForConfiguration:&error]) { | |
| 533 RTCLogError(@"Failed to lock device for configuration. Error: %@", error.loc alizedDescription); | |
| 534 return; | |
| 535 } | |
| 536 device.activeVideoMinFrameDuration = minFrameDuration; | |
| 537 [device unlockForConfiguration]; | |
| 538 } | |
| 539 | |
| 540 // Called from capture session queue. | 633 // Called from capture session queue. |
| 541 - (void)updateOrientation { | 634 - (void)updateOrientation { |
| 542 #if TARGET_OS_IPHONE | 635 #if TARGET_OS_IPHONE |
| 543 switch ([UIDevice currentDevice].orientation) { | 636 switch ([UIDevice currentDevice].orientation) { |
| 544 case UIDeviceOrientationPortrait: | 637 case UIDeviceOrientationPortrait: |
| 545 _rotation = webrtc::kVideoRotation_90; | 638 _rotation = webrtc::kVideoRotation_90; |
| 546 break; | 639 break; |
| 547 case UIDeviceOrientationPortraitUpsideDown: | 640 case UIDeviceOrientationPortraitUpsideDown: |
| 548 _rotation = webrtc::kVideoRotation_270; | 641 _rotation = webrtc::kVideoRotation_270; |
| 549 break; | 642 break; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 574 newInput = _backCameraInput; | 667 newInput = _backCameraInput; |
| 575 } | 668 } |
| 576 if (oldInput) { | 669 if (oldInput) { |
| 577 // Ok to remove this even if it's not attached. Will be no-op. | 670 // Ok to remove this even if it's not attached. Will be no-op. |
| 578 [_captureSession removeInput:oldInput]; | 671 [_captureSession removeInput:oldInput]; |
| 579 } | 672 } |
| 580 if (newInput) { | 673 if (newInput) { |
| 581 [_captureSession addInput:newInput]; | 674 [_captureSession addInput:newInput]; |
| 582 } | 675 } |
| 583 [self updateOrientation]; | 676 [self updateOrientation]; |
| 677 AVCaptureDevice *newDevice = newInput.device; | |
| 678 const cricket::VideoFormat* format = _capturer->GetCaptureFormat(); | |
|
tkchin_webrtc
2016/10/05 17:33:12
*format
| |
| 679 SetFormatForCaptureDevice(newDevice, _captureSession, *format); | |
| 584 [_captureSession commitConfiguration]; | 680 [_captureSession commitConfiguration]; |
| 585 | |
| 586 const auto fps = cricket::VideoFormat::IntervalToFps(_capturer->GetCaptureFo rmat()->interval); | |
| 587 [self setMinFrameDuration:CMTimeMake(1, fps)forDevice:newInput.device]; | |
| 588 }]; | 681 }]; |
| 589 } | 682 } |
| 590 | 683 |
| 591 @end | 684 @end |
| 592 | 685 |
| 593 namespace webrtc { | 686 namespace webrtc { |
| 594 | 687 |
| 595 enum AVFoundationVideoCapturerMessageType : uint32_t { | 688 enum AVFoundationVideoCapturerMessageType : uint32_t { |
| 596 kMessageTypeFrame, | 689 kMessageTypeFrame, |
| 597 }; | 690 }; |
| 598 | 691 |
| 599 AVFoundationVideoCapturer::AVFoundationVideoCapturer() : _capturer(nil) { | 692 AVFoundationVideoCapturer::AVFoundationVideoCapturer() : _capturer(nil) { |
| 600 // Set our supported formats. This matches kAvailablePresets. | |
| 601 _capturer = | 693 _capturer = |
| 602 [[RTCAVFoundationVideoCapturerInternal alloc] initWithCapturer:this]; | 694 [[RTCAVFoundationVideoCapturerInternal alloc] initWithCapturer:this]; |
| 603 | 695 |
| 604 std::vector<cricket::VideoFormat> supported_formats; | 696 std::set<cricket::VideoFormat> front_camera_video_formats = |
| 605 int framerate = 30; | 697 GetSupportedVideoFormatsForDevice([_capturer frontCaptureDevice]); |
| 606 | 698 |
| 607 #if TARGET_OS_IPHONE | 699 std::set<cricket::VideoFormat> back_camera_video_formats = |
| 608 if ([UIDevice deviceType] == RTCDeviceTypeIPhone4S) { | 700 GetSupportedVideoFormatsForDevice([_capturer backCaptureDevice]); |
| 609 set_enable_video_adapter(false); | 701 |
| 610 framerate = 15; | 702 std::vector<cricket::VideoFormat> intersection_video_formats; |
| 703 if (back_camera_video_formats.empty()) { | |
| 704 intersection_video_formats.assign(front_camera_video_formats.begin(), | |
| 705 front_camera_video_formats.end()); | |
| 706 | |
| 707 } else if (front_camera_video_formats.empty()) { | |
| 708 intersection_video_formats.assign(back_camera_video_formats.begin(), | |
| 709 back_camera_video_formats.end()); | |
| 710 } else { | |
| 711 std::set_intersection( | |
|
magjed_webrtc
2016/10/04 13:21:25
nit: At least according to C++ style you should ei
| |
| 712 front_camera_video_formats.begin(), front_camera_video _formats.end(), | |
| 713 back_camera_video_formats.begin(), back_camera_video_f ormats.end(), | |
| 714 std::back_inserter(intersection_video_formats)); | |
| 611 } | 715 } |
| 612 #endif | 716 SetSupportedFormats(intersection_video_formats); |
| 613 | |
| 614 for (const auto preset : kAvailablePresets) { | |
| 615 if ([_capturer.captureSession canSetSessionPreset:preset.sessionPreset]) { | |
| 616 const auto format = cricket::VideoFormat( | |
| 617 preset.width, | |
| 618 preset.height, | |
| 619 cricket::VideoFormat::FpsToInterval(framerate), | |
| 620 cricket::FOURCC_NV12); | |
| 621 supported_formats.push_back(format); | |
| 622 } | |
| 623 } | |
| 624 | |
| 625 SetSupportedFormats(supported_formats); | |
| 626 } | 717 } |
| 627 | 718 |
| 628 AVFoundationVideoCapturer::~AVFoundationVideoCapturer() { | 719 AVFoundationVideoCapturer::~AVFoundationVideoCapturer() { |
| 629 _capturer = nil; | 720 _capturer = nil; |
| 630 } | 721 } |
| 631 | 722 |
| 632 cricket::CaptureState AVFoundationVideoCapturer::Start( | 723 cricket::CaptureState AVFoundationVideoCapturer::Start( |
| 633 const cricket::VideoFormat& format) { | 724 const cricket::VideoFormat& format) { |
| 634 if (!_capturer) { | 725 if (!_capturer) { |
| 635 LOG(LS_ERROR) << "Failed to create AVFoundation capturer."; | 726 LOG(LS_ERROR) << "Failed to create AVFoundation capturer."; |
| 636 return cricket::CaptureState::CS_FAILED; | 727 return cricket::CaptureState::CS_FAILED; |
| 637 } | 728 } |
| 638 if (_capturer.isRunning) { | 729 if (_capturer.isRunning) { |
| 639 LOG(LS_ERROR) << "The capturer is already running."; | 730 LOG(LS_ERROR) << "The capturer is already running."; |
| 640 return cricket::CaptureState::CS_FAILED; | 731 return cricket::CaptureState::CS_FAILED; |
| 641 } | 732 } |
| 642 | 733 |
| 643 NSString *desiredPreset = GetSessionPresetForVideoFormat(format); | 734 AVCaptureDevice* device = [_capturer getActiveCaptureDevice]; |
| 644 RTC_DCHECK(desiredPreset); | 735 AVCaptureSession* session = _capturer.captureSession; |
| 645 | 736 |
| 646 [_capturer.captureSession beginConfiguration]; | 737 if (!SetFormatForCaptureDevice(device, session, format)) { |
| 647 if (![_capturer.captureSession canSetSessionPreset:desiredPreset]) { | |
| 648 LOG(LS_ERROR) << "Unsupported video format."; | |
| 649 [_capturer.captureSession commitConfiguration]; | |
| 650 return cricket::CaptureState::CS_FAILED; | 738 return cricket::CaptureState::CS_FAILED; |
| 651 } | 739 } |
| 652 _capturer.captureSession.sessionPreset = desiredPreset; | |
| 653 [_capturer.captureSession commitConfiguration]; | |
| 654 | 740 |
| 655 SetCaptureFormat(&format); | 741 SetCaptureFormat(&format); |
| 656 // This isn't super accurate because it takes a while for the AVCaptureSession | 742 // This isn't super accurate because it takes a while for the AVCaptureSession |
| 657 // to spin up, and this call returns async. | 743 // to spin up, and this call returns async. |
| 658 // TODO(tkchin): make this better. | 744 // TODO(tkchin): make this better. |
| 659 [_capturer start]; | 745 [_capturer start]; |
| 660 SetCaptureState(cricket::CaptureState::CS_RUNNING); | 746 SetCaptureState(cricket::CaptureState::CS_RUNNING); |
| 661 | 747 |
| 662 // Adjust the framerate for all capture devices. | |
| 663 const auto fps = cricket::VideoFormat::IntervalToFps(format.interval); | |
| 664 AVCaptureDevice *activeDevice = [_capturer getActiveCaptureDevice]; | |
| 665 [_capturer setMinFrameDuration:CMTimeMake(1, fps)forDevice:activeDevice]; | |
| 666 | |
| 667 return cricket::CaptureState::CS_STARTING; | 748 return cricket::CaptureState::CS_STARTING; |
| 668 } | 749 } |
| 669 | 750 |
| 670 void AVFoundationVideoCapturer::Stop() { | 751 void AVFoundationVideoCapturer::Stop() { |
| 671 [_capturer stop]; | 752 [_capturer stop]; |
| 672 SetCaptureFormat(NULL); | 753 SetCaptureFormat(NULL); |
| 673 } | 754 } |
| 674 | 755 |
| 675 bool AVFoundationVideoCapturer::IsRunning() { | 756 bool AVFoundationVideoCapturer::IsRunning() { |
| 676 return _capturer.isRunning; | 757 return _capturer.isRunning; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 buffer = rotated_buffer; | 837 buffer = rotated_buffer; |
| 757 } | 838 } |
| 758 } | 839 } |
| 759 | 840 |
| 760 OnFrame(cricket::WebRtcVideoFrame(buffer, rotation, | 841 OnFrame(cricket::WebRtcVideoFrame(buffer, rotation, |
| 761 translated_camera_time_us, 0), | 842 translated_camera_time_us, 0), |
| 762 captured_width, captured_height); | 843 captured_width, captured_height); |
| 763 } | 844 } |
| 764 | 845 |
| 765 } // namespace webrtc | 846 } // namespace webrtc |
| OLD | NEW |