Index: webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm |
diff --git a/webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm b/webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm |
index 331db6d9557d4a6d74dd84d2692bc346ae396037..918833ef89a8447bcef55ddd2a5eb90e78e480b2 100644 |
--- a/webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm |
+++ b/webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm |
@@ -27,20 +27,42 @@ |
#include "webrtc/base/thread.h" |
#include "webrtc/common_video/include/corevideo_frame_buffer.h" |
-// TODO(tkchin): support other formats. |
-static NSString *const kDefaultPreset = AVCaptureSessionPreset640x480; |
-static NSString *const kIPhone4SPreset = AVCaptureSessionPreset352x288; |
-static cricket::VideoFormat const kDefaultFormat = |
- cricket::VideoFormat(640, |
- 480, |
- cricket::VideoFormat::FpsToInterval(30), |
- cricket::FOURCC_NV12); |
-// iPhone4S is too slow to handle 30fps. |
-static cricket::VideoFormat const kIPhone4SFormat = |
- cricket::VideoFormat(352, |
- 288, |
- cricket::VideoFormat::FpsToInterval(15), |
- cricket::FOURCC_NV12); |
+struct AVCaptureSessionPresetResolution { |
+ NSString *sessionPreset; |
+ int width; |
+ int height; |
+}; |
+ |
+#if TARGET_OS_IPHONE |
+static const AVCaptureSessionPresetResolution kAvailablePresets[] = { |
+ { AVCaptureSessionPreset352x288, 352, 288}, |
+ { AVCaptureSessionPreset640x480, 640, 480}, |
+ { AVCaptureSessionPreset1280x720, 1280, 720}, |
+ { AVCaptureSessionPreset1920x1080, 1920, 1080}, |
+}; |
+#else // macOS |
+static const AVCaptureSessionPresetResolution kAvailablePresets[] = { |
+ { AVCaptureSessionPreset320x240, 320, 240}, |
+ { AVCaptureSessionPreset352x288, 352, 288}, |
+ { AVCaptureSessionPreset640x480, 640, 480}, |
+ { AVCaptureSessionPreset960x540, 960, 540}, |
+ { AVCaptureSessionPreset1280x720, 1280, 720}, |
+}; |
+#endif |
+ |
+// Mapping from cricket::VideoFormat to AVCaptureSession presets. |
+static NSString *GetSessionPresetForVideoFormat( |
+ const cricket::VideoFormat& format) { |
+ for (const auto preset : kAvailablePresets) { |
+ // Check both orientations |
+ if ((format.width == preset.width && format.height == preset.height) || |
+ (format.width == preset.height && format.height == preset.width)) { |
+ return preset.sessionPreset; |
+ } |
+ } |
+ // If no matching preset is found, use a default one. |
+ return AVCaptureSessionPreset640x480; |
+} |
// This class used to capture frames using AVFoundation APIs on iOS. It is meant |
// to be owned by an instance of AVFoundationVideoCapturer. The reason for this |
@@ -361,17 +383,6 @@ static cricket::VideoFormat const kIPhone4SFormat = |
captureSession.usesApplicationAudioSession = NO; |
} |
#endif |
- NSString *preset = kDefaultPreset; |
-#if TARGET_OS_IPHONE |
- if ([UIDevice deviceType] == RTCDeviceTypeIPhone4S) { |
- preset = kIPhone4SPreset; |
- } |
-#endif |
- if (![captureSession canSetSessionPreset:preset]) { |
- RTCLogError(@"Session preset unsupported."); |
- return NO; |
- } |
- captureSession.sessionPreset = preset; |
// Add the output. |
AVCaptureVideoDataOutput *videoDataOutput = [self videoDataOutput]; |
@@ -399,11 +410,7 @@ static cricket::VideoFormat const kIPhone4SFormat = |
AVCaptureDeviceInput *input = self.useBackCamera ? |
backCameraInput : frontCameraInput; |
[captureSession addInput:input]; |
-#if TARGET_OS_IPHONE |
- if ([UIDevice deviceType] == RTCDeviceTypeIPhone4S) { |
- [self setMinFrameDuration:CMTimeMake(1, 15) forDevice:input.device]; |
- } |
-#endif |
+ |
_captureSession = captureSession; |
return YES; |
} |
@@ -486,15 +493,18 @@ static cricket::VideoFormat const kIPhone4SFormat = |
return _backCameraInput; |
} |
-- (void)setMinFrameDuration:(CMTime)minFrameDuration |
- forDevice:(AVCaptureDevice *)device { |
+- (void)setMinFrameDuration:(CMTime)minFrameDuration { |
NSError *error = nil; |
- if (![device lockForConfiguration:&error]) { |
- RTCLogError(@"Failed to lock device for configuration. Error: %@", error.localizedDescription); |
- return; |
+ for (AVCaptureDevice *device in |
+ [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { |
tkchin_webrtc
2016/08/18 15:17:24
Seems odd to do this for every capture device. Cou
|
+ if (![device lockForConfiguration:&error]) { |
+ RTCLogError(@"Failed to lock device for configuration. Error: %@", |
+ error.localizedDescription); |
+ return; |
magjed_webrtc
2016/08/18 09:27:37
nit: continue might be more appropriate than retur
|
+ } |
+ device.activeVideoMinFrameDuration = minFrameDuration; |
+ [device unlockForConfiguration]; |
} |
- device.activeVideoMinFrameDuration = minFrameDuration; |
- [device unlockForConfiguration]; |
} |
// Called from capture session queue. |
@@ -552,11 +562,6 @@ static cricket::VideoFormat const kIPhone4SFormat = |
} |
[self updateOrientation]; |
[_captureSession commitConfiguration]; |
-#if TARGET_OS_IPHONE |
- if ([UIDevice deviceType] == RTCDeviceTypeIPhone4S) { |
- [self setMinFrameDuration:CMTimeMake(1, 15) forDevice:newInput.device]; |
- } |
-#endif |
}]; |
} |
@@ -577,21 +582,32 @@ struct AVFoundationFrame { |
AVFoundationVideoCapturer::AVFoundationVideoCapturer() |
: _capturer(nil), _startThread(nullptr) { |
- // Set our supported formats. This matches preset. |
+ // Set our supported formats. This matches kAvailablePresets. |
+ _capturer = |
+ [[RTCAVFoundationVideoCapturerInternal alloc] initWithCapturer:this]; |
+ |
std::vector<cricket::VideoFormat> supported_formats; |
+ int framerate = 30; |
+ |
#if TARGET_OS_IPHONE |
if ([UIDevice deviceType] == RTCDeviceTypeIPhone4S) { |
- supported_formats.push_back(cricket::VideoFormat(kIPhone4SFormat)); |
set_enable_video_adapter(false); |
- } else { |
- supported_formats.push_back(cricket::VideoFormat(kDefaultFormat)); |
+ framerate = 15; |
} |
-#else |
- supported_formats.push_back(cricket::VideoFormat(kDefaultFormat)); |
#endif |
+ |
+ for (const auto preset : kAvailablePresets) { |
+ if ([_capturer.captureSession canSetSessionPreset:preset.sessionPreset]) { |
+ const auto format = cricket::VideoFormat( |
+ preset.width, |
+ preset.height, |
+ cricket::VideoFormat::FpsToInterval(framerate), |
+ cricket::FOURCC_NV12); |
+ supported_formats.push_back(format); |
+ } |
+ } |
+ |
SetSupportedFormats(supported_formats); |
- _capturer = |
- [[RTCAVFoundationVideoCapturerInternal alloc] initWithCapturer:this]; |
} |
AVFoundationVideoCapturer::~AVFoundationVideoCapturer() { |
@@ -608,10 +624,18 @@ cricket::CaptureState AVFoundationVideoCapturer::Start( |
LOG(LS_ERROR) << "The capturer is already running."; |
return cricket::CaptureState::CS_FAILED; |
} |
- if (format != kDefaultFormat && format != kIPhone4SFormat) { |
- LOG(LS_ERROR) << "Unsupported format provided."; |
+ |
+ NSString *desiredPreset = GetSessionPresetForVideoFormat(format); |
+ RTC_DCHECK(desiredPreset); |
+ |
+ [_capturer.captureSession beginConfiguration]; |
+ if (![_capturer.captureSession canSetSessionPreset:desiredPreset]) { |
+ LOG(LS_ERROR) << "Unsupported video format."; |
+ [_capturer.captureSession commitConfiguration]; |
return cricket::CaptureState::CS_FAILED; |
} |
+ _capturer.captureSession.sessionPreset = desiredPreset; |
+ [_capturer.captureSession commitConfiguration]; |
// Keep track of which thread capture started on. This is the thread that |
// frames need to be sent to. |
@@ -625,6 +649,10 @@ cricket::CaptureState AVFoundationVideoCapturer::Start( |
[_capturer start]; |
SetCaptureState(cricket::CaptureState::CS_RUNNING); |
+ // Adjust the framerate for all capture devices. |
+ const auto fps = cricket::VideoFormat::IntervalToFps(format.interval); |
magjed_webrtc
2016/08/18 09:27:37
nit: use int instead of auto here. We typically on
|
+ [_capturer setMinFrameDuration:CMTimeMake(1, fps)]; |
+ |
return cricket::CaptureState::CS_STARTING; |
} |