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 // Maping from cricket::VideoFormat to AVCaptureDeviceFormat. |
|
kthelgason
2016/09/20 07:00:30
nit: mapping
| |
| 34 NSString *sessionPreset; | 34 static AVCaptureDeviceFormat *GetDeviceFormatForVideoFormat(const AVCaptureDevic e *device, |
| 35 int width; | 35 const cricket::Video Format& videoFormat) { |
| 36 int height; | |
| 37 }; | |
| 38 | 36 |
| 39 #if TARGET_OS_IPHONE | 37 AVCaptureDeviceFormat *desiredDeviceFormat = nil; |
| 40 static const AVCaptureSessionPresetResolution kAvailablePresets[] = { | 38 for (AVCaptureDeviceFormat *deviceFormat in [device formats]) { |
| 41 { AVCaptureSessionPreset352x288, 352, 288}, | 39 CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions([deviceF ormat formatDescription]); |
| 42 { AVCaptureSessionPreset640x480, 640, 480}, | 40 FourCharCode code = CMFormatDescriptionGetMediaSubType([deviceFormat formatD escription]); |
| 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 if (code != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange && |
| 57 static NSString *GetSessionPresetForVideoFormat( | 43 code !=kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) { |
| 58 const cricket::VideoFormat& format) { | 44 continue; |
| 59 for (const auto preset : kAvailablePresets) { | 45 } |
| 60 // Check both orientations | 46 |
| 61 if ((format.width == preset.width && format.height == preset.height) || | 47 if (videoFormat.width == dimension.width && videoFormat.height == dimension. height) { |
|
magjed_webrtc
2016/09/20 08:42:18
Shouldn't we also look at fps? Maybe it would be b
daniela-webrtc
2016/09/26 11:03:15
Acknowledged.
| |
| 62 (format.width == preset.height && format.height == preset.width)) { | 48 if (code == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { |
| 63 return preset.sessionPreset; | 49 //this is the preferred format so no need to wait for better option |
| 50 return deviceFormat; | |
| 51 } else { | |
| 52 //this is good candidate, but let's wait for something better | |
| 53 desiredDeviceFormat = deviceFormat; | |
| 54 } | |
| 64 } | 55 } |
| 65 } | 56 } |
| 66 // If no matching preset is found, use a default one. | 57 return desiredDeviceFormat; |
| 67 return AVCaptureSessionPreset640x480; | 58 } |
| 59 | |
| 60 // Mapping from AVCaptureDeviceFormat to cricket::VideoFormat for given input de vice. | |
| 61 static std::vector<cricket::VideoFormat> GetSupportedVideoFormatsForDevice(AVCap tureDevice *device) { | |
| 62 std::vector<cricket::VideoFormat> supportedFormats; | |
| 63 | |
| 64 for (AVCaptureDeviceFormat *deviceFormat in [device formats]) { | |
| 65 FourCharCode code = CMFormatDescriptionGetMediaSubType([deviceFormat formatD escription]); | |
| 66 | |
| 67 if (code != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange && | |
| 68 code !=kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) { | |
|
kthelgason
2016/09/20 07:00:30
nit: missing space
daniela-webrtc
2016/09/23 08:49:17
Acknowledged.
| |
| 69 continue; | |
| 70 } | |
| 71 | |
| 72 CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions([deviceF ormat formatDescription]); | |
| 73 | |
| 74 for (AVFrameRateRange* frameRate in [deviceFormat videoSupportedFrameRateRan ges]) { | |
| 75 Float64 fps = frameRate.maxFrameRate; | |
|
kthelgason
2016/09/20 07:00:30
is there a need to introduce this variable?
daniela-webrtc
2016/09/26 11:03:15
Acknowledged.
| |
| 76 int64_t interval = cricket::VideoFormat::FpsToInterval(fps); | |
| 77 cricket::VideoFormat format = cricket::VideoFormat(dimension.width, | |
| 78 dimension.height, | |
| 79 interval, | |
| 80 cricket::FOURCC_NV12); | |
| 81 | |
| 82 std::vector<cricket::VideoFormat>::iterator iterator = std::find(supported Formats.begin(), | |
|
kthelgason
2016/09/20 07:00:30
I'd go for auto here, this type is very unwieldy.
daniela-webrtc
2016/09/23 08:49:17
This will no longer be needed once I implement the
| |
| 83 supported Formats.end(), | |
| 84 format); | |
| 85 if (iterator != supportedFormats.end()) { | |
| 86 continue; | |
| 87 } else { | |
| 88 supportedFormats.push_back(format); | |
| 89 } | |
| 90 } | |
|
kthelgason
2016/09/20 07:00:30
We might be better off just using a std::set for s
magjed_webrtc
2016/09/20 08:42:18
+1 Go with a std::set, it should simplify the code
daniela-webrtc
2016/09/23 08:49:17
Acknowledged.
| |
| 91 } | |
| 92 return supportedFormats; | |
| 68 } | 93 } |
| 69 | 94 |
| 70 // This class used to capture frames using AVFoundation APIs on iOS. It is meant | 95 // 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 | 96 // to be owned by an instance of AVFoundationVideoCapturer. The reason for this |
| 72 // because other webrtc objects own cricket::VideoCapturer, which is not | 97 // because other webrtc objects own cricket::VideoCapturer, which is not |
| 73 // ref counted. To prevent bad behavior we do not expose this class directly. | 98 // ref counted. To prevent bad behavior we do not expose this class directly. |
| 74 @interface RTCAVFoundationVideoCapturerInternal : NSObject | 99 @interface RTCAVFoundationVideoCapturerInternal : NSObject |
| 75 <AVCaptureVideoDataOutputSampleBufferDelegate> | 100 <AVCaptureVideoDataOutputSampleBufferDelegate> |
| 76 | 101 |
| 77 @property(nonatomic, readonly) AVCaptureSession *captureSession; | 102 @property(nonatomic, readonly) AVCaptureSession *captureSession; |
| 78 @property(nonatomic, readonly) dispatch_queue_t frameQueue; | 103 @property(nonatomic, readonly) dispatch_queue_t frameQueue; |
| 79 @property(nonatomic, readonly) BOOL canUseBackCamera; | 104 @property(nonatomic, readonly) BOOL canUseBackCamera; |
| 80 @property(nonatomic, assign) BOOL useBackCamera; // Defaults to NO. | 105 @property(nonatomic, assign) BOOL useBackCamera; // Defaults to NO. |
| 81 @property(nonatomic, assign) BOOL isRunning; // Whether the capture session is running. | 106 @property(nonatomic, assign) BOOL isRunning; // Whether the capture session is running. |
| 82 @property(atomic, assign) BOOL hasStarted; // Whether we have an unmatched star t. | 107 @property(atomic, assign) BOOL hasStarted; // Whether we have an unmatched star t. |
| 83 | 108 |
| 84 // We keep a pointer back to AVFoundationVideoCapturer to make callbacks on it | 109 // 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 | 110 // when we receive frames. This is safe because this object should be owned by |
| 86 // it. | 111 // it. |
| 87 - (instancetype)initWithCapturer:(webrtc::AVFoundationVideoCapturer *)capturer; | 112 - (instancetype)initWithCapturer:(webrtc::AVFoundationVideoCapturer *)capturer; |
| 88 - (AVCaptureDevice *)getActiveCaptureDevice; | 113 - (AVCaptureDevice *)getActiveCaptureDevice; |
| 89 | 114 |
| 115 - (nullable AVCaptureDevice *)frontCaptureDevice; | |
| 116 - (nullable AVCaptureDevice *)backCaptureDevice; | |
| 117 | |
| 90 // Starts and stops the capture session asynchronously. We cannot do this | 118 // Starts and stops the capture session asynchronously. We cannot do this |
| 91 // synchronously without blocking a WebRTC thread. | 119 // synchronously without blocking a WebRTC thread. |
| 92 - (void)start; | 120 - (void)start; |
| 93 - (void)stop; | 121 - (void)stop; |
| 94 | 122 |
| 95 @end | 123 @end |
| 96 | 124 |
| 97 @implementation RTCAVFoundationVideoCapturerInternal { | 125 @implementation RTCAVFoundationVideoCapturerInternal { |
| 98 // Keep pointers to inputs for convenience. | 126 // Keep pointers to inputs for convenience. |
| 99 AVCaptureDeviceInput *_frontCameraInput; | 127 AVCaptureDeviceInput *_frontCameraInput; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 } | 196 } |
| 169 | 197 |
| 170 - (AVCaptureSession *)captureSession { | 198 - (AVCaptureSession *)captureSession { |
| 171 return _captureSession; | 199 return _captureSession; |
| 172 } | 200 } |
| 173 | 201 |
| 174 - (AVCaptureDevice *)getActiveCaptureDevice { | 202 - (AVCaptureDevice *)getActiveCaptureDevice { |
| 175 return self.useBackCamera ? _backCameraInput.device : _frontCameraInput.device ; | 203 return self.useBackCamera ? _backCameraInput.device : _frontCameraInput.device ; |
| 176 } | 204 } |
| 177 | 205 |
| 206 - (AVCaptureDevice *)frontCaptureDevice { | |
| 207 return _frontCameraInput.device; | |
| 208 } | |
| 209 | |
| 210 - (AVCaptureDevice *)backCaptureDevice { | |
| 211 return _backCameraInput.device; | |
| 212 } | |
| 213 | |
| 214 | |
| 178 - (dispatch_queue_t)frameQueue { | 215 - (dispatch_queue_t)frameQueue { |
| 179 if (!_frameQueue) { | 216 if (!_frameQueue) { |
| 180 _frameQueue = | 217 _frameQueue = |
| 181 dispatch_queue_create("org.webrtc.avfoundationvideocapturer.video", | 218 dispatch_queue_create("org.webrtc.avfoundationvideocapturer.video", |
| 182 DISPATCH_QUEUE_SERIAL); | 219 DISPATCH_QUEUE_SERIAL); |
| 183 dispatch_set_target_queue( | 220 dispatch_set_target_queue( |
| 184 _frameQueue, | 221 _frameQueue, |
| 185 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)); | 222 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)); |
| 186 } | 223 } |
| 187 return _frameQueue; | 224 return _frameQueue; |
| (...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 | 627 |
| 591 @end | 628 @end |
| 592 | 629 |
| 593 namespace webrtc { | 630 namespace webrtc { |
| 594 | 631 |
| 595 enum AVFoundationVideoCapturerMessageType : uint32_t { | 632 enum AVFoundationVideoCapturerMessageType : uint32_t { |
| 596 kMessageTypeFrame, | 633 kMessageTypeFrame, |
| 597 }; | 634 }; |
| 598 | 635 |
| 599 AVFoundationVideoCapturer::AVFoundationVideoCapturer() : _capturer(nil) { | 636 AVFoundationVideoCapturer::AVFoundationVideoCapturer() : _capturer(nil) { |
| 600 // Set our supported formats. This matches kAvailablePresets. | 637 _capturer = [[RTCAVFoundationVideoCapturerInternal alloc] initWithCapturer:thi s]; |
| 601 _capturer = | |
| 602 [[RTCAVFoundationVideoCapturerInternal alloc] initWithCapturer:this]; | |
| 603 | 638 |
| 604 std::vector<cricket::VideoFormat> supported_formats; | 639 std::vector<cricket::VideoFormat> frontCameraSupportedVideoFormats = |
| 605 int framerate = 30; | 640 GetSupportedVideoFormatsForDevice([_capturer frontCaptureDevice]); |
| 641 std::vector<cricket::VideoFormat> backCameraSupportedVideoFormats = | |
|
kthelgason
2016/09/20 07:00:30
I would use auto for all these types, I try to use
magjed_webrtc
2016/09/20 08:42:18
See https://google.github.io/styleguide/cppguide.h
| |
| 642 GetSupportedVideoFormatsForDevice([_capturer backCaptureDevice]); | |
| 606 | 643 |
| 607 #if TARGET_OS_IPHONE | 644 std::sort(frontCameraSupportedVideoFormats.begin(), frontCameraSupportedVideoF ormats.end()); |
| 608 if ([UIDevice deviceType] == RTCDeviceTypeIPhone4S) { | 645 std::sort(backCameraSupportedVideoFormats.begin(), backCameraSupportedVideoFor mats.end()); |
| 609 set_enable_video_adapter(false); | |
| 610 framerate = 15; | |
| 611 } | |
| 612 #endif | |
| 613 | 646 |
| 614 for (const auto preset : kAvailablePresets) { | 647 std::vector<cricket::VideoFormat> intersectionVideoFormats; |
| 615 if ([_capturer.captureSession canSetSessionPreset:preset.sessionPreset]) { | 648 std::set_intersection(frontCameraSupportedVideoFormats.begin(), |
| 616 const auto format = cricket::VideoFormat( | 649 frontCameraSupportedVideoFormats.end(), |
| 617 preset.width, | 650 backCameraSupportedVideoFormats.begin(), |
| 618 preset.height, | 651 backCameraSupportedVideoFormats.end(), |
| 619 cricket::VideoFormat::FpsToInterval(framerate), | 652 std::back_inserter(intersectionVideoFormats)); |
| 620 cricket::FOURCC_NV12); | |
| 621 supported_formats.push_back(format); | |
| 622 } | |
| 623 } | |
| 624 | 653 |
| 625 SetSupportedFormats(supported_formats); | 654 SetSupportedFormats(intersectionVideoFormats); |
| 626 } | 655 } |
| 627 | 656 |
| 628 AVFoundationVideoCapturer::~AVFoundationVideoCapturer() { | 657 AVFoundationVideoCapturer::~AVFoundationVideoCapturer() { |
| 629 _capturer = nil; | 658 _capturer = nil; |
| 630 } | 659 } |
| 631 | 660 |
| 632 cricket::CaptureState AVFoundationVideoCapturer::Start( | 661 cricket::CaptureState AVFoundationVideoCapturer::Start( |
| 633 const cricket::VideoFormat& format) { | 662 const cricket::VideoFormat& format) { |
| 634 if (!_capturer) { | 663 if (!_capturer) { |
| 635 LOG(LS_ERROR) << "Failed to create AVFoundation capturer."; | 664 LOG(LS_ERROR) << "Failed to create AVFoundation capturer."; |
| 636 return cricket::CaptureState::CS_FAILED; | 665 return cricket::CaptureState::CS_FAILED; |
| 637 } | 666 } |
| 638 if (_capturer.isRunning) { | 667 if (_capturer.isRunning) { |
| 639 LOG(LS_ERROR) << "The capturer is already running."; | 668 LOG(LS_ERROR) << "The capturer is already running."; |
| 640 return cricket::CaptureState::CS_FAILED; | 669 return cricket::CaptureState::CS_FAILED; |
| 641 } | 670 } |
| 642 | 671 |
| 643 NSString *desiredPreset = GetSessionPresetForVideoFormat(format); | 672 AVCaptureDeviceFormat *deviceFormat = |
| 644 RTC_DCHECK(desiredPreset); | 673 GetDeviceFormatForVideoFormat([_capturer getActiveCaptureDevice], format); |
|
magjed_webrtc
2016/09/20 08:42:18
You need to indent the new line with 4 spaces. htt
daniela-webrtc
2016/09/26 11:03:15
Acknowledged.
| |
| 674 AVCaptureDevice *device = [_capturer getActiveCaptureDevice]; | |
| 675 AVCaptureSession *session = [_capturer captureSession]; | |
| 676 NSError *error = nil; | |
| 645 | 677 |
| 646 [_capturer.captureSession beginConfiguration]; | 678 [session beginConfiguration]; // the session to which the receiver's AVCapture DeviceInput is added. |
|
kthelgason
2016/09/20 07:00:30
Is this necessary when only re-configuring the dev
daniela-webrtc
2016/09/23 08:49:17
Yes. Because this essentially causes the session t
| |
| 647 if (![_capturer.captureSession canSetSessionPreset:desiredPreset]) { | 679 if ([device lockForConfiguration:&error]) { |
| 648 LOG(LS_ERROR) << "Unsupported video format."; | 680 @try { |
| 649 [_capturer.captureSession commitConfiguration]; | 681 [device setActiveFormat:deviceFormat]; |
| 650 return cricket::CaptureState::CS_FAILED; | 682 } @catch (NSException *exception) { |
| 683 LOG(LS_ERROR) << [NSString stringWithFormat: | |
| 684 @"Exception occured while setting active format!\n User info:%@", exception.userInfo]; | |
| 685 return cricket::CaptureState::CS_FAILED; | |
| 686 } | |
| 687 | |
| 688 [device unlockForConfiguration]; | |
| 651 } | 689 } |
| 652 _capturer.captureSession.sessionPreset = desiredPreset; | 690 |
| 653 [_capturer.captureSession commitConfiguration]; | 691 [session commitConfiguration]; |
| 654 | 692 |
| 655 SetCaptureFormat(&format); | 693 SetCaptureFormat(&format); |
| 656 // This isn't super accurate because it takes a while for the AVCaptureSession | 694 // This isn't super accurate because it takes a while for the AVCaptureSession |
| 657 // to spin up, and this call returns async. | 695 // to spin up, and this call returns async. |
| 658 // TODO(tkchin): make this better. | 696 // TODO(tkchin): make this better. |
| 659 [_capturer start]; | 697 [_capturer start]; |
| 660 SetCaptureState(cricket::CaptureState::CS_RUNNING); | 698 SetCaptureState(cricket::CaptureState::CS_RUNNING); |
| 661 | 699 |
| 662 // Adjust the framerate for all capture devices. | 700 // Adjust the framerate for all capture devices. |
| 663 const auto fps = cricket::VideoFormat::IntervalToFps(format.interval); | 701 const auto fps = cricket::VideoFormat::IntervalToFps(format.interval); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 buffer = rotated_buffer; | 794 buffer = rotated_buffer; |
| 757 } | 795 } |
| 758 } | 796 } |
| 759 | 797 |
| 760 OnFrame(cricket::WebRtcVideoFrame(buffer, rotation, | 798 OnFrame(cricket::WebRtcVideoFrame(buffer, rotation, |
| 761 translated_camera_time_us, 0), | 799 translated_camera_time_us, 0), |
| 762 captured_width, captured_height); | 800 captured_width, captured_height); |
| 763 } | 801 } |
| 764 | 802 |
| 765 } // namespace webrtc | 803 } // namespace webrtc |
| OLD | NEW |