Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2113)

Unified Diff: webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm

Issue 2349223002: Replace SessionPresets with AVCaptureDeviceFormats (Closed)
Patch Set: Address reviewer's comments Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 5708346ae2bccdee06da02c5eea8d2a13d37d453..6e8b84d5e177715186490bec5e805cc3c25bba69 100644
--- a/webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm
+++ b/webrtc/sdk/objc/Framework/Classes/avfoundationvideocapturer.mm
@@ -30,41 +30,71 @@
#include "webrtc/common_video/include/corevideo_frame_buffer.h"
#include "webrtc/common_video/rotation.h"
-struct AVCaptureSessionPresetResolution {
- NSString *sessionPreset;
- int width;
- int height;
-};
+static const int kFramesPerSecond = 30;
magjed_webrtc 2016/09/27 14:36:10 Can you add a todo, something like: // TODO(denici
daniela-webrtc 2016/09/28 15:29:26 Done.
+
+// Maping from cricket::VideoFormat to AVCaptureDeviceFormat.
tkchin_webrtc 2016/09/27 13:39:34 nit: Mapping
daniela-webrtc 2016/09/28 15:29:27 Done.
+static AVCaptureDeviceFormat* GetDeviceFormatForVideoFormat(
+ const AVCaptureDevice* device,
+ const cricket::VideoFormat& videoFormat) {
+ AVCaptureDeviceFormat* desiredDeviceFormat = nil;
tkchin_webrtc 2016/09/27 13:39:34 if treating this as a C/C++ function, should be de
daniela-webrtc 2016/09/28 15:29:26 Done.
+ for (AVCaptureDeviceFormat* deviceFormat in [device formats]) {
tkchin_webrtc 2016/09/27 13:39:33 dot syntax for properties. Here and elsewhere
daniela-webrtc 2016/09/28 15:29:27 Done.
+ CMVideoDimensions dimension =
+ CMVideoFormatDescriptionGetDimensions([deviceFormat formatDescription]);
+ FourCharCode code =
+ CMFormatDescriptionGetMediaSubType([deviceFormat formatDescription]);
+
+ if (code != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange &&
tkchin_webrtc 2016/09/27 13:39:33 If we care about only selectively picking out NV12
magjed_webrtc 2016/09/27 14:36:10 Ah, true. We hardcode the pixel format to FullRang
daniela-webrtc 2016/09/28 15:29:26 Not sure I follow. The reason why we allow both fu
+ code != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {
+ continue;
+ }
-#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
+ if (videoFormat.width == dimension.width &&
+ videoFormat.height == dimension.height) {
+ for (AVFrameRateRange* framerate in
+ [deviceFormat videoSupportedFrameRateRanges]) {
+ if (!(framerate.minFrameRate >= kFramesPerSecond &&
tkchin_webrtc 2016/09/27 13:39:34 perhaps frameRate.minFrameRate < kFramesPerSecond
daniela-webrtc 2016/09/28 15:29:26 Great catch. Thanks
+ framerate.maxFrameRate <= kFramesPerSecond)) {
magjed_webrtc 2016/09/27 14:36:10 I think this check is incorrect, the comparison is
daniela-webrtc 2016/09/28 15:29:26 Done.
+ continue;
+ }
+ }
+ if (code == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
+ // this is the preferred format so no need to wait for better option
tkchin_webrtc 2016/09/27 13:39:34 nit: Capitalize first letter of comment and end wi
daniela-webrtc 2016/09/28 15:29:26 Done.
+ return deviceFormat;
+ } else {
+ // this is good candidate, but let's wait for something better
+ desiredDeviceFormat = deviceFormat;
magjed_webrtc 2016/09/27 14:36:10 I'm wondering how we should select between multipl
+ }
+ }
+ }
+ return desiredDeviceFormat;
+}
+
+// Mapping from AVCaptureDeviceFormat to cricket::VideoFormat for given input
+// device.
+static std::set<cricket::VideoFormat> GetSupportedVideoFormatsForDevice(
+ AVCaptureDevice* device) {
tkchin_webrtc 2016/09/27 13:39:33 ditto pick one of C++/ObjC style conventions to us
daniela-webrtc 2016/09/28 15:29:26 Done.
+ std::set<cricket::VideoFormat> supportedFormats;
+
+ for (AVCaptureDeviceFormat* deviceFormat in [device formats]) {
+ FourCharCode code =
+ CMFormatDescriptionGetMediaSubType([deviceFormat formatDescription]);
-// 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 (code != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange &&
tkchin_webrtc 2016/09/27 13:39:33 I would've expected this code to output all possib
magjed_webrtc 2016/09/27 14:36:10 FYI - We currently only support NV12 because the c
+ code != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {
+ continue;
}
+
+ CMVideoDimensions dimension =
+ CMVideoFormatDescriptionGetDimensions([deviceFormat formatDescription]);
+
magjed_webrtc 2016/09/27 14:36:10 I think we should have the fps check here as well,
daniela-webrtc 2016/09/28 15:29:26 Agreed. I don't like how I handled the filtering o
daniela-webrtc 2016/09/30 11:35:59 I've uploaded a patch with this change. Please let
+ cricket::VideoFormat format = cricket::VideoFormat(
+ dimension.width, dimension.height,
+ cricket::VideoFormat::FpsToInterval(kFramesPerSecond),
+ cricket::FOURCC_NV12);
+ supportedFormats.insert(format);
}
- // If no matching preset is found, use a default one.
- return AVCaptureSessionPreset640x480;
+
+ return supportedFormats;
}
// This class used to capture frames using AVFoundation APIs on iOS. It is meant
@@ -87,6 +117,9 @@ static NSString *GetSessionPresetForVideoFormat(
- (instancetype)initWithCapturer:(webrtc::AVFoundationVideoCapturer *)capturer;
- (AVCaptureDevice *)getActiveCaptureDevice;
+- (nullable AVCaptureDevice*)frontCaptureDevice;
tkchin_webrtc 2016/09/27 13:39:34 not sure we need nullability annotations for inter
daniela-webrtc 2016/09/28 15:29:26 In general I like nullable/nonnull annotations as
+- (nullable AVCaptureDevice*)backCaptureDevice;
+
// Starts and stops the capture session asynchronously. We cannot do this
// synchronously without blocking a WebRTC thread.
- (void)start;
@@ -175,6 +208,14 @@ static NSString *GetSessionPresetForVideoFormat(
return self.useBackCamera ? _backCameraInput.device : _frontCameraInput.device;
}
+- (AVCaptureDevice*)frontCaptureDevice {
+ return _frontCameraInput.device;
tkchin_webrtc 2016/09/27 13:39:33 nit: Device *) here and below
daniela-webrtc 2016/09/28 15:29:26 Done.
+}
+
+- (AVCaptureDevice*)backCaptureDevice {
+ return _backCameraInput.device;
+}
+
- (dispatch_queue_t)frameQueue {
if (!_frameQueue) {
_frameQueue =
@@ -526,17 +567,6 @@ static NSString *GetSessionPresetForVideoFormat(
return _backCameraInput;
}
-- (void)setMinFrameDuration:(CMTime)minFrameDuration
- forDevice:(AVCaptureDevice *)device {
- NSError *error = nil;
- if (![device lockForConfiguration:&error]) {
- RTCLogError(@"Failed to lock device for configuration. Error: %@", error.localizedDescription);
- return;
- }
- device.activeVideoMinFrameDuration = minFrameDuration;
- [device unlockForConfiguration];
-}
-
// Called from capture session queue.
- (void)updateOrientation {
#if TARGET_OS_IPHONE
@@ -581,10 +611,26 @@ static NSString *GetSessionPresetForVideoFormat(
[_captureSession addInput:newInput];
}
[self updateOrientation];
- [_captureSession commitConfiguration];
+ AVCaptureDevice* newDevice = [newInput device];
tkchin_webrtc 2016/09/27 13:39:34 Device *newDevice here and below
daniela-webrtc 2016/09/28 15:29:26 Done.
+ NSError* error = nil;
+ const cricket::VideoFormat* format = _capturer->GetCaptureFormat();
tkchin_webrtc 2016/09/27 13:39:34 is this thread safe? (Calling from different queue
daniela-webrtc 2016/09/29 11:02:31 Not sure. If i understand correctly the capture fo
+ AVCaptureDeviceFormat* newFormat =
+ GetDeviceFormatForVideoFormat(newDevice, *format);
tkchin_webrtc 2016/09/27 13:39:33 How expensive is this operation? Is it slow to que
daniela-webrtc 2016/09/29 11:02:31 Shouldn't be too expensive and ideally shouldn't h
const auto fps = cricket::VideoFormat::IntervalToFps(_capturer->GetCaptureFormat()->interval);
- [self setMinFrameDuration:CMTimeMake(1, fps)forDevice:newInput.device];
+ if ([newDevice lockForConfiguration:&error]) {
+ @try {
+ [newDevice setActiveFormat:newFormat];
tkchin_webrtc 2016/09/27 13:39:33 Use dot syntax where able .activeFormat =
daniela-webrtc 2016/09/28 15:29:26 Done.
+ [newDevice setActiveVideoMinFrameDuration:CMTimeMake(1, fps)];
+ } @catch (NSException* exception) {
+ LOG(LS_ERROR) << [NSString stringWithFormat:@"Exception occured while "
tkchin_webrtc 2016/09/27 13:39:34 We've used RTCLogError as a convenience
daniela-webrtc 2016/09/28 15:29:26 Done.
daniela-webrtc 2016/09/29 11:02:31 For future reference, do we use RTCLogError in Obj
+ @"setting active "
+ @"format!\n User info:%@",
+ exception.userInfo];
+ }
+ [newDevice unlockForConfiguration];
+ }
+ [_captureSession commitConfiguration];
}];
}
@@ -597,32 +643,39 @@ enum AVFoundationVideoCapturerMessageType : uint32_t {
};
AVFoundationVideoCapturer::AVFoundationVideoCapturer() : _capturer(nil) {
- // Set our supported formats. This matches kAvailablePresets.
_capturer =
[[RTCAVFoundationVideoCapturerInternal alloc] initWithCapturer:this];
- std::vector<cricket::VideoFormat> supported_formats;
- int framerate = 30;
+ std::set<cricket::VideoFormat> frontCameraSupportedVideoFormats =
tkchin_webrtc 2016/09/27 13:39:34 c++ style here so front_camera_supported_video_for
daniela-webrtc 2016/09/28 15:29:26 Done.
+ GetSupportedVideoFormatsForDevice([_capturer frontCaptureDevice]);
-#if TARGET_OS_IPHONE
- if ([UIDevice deviceType] == RTCDeviceTypeIPhone4S) {
- set_enable_video_adapter(false);
- framerate = 15;
+ std::set<cricket::VideoFormat> backCameraSupportedVideoFormats =
+ GetSupportedVideoFormatsForDevice([_capturer backCaptureDevice]);
+
+ std::vector<cricket::VideoFormat> intersectionVideoFormats;
+ if (backCameraSupportedVideoFormats.size() == 0) {
+ std::copy(frontCameraSupportedVideoFormats.begin(),
+ frontCameraSupportedVideoFormats.end(),
+ std::back_inserter(intersectionVideoFormats));
+ SetSupportedFormats(intersectionVideoFormats);
+ return;
}
-#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);
- }
+ if (frontCameraSupportedVideoFormats.size() == 0) {
+ std::copy(backCameraSupportedVideoFormats.begin(),
+ backCameraSupportedVideoFormats.end(),
+ std::back_inserter(intersectionVideoFormats));
+ SetSupportedFormats(intersectionVideoFormats);
+ return;
}
- SetSupportedFormats(supported_formats);
+ std::set_intersection(frontCameraSupportedVideoFormats.begin(),
+ frontCameraSupportedVideoFormats.end(),
+ backCameraSupportedVideoFormats.begin(),
+ backCameraSupportedVideoFormats.end(),
+ std::back_inserter(intersectionVideoFormats));
+
+ SetSupportedFormats(intersectionVideoFormats);
}
AVFoundationVideoCapturer::~AVFoundationVideoCapturer() {
@@ -640,17 +693,32 @@ cricket::CaptureState AVFoundationVideoCapturer::Start(
return cricket::CaptureState::CS_FAILED;
}
- NSString *desiredPreset = GetSessionPresetForVideoFormat(format);
- RTC_DCHECK(desiredPreset);
+ AVCaptureDeviceFormat* deviceFormat =
+ GetDeviceFormatForVideoFormat([_capturer getActiveCaptureDevice], format);
+ const auto fps = cricket::VideoFormat::IntervalToFps(format.interval);
- [_capturer.captureSession beginConfiguration];
- if (![_capturer.captureSession canSetSessionPreset:desiredPreset]) {
- LOG(LS_ERROR) << "Unsupported video format.";
- [_capturer.captureSession commitConfiguration];
- return cricket::CaptureState::CS_FAILED;
+ AVCaptureDevice* device = [_capturer getActiveCaptureDevice];
+ AVCaptureSession* session = [_capturer captureSession];
+ NSError* error = nil;
+
+ [session beginConfiguration]; // the session to which the receiver's
tkchin_webrtc 2016/09/27 13:39:34 nit: don't split comments out at end of line, plac
daniela-webrtc 2016/09/28 15:29:26 Actually this comment is not needed. I'll remove i
daniela-webrtc 2016/09/30 11:35:59 Done.
+ // AVCaptureDeviceInput is added.
+ if ([device lockForConfiguration:&error]) {
magjed_webrtc 2016/09/27 14:36:10 Can we extract this out in a common function: void
daniela-webrtc 2016/09/29 11:02:31 YES! I forgot to do this. Good catch. Thanks
daniela-webrtc 2016/09/30 11:35:59 Done.
+ @try {
+ [device setActiveFormat:deviceFormat];
+ [device setActiveVideoMinFrameDuration:CMTimeMake(1, fps)];
+ } @catch (NSException* exception) {
+ LOG(LS_ERROR) << [NSString
+ stringWithFormat:
+ @"Exception occured while setting active format!\n User info:%@",
+ exception.userInfo];
+ return cricket::CaptureState::CS_FAILED;
+ }
+
+ [device unlockForConfiguration];
}
- _capturer.captureSession.sessionPreset = desiredPreset;
- [_capturer.captureSession commitConfiguration];
+
+ [session commitConfiguration];
SetCaptureFormat(&format);
// This isn't super accurate because it takes a while for the AVCaptureSession
@@ -659,11 +727,6 @@ 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);
- AVCaptureDevice *activeDevice = [_capturer getActiveCaptureDevice];
- [_capturer setMinFrameDuration:CMTimeMake(1, fps)forDevice:activeDevice];
-
return cricket::CaptureState::CS_STARTING;
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698