Revert "Remove deprecated mac capture code."
This reverts commit 3f1d15b35223dc129afd180d020318a56ea1d006.
Reason for revert: Removing this breaks a debugging tool that people relied on. I will update that tool to use the new capturer before relanding this.
Original change's description:
> Remove deprecated mac capture code.
>
> Bug: webrtc:6898, webrtc:6333, webrtc:7861
> Change-Id: Ie33eaa47585012f98b59ccffc0c849c1d9da54da
> Reviewed-on: https://webrtc-review.googlesource.com/79920
> Reviewed-by: Anders Carlsson <andersc@webrtc.org>
> Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
> Commit-Queue: Kári Helgason <kthelgason@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#23454}
TBR=henrika@webrtc.org,andersc@webrtc.org,kthelgason@webrtc.org
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: webrtc:6898, webrtc:6333, webrtc:7861
Change-Id: Ifc367eecfe92a2b2e4a826a820dc9c3c970ea01e
Reviewed-on: https://webrtc-review.googlesource.com/84380
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Commit-Queue: Kári Helgason <kthelgason@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23681}
diff --git a/examples/BUILD.gn b/examples/BUILD.gn
index 269e48b..c750f16 100644
--- a/examples/BUILD.gn
+++ b/examples/BUILD.gn
@@ -303,11 +303,7 @@
"../sdk:videosource_objc",
]
}
- libs = [
- "AVFoundation.framework",
- "CoreMedia.framework",
- "QuartzCore.framework",
- ]
+ libs = [ "QuartzCore.framework" ]
}
if (is_ios) {
@@ -346,8 +342,6 @@
":apprtc_signaling",
"../sdk:framework_objc",
]
-
- libs = [ "AVFoundation.framework" ]
}
ios_app_bundle("AppRTCMobile") {
diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn
index 4ce64e1..62c5314 100644
--- a/modules/video_capture/BUILD.gn
+++ b/modules/video_capture/BUILD.gn
@@ -68,6 +68,46 @@
}
if (!build_with_chromium) {
+ config("video_capture_internal_impl_config") {
+ if (is_ios || is_mac) {
+ libs = [
+ "AVFoundation.framework",
+ "CoreMedia.framework",
+ "CoreVideo.framework",
+ ]
+ }
+ }
+
+ if (is_ios || is_mac) {
+ rtc_source_set("video_capture_internal_impl_objc") {
+ visibility = [ ":video_capture_internal_impl" ]
+
+ deps = [
+ ":video_capture_module",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers",
+ ]
+
+ sources = [
+ "objc/device_info.h",
+ "objc/device_info.mm",
+ "objc/device_info_objc.h",
+ "objc/device_info_objc.mm",
+ "objc/rtc_video_capture_objc.h",
+ "objc/rtc_video_capture_objc.mm",
+ "objc/video_capture.h",
+ "objc/video_capture.mm",
+ ]
+
+ all_dependent_configs = [ ":video_capture_internal_impl_config" ]
+
+ if (!build_with_chromium && is_clang) {
+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+ }
+ }
+ }
+
rtc_source_set("video_capture_internal_impl") {
deps = [
":video_capture_module",
@@ -118,6 +158,11 @@
deps += [ "//third_party/winsdk_samples" ]
}
}
+ if (is_ios || is_mac) {
+ deps += [ ":video_capture_internal_impl_objc" ]
+ }
+
+ all_dependent_configs = [ ":video_capture_internal_impl_config" ]
if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
diff --git a/modules/video_capture/objc/device_info.h b/modules/video_capture/objc/device_info.h
new file mode 100644
index 0000000..8802367
--- /dev/null
+++ b/modules/video_capture/objc/device_info.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_VIDEO_CAPTURE_OBJC_DEVICE_INFO_H_
+#define MODULES_VIDEO_CAPTURE_OBJC_DEVICE_INFO_H_
+
+#include "modules/video_capture/device_info_impl.h"
+
+#include <map>
+#include <string>
+
+namespace webrtc {
+namespace videocapturemodule {
+class DeviceInfoIos : public DeviceInfoImpl {
+ public:
+ DeviceInfoIos();
+ virtual ~DeviceInfoIos();
+
+ // Implementation of DeviceInfoImpl.
+ int32_t Init() override;
+ uint32_t NumberOfDevices() override;
+ int32_t GetDeviceName(uint32_t deviceNumber,
+ char* deviceNameUTF8,
+ uint32_t deviceNameLength,
+ char* deviceUniqueIdUTF8,
+ uint32_t deviceUniqueIdUTF8Length,
+ char* productUniqueIdUTF8 = 0,
+ uint32_t productUniqueIdUTF8Length = 0) override;
+
+ int32_t NumberOfCapabilities(const char* deviceUniqueIdUTF8) override;
+
+ int32_t GetCapability(const char* deviceUniqueIdUTF8,
+ const uint32_t deviceCapabilityNumber,
+ VideoCaptureCapability& capability) override;
+
+ int32_t DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
+ const char* dialogTitleUTF8,
+ void* parentWindow,
+ uint32_t positionX,
+ uint32_t positionY) override;
+
+ int32_t GetOrientation(const char* deviceUniqueIdUTF8,
+ VideoRotation& orientation) override;
+
+ int32_t CreateCapabilityMap(const char* device_unique_id_utf8) override;
+
+ private:
+ std::map<std::string, VideoCaptureCapabilities> _capabilitiesMap;
+};
+
+} // namespace videocapturemodule
+} // namespace webrtc
+
+#endif // MODULES_VIDEO_CAPTURE_OBJC_DEVICE_INFO_H_
diff --git a/modules/video_capture/objc/device_info.mm b/modules/video_capture/objc/device_info.mm
new file mode 100644
index 0000000..42c1cd4
--- /dev/null
+++ b/modules/video_capture/objc/device_info.mm
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#include <AVFoundation/AVFoundation.h>
+
+#include <string>
+
+#include "modules/video_capture/objc/device_info.h"
+#include "modules/video_capture/objc/device_info_objc.h"
+#include "modules/video_capture/video_capture_impl.h"
+#include "rtc_base/logging.h"
+
+using namespace webrtc;
+using namespace videocapturemodule;
+
+static NSArray* camera_presets = @[
+ AVCaptureSessionPreset352x288,
+ AVCaptureSessionPreset640x480,
+ AVCaptureSessionPreset1280x720
+];
+
+#define IOS_UNSUPPORTED() \
+ RTC_LOG(LS_ERROR) << __FUNCTION__ << " is not supported on the iOS platform."; \
+ return -1;
+
+VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
+ return new DeviceInfoIos();
+}
+
+DeviceInfoIos::DeviceInfoIos() {
+ this->Init();
+}
+
+DeviceInfoIos::~DeviceInfoIos() {}
+
+int32_t DeviceInfoIos::Init() {
+ // Fill in all device capabilities.
+
+ int deviceCount = [DeviceInfoIosObjC captureDeviceCount];
+
+ for (int i = 0; i < deviceCount; i++) {
+ AVCaptureDevice* avDevice = [DeviceInfoIosObjC captureDeviceForIndex:i];
+ VideoCaptureCapabilities capabilityVector;
+
+ for (NSString* preset in camera_presets) {
+ BOOL support = [avDevice supportsAVCaptureSessionPreset:preset];
+ if (support) {
+ VideoCaptureCapability capability = [DeviceInfoIosObjC capabilityForPreset:preset];
+ capabilityVector.push_back(capability);
+ }
+ }
+
+ char deviceNameUTF8[256];
+ char deviceId[256];
+ this->GetDeviceName(i, deviceNameUTF8, 256, deviceId, 256);
+ std::string deviceIdCopy(deviceId);
+ std::pair<std::string, VideoCaptureCapabilities> mapPair =
+ std::pair<std::string, VideoCaptureCapabilities>(deviceIdCopy, capabilityVector);
+ _capabilitiesMap.insert(mapPair);
+ }
+
+ return 0;
+}
+
+uint32_t DeviceInfoIos::NumberOfDevices() {
+ return [DeviceInfoIosObjC captureDeviceCount];
+}
+
+int32_t DeviceInfoIos::GetDeviceName(uint32_t deviceNumber,
+ char* deviceNameUTF8,
+ uint32_t deviceNameUTF8Length,
+ char* deviceUniqueIdUTF8,
+ uint32_t deviceUniqueIdUTF8Length,
+ char* productUniqueIdUTF8,
+ uint32_t productUniqueIdUTF8Length) {
+ NSString* deviceName = [DeviceInfoIosObjC deviceNameForIndex:deviceNumber];
+
+ NSString* deviceUniqueId = [DeviceInfoIosObjC deviceUniqueIdForIndex:deviceNumber];
+
+ strncpy(deviceNameUTF8, [deviceName UTF8String], deviceNameUTF8Length);
+ deviceNameUTF8[deviceNameUTF8Length - 1] = '\0';
+
+ strncpy(deviceUniqueIdUTF8, deviceUniqueId.UTF8String, deviceUniqueIdUTF8Length);
+ deviceUniqueIdUTF8[deviceUniqueIdUTF8Length - 1] = '\0';
+
+ if (productUniqueIdUTF8) {
+ productUniqueIdUTF8[0] = '\0';
+ }
+
+ return 0;
+}
+
+int32_t DeviceInfoIos::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
+ int32_t numberOfCapabilities = 0;
+ std::string deviceUniqueId(deviceUniqueIdUTF8);
+ std::map<std::string, VideoCaptureCapabilities>::iterator it =
+ _capabilitiesMap.find(deviceUniqueId);
+
+ if (it != _capabilitiesMap.end()) {
+ numberOfCapabilities = it->second.size();
+ }
+ return numberOfCapabilities;
+}
+
+int32_t DeviceInfoIos::GetCapability(const char* deviceUniqueIdUTF8,
+ const uint32_t deviceCapabilityNumber,
+ VideoCaptureCapability& capability) {
+ std::string deviceUniqueId(deviceUniqueIdUTF8);
+ std::map<std::string, VideoCaptureCapabilities>::iterator it =
+ _capabilitiesMap.find(deviceUniqueId);
+
+ if (it != _capabilitiesMap.end()) {
+ VideoCaptureCapabilities deviceCapabilities = it->second;
+
+ if (deviceCapabilityNumber < deviceCapabilities.size()) {
+ VideoCaptureCapability cap;
+ cap = deviceCapabilities[deviceCapabilityNumber];
+ capability = cap;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int32_t DeviceInfoIos::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
+ const char* dialogTitleUTF8,
+ void* parentWindow,
+ uint32_t positionX,
+ uint32_t positionY) {
+ IOS_UNSUPPORTED();
+}
+
+int32_t DeviceInfoIos::GetOrientation(const char* deviceUniqueIdUTF8, VideoRotation& orientation) {
+ if (strcmp(deviceUniqueIdUTF8, "Front Camera") == 0) {
+ orientation = kVideoRotation_0;
+ } else {
+ orientation = kVideoRotation_90;
+ }
+ return orientation;
+}
+
+int32_t DeviceInfoIos::CreateCapabilityMap(const char* deviceUniqueIdUTF8) {
+ std::string deviceName(deviceUniqueIdUTF8);
+ std::map<std::string, std::vector<VideoCaptureCapability>>::iterator it =
+ _capabilitiesMap.find(deviceName);
+ VideoCaptureCapabilities deviceCapabilities;
+ if (it != _capabilitiesMap.end()) {
+ _captureCapabilities = it->second;
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/modules/video_capture/objc/device_info_objc.h b/modules/video_capture/objc/device_info_objc.h
new file mode 100644
index 0000000..670c3a1
--- /dev/null
+++ b/modules/video_capture/objc/device_info_objc.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_VIDEO_CAPTURE_OBJC_DEVICE_INFO_OBJC_H_
+#define MODULES_VIDEO_CAPTURE_OBJC_DEVICE_INFO_OBJC_H_
+
+#import <AVFoundation/AVFoundation.h>
+
+#include "modules/video_capture/video_capture_defines.h"
+
+@interface DeviceInfoIosObjC : NSObject
++ (int)captureDeviceCount;
++ (AVCaptureDevice*)captureDeviceForIndex:(int)index;
++ (AVCaptureDevice*)captureDeviceForUniqueId:(NSString*)uniqueId;
++ (NSString*)deviceNameForIndex:(int)index;
++ (NSString*)deviceUniqueIdForIndex:(int)index;
++ (NSString*)deviceNameForUniqueId:(NSString*)uniqueId;
++ (webrtc::VideoCaptureCapability)capabilityForPreset:(NSString*)preset;
+
+@end
+
+#endif // MODULES_VIDEO_CAPTURE_OBJC_DEVICE_INFO_OBJC_H_
diff --git a/modules/video_capture/objc/device_info_objc.mm b/modules/video_capture/objc/device_info_objc.mm
new file mode 100644
index 0000000..f2b102e
--- /dev/null
+++ b/modules/video_capture/objc/device_info_objc.mm
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import <AVFoundation/AVFoundation.h>
+
+#import "modules/video_capture/objc/device_info_objc.h"
+#include "modules/video_capture/video_capture_config.h"
+
+@implementation DeviceInfoIosObjC
+
++ (int)captureDeviceCount {
+ return [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
+}
+
++ (AVCaptureDevice*)captureDeviceForIndex:(int)index {
+ return [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]
+ objectAtIndex:index];
+}
+
++ (AVCaptureDevice*)captureDeviceForUniqueId:(NSString*)uniqueId {
+ for (AVCaptureDevice* device in
+ [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
+ if ([uniqueId isEqual:device.uniqueID]) {
+ return device;
+ }
+ }
+
+ return nil;
+}
+
++ (NSString*)deviceNameForIndex:(int)index {
+ return [DeviceInfoIosObjC captureDeviceForIndex:index].localizedName;
+}
+
++ (NSString*)deviceUniqueIdForIndex:(int)index {
+ return [DeviceInfoIosObjC captureDeviceForIndex:index].uniqueID;
+}
+
++ (NSString*)deviceNameForUniqueId:(NSString*)uniqueId {
+ return [[AVCaptureDevice deviceWithUniqueID:uniqueId] localizedName];
+}
+
++ (webrtc::VideoCaptureCapability)capabilityForPreset:(NSString*)preset {
+ webrtc::VideoCaptureCapability capability;
+
+ // TODO(tkchin): Maybe query AVCaptureDevice for supported formats, and
+ // then get the dimensions / frame rate from each supported format
+ if ([preset isEqualToString:AVCaptureSessionPreset352x288]) {
+ capability.width = 352;
+ capability.height = 288;
+ capability.maxFPS = 30;
+ capability.videoType = webrtc::VideoType::kNV12;
+ capability.interlaced = false;
+ } else if ([preset isEqualToString:AVCaptureSessionPreset640x480]) {
+ capability.width = 640;
+ capability.height = 480;
+ capability.maxFPS = 30;
+ capability.videoType = webrtc::VideoType::kNV12;
+ capability.interlaced = false;
+ } else if ([preset isEqualToString:AVCaptureSessionPreset1280x720]) {
+ capability.width = 1280;
+ capability.height = 720;
+ capability.maxFPS = 30;
+ capability.videoType = webrtc::VideoType::kNV12;
+ capability.interlaced = false;
+ }
+
+ return capability;
+}
+
+@end
diff --git a/modules/video_capture/objc/rtc_video_capture_objc.h b/modules/video_capture/objc/rtc_video_capture_objc.h
new file mode 100644
index 0000000..4b1d71c
--- /dev/null
+++ b/modules/video_capture/objc/rtc_video_capture_objc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_VIDEO_CAPTURE_OBJC_RTC_VIDEO_CAPTURE_OBJC_H_
+#define MODULES_VIDEO_CAPTURE_OBJC_RTC_VIDEO_CAPTURE_OBJC_H_
+
+#import <Foundation/Foundation.h>
+#ifdef WEBRTC_IOS
+#import <UIKit/UIKit.h>
+#endif
+
+#include "modules/video_capture/objc/video_capture.h"
+
+// The following class listens to a notification with name:
+// 'StatusBarOrientationDidChange'.
+// This notification must be posted in order for the capturer to reflect the
+// orientation change in video w.r.t. the application orientation.
+@interface RTCVideoCaptureIosObjC
+ : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate>
+
+@property webrtc::VideoRotation frameRotation;
+
+// custom initializer. Instance of VideoCaptureIos is needed
+// for callback purposes.
+// default init methods have been overridden to return nil.
+- (id)initWithOwner:(webrtc::videocapturemodule::VideoCaptureIos*)owner;
+- (BOOL)setCaptureDeviceByUniqueId:(NSString*)uniqueId;
+- (BOOL)startCaptureWithCapability:
+ (const webrtc::VideoCaptureCapability&)capability;
+- (BOOL)stopCapture;
+
+@end
+#endif // MODULES_VIDEO_CAPTURE_OBJC_RTC_VIDEO_CAPTURE_OBJC_H_
diff --git a/modules/video_capture/objc/rtc_video_capture_objc.mm b/modules/video_capture/objc/rtc_video_capture_objc.mm
new file mode 100644
index 0000000..61ef8db
--- /dev/null
+++ b/modules/video_capture/objc/rtc_video_capture_objc.mm
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import <AVFoundation/AVFoundation.h>
+#ifdef WEBRTC_IOS
+#import <UIKit/UIKit.h>
+#endif
+
+#import "modules/video_capture/objc/device_info_objc.h"
+#import "modules/video_capture/objc/rtc_video_capture_objc.h"
+
+#include "rtc_base/logging.h"
+
+using namespace webrtc;
+using namespace webrtc::videocapturemodule;
+
+@interface RTCVideoCaptureIosObjC (hidden)
+- (int)changeCaptureInputWithName:(NSString*)captureDeviceName;
+@end
+
+@implementation RTCVideoCaptureIosObjC {
+ webrtc::videocapturemodule::VideoCaptureIos* _owner;
+ webrtc::VideoCaptureCapability _capability;
+ AVCaptureSession* _captureSession;
+ BOOL _orientationHasChanged;
+ AVCaptureConnection* _connection;
+ BOOL _captureChanging; // Guarded by _captureChangingCondition.
+ NSCondition* _captureChangingCondition;
+}
+
+@synthesize frameRotation = _framRotation;
+
+- (id)initWithOwner:(VideoCaptureIos*)owner {
+ if (self = [super init]) {
+ _owner = owner;
+ _captureSession = [[AVCaptureSession alloc] init];
+#if defined(WEBRTC_IOS)
+ _captureSession.usesApplicationAudioSession = NO;
+#endif
+ _captureChanging = NO;
+ _captureChangingCondition = [[NSCondition alloc] init];
+
+ if (!_captureSession || !_captureChangingCondition) {
+ return nil;
+ }
+
+ // create and configure a new output (using callbacks)
+ AVCaptureVideoDataOutput* captureOutput = [[AVCaptureVideoDataOutput alloc] init];
+ NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
+
+ NSNumber* val = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8];
+ NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val forKey:key];
+ captureOutput.videoSettings = videoSettings;
+
+ // add new output
+ if ([_captureSession canAddOutput:captureOutput]) {
+ [_captureSession addOutput:captureOutput];
+ } else {
+ RTC_LOG(LS_ERROR) << __FUNCTION__ << ": Could not add output to AVCaptureSession";
+ }
+
+#ifdef WEBRTC_IOS
+ [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
+
+ NSNotificationCenter* notify = [NSNotificationCenter defaultCenter];
+ [notify addObserver:self
+ selector:@selector(onVideoError:)
+ name:AVCaptureSessionRuntimeErrorNotification
+ object:_captureSession];
+ [notify addObserver:self
+ selector:@selector(deviceOrientationDidChange:)
+ name:UIDeviceOrientationDidChangeNotification
+ object:nil];
+#endif
+ }
+
+ return self;
+}
+
+- (void)directOutputToSelf {
+ [[self currentOutput]
+ setSampleBufferDelegate:self
+ queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
+}
+
+- (void)directOutputToNil {
+ [[self currentOutput] setSampleBufferDelegate:nil queue:NULL];
+}
+
+- (void)deviceOrientationDidChange:(NSNotification*)notification {
+ _orientationHasChanged = YES;
+ [self setRelativeVideoOrientation];
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (BOOL)setCaptureDeviceByUniqueId:(NSString*)uniqueId {
+ [self waitForCaptureChangeToFinish];
+ // check to see if the camera is already set
+ if (_captureSession) {
+ NSArray* currentInputs = [NSArray arrayWithArray:[_captureSession inputs]];
+ if ([currentInputs count] > 0) {
+ AVCaptureDeviceInput* currentInput = [currentInputs objectAtIndex:0];
+ if ([uniqueId isEqualToString:[currentInput.device localizedName]]) {
+ return YES;
+ }
+ }
+ }
+
+ return [self changeCaptureInputByUniqueId:uniqueId];
+}
+
+- (BOOL)startCaptureWithCapability:(const VideoCaptureCapability&)capability {
+ [self waitForCaptureChangeToFinish];
+ if (!_captureSession) {
+ return NO;
+ }
+
+ // check limits of the resolution
+ if (capability.maxFPS < 0 || capability.maxFPS > 60) {
+ return NO;
+ }
+
+ if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
+ if (capability.width > 1280 || capability.height > 720) {
+ return NO;
+ }
+ } else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
+ if (capability.width > 640 || capability.height > 480) {
+ return NO;
+ }
+ } else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset352x288]) {
+ if (capability.width > 352 || capability.height > 288) {
+ return NO;
+ }
+ } else if (capability.width < 0 || capability.height < 0) {
+ return NO;
+ }
+
+ _capability = capability;
+
+ AVCaptureVideoDataOutput* currentOutput = [self currentOutput];
+ if (!currentOutput) return NO;
+
+ [self directOutputToSelf];
+
+ _orientationHasChanged = NO;
+ _captureChanging = YES;
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ [self startCaptureInBackgroundWithOutput:currentOutput];
+ });
+ return YES;
+}
+
+- (AVCaptureVideoDataOutput*)currentOutput {
+ return [[_captureSession outputs] firstObject];
+}
+
+- (void)startCaptureInBackgroundWithOutput:(AVCaptureVideoDataOutput*)currentOutput {
+ NSString* captureQuality = [NSString stringWithString:AVCaptureSessionPresetLow];
+ if (_capability.width >= 1280 || _capability.height >= 720) {
+ captureQuality = [NSString stringWithString:AVCaptureSessionPreset1280x720];
+ } else if (_capability.width >= 640 || _capability.height >= 480) {
+ captureQuality = [NSString stringWithString:AVCaptureSessionPreset640x480];
+ } else if (_capability.width >= 352 || _capability.height >= 288) {
+ captureQuality = [NSString stringWithString:AVCaptureSessionPreset352x288];
+ }
+
+ // begin configuration for the AVCaptureSession
+ [_captureSession beginConfiguration];
+
+ // picture resolution
+ [_captureSession setSessionPreset:captureQuality];
+
+ _connection = [currentOutput connectionWithMediaType:AVMediaTypeVideo];
+ [self setRelativeVideoOrientation];
+
+ // finished configuring, commit settings to AVCaptureSession.
+ [_captureSession commitConfiguration];
+
+ [_captureSession startRunning];
+ [self signalCaptureChangeEnd];
+}
+
+- (void)setRelativeVideoOrientation {
+ if (!_connection.supportsVideoOrientation) {
+ return;
+ }
+#ifndef WEBRTC_IOS
+ _connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
+ return;
+#else
+ switch ([UIDevice currentDevice].orientation) {
+ case UIDeviceOrientationPortrait:
+ _connection.videoOrientation = AVCaptureVideoOrientationPortrait;
+ break;
+ case UIDeviceOrientationPortraitUpsideDown:
+ _connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
+ break;
+ case UIDeviceOrientationLandscapeLeft:
+ _connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
+ break;
+ case UIDeviceOrientationLandscapeRight:
+ _connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
+ break;
+ case UIDeviceOrientationFaceUp:
+ case UIDeviceOrientationFaceDown:
+ case UIDeviceOrientationUnknown:
+ if (!_orientationHasChanged) {
+ _connection.videoOrientation = AVCaptureVideoOrientationPortrait;
+ }
+ break;
+ }
+#endif
+}
+
+- (void)onVideoError:(NSNotification*)notification {
+ NSLog(@"onVideoError: %@", notification);
+ // TODO(sjlee): make the specific error handling with this notification.
+ RTC_LOG(LS_ERROR) << __FUNCTION__ << ": [AVCaptureSession startRunning] error.";
+}
+
+- (BOOL)stopCapture {
+#ifdef WEBRTC_IOS
+ [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
+#endif
+ _orientationHasChanged = NO;
+ [self waitForCaptureChangeToFinish];
+ [self directOutputToNil];
+
+ if (!_captureSession) {
+ return NO;
+ }
+
+ _captureChanging = YES;
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
+ [self stopCaptureInBackground];
+ });
+ return YES;
+}
+
+- (void)stopCaptureInBackground {
+ [_captureSession stopRunning];
+ [self signalCaptureChangeEnd];
+}
+
+- (BOOL)changeCaptureInputByUniqueId:(NSString*)uniqueId {
+ [self waitForCaptureChangeToFinish];
+ NSArray* currentInputs = [_captureSession inputs];
+ // remove current input
+ if ([currentInputs count] > 0) {
+ AVCaptureInput* currentInput = (AVCaptureInput*)[currentInputs objectAtIndex:0];
+
+ [_captureSession removeInput:currentInput];
+ }
+
+ // Look for input device with the name requested (as our input param)
+ // get list of available capture devices
+ int captureDeviceCount = [DeviceInfoIosObjC captureDeviceCount];
+ if (captureDeviceCount <= 0) {
+ return NO;
+ }
+
+ AVCaptureDevice* captureDevice = [DeviceInfoIosObjC captureDeviceForUniqueId:uniqueId];
+
+ if (!captureDevice) {
+ return NO;
+ }
+
+ // now create capture session input out of AVCaptureDevice
+ NSError* deviceError = nil;
+ AVCaptureDeviceInput* newCaptureInput =
+ [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&deviceError];
+
+ if (!newCaptureInput) {
+ const char* errorMessage = [[deviceError localizedDescription] UTF8String];
+
+ RTC_LOG(LS_ERROR) << __FUNCTION__ << ": deviceInputWithDevice error:" << errorMessage;
+
+ return NO;
+ }
+
+ // try to add our new capture device to the capture session
+ [_captureSession beginConfiguration];
+
+ BOOL addedCaptureInput = NO;
+ if ([_captureSession canAddInput:newCaptureInput]) {
+ [_captureSession addInput:newCaptureInput];
+ addedCaptureInput = YES;
+ } else {
+ addedCaptureInput = NO;
+ }
+
+ [_captureSession commitConfiguration];
+
+ return addedCaptureInput;
+}
+
+- (void)captureOutput:(AVCaptureOutput*)captureOutput
+ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
+ fromConnection:(AVCaptureConnection*)connection {
+ const int kFlags = 0;
+ CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
+
+ if (CVPixelBufferLockBaseAddress(videoFrame, kFlags) != kCVReturnSuccess) {
+ return;
+ }
+
+ uint8_t* baseAddress = (uint8_t*)CVPixelBufferGetBaseAddress(videoFrame);
+ const size_t width = CVPixelBufferGetWidth(videoFrame);
+ const size_t height = CVPixelBufferGetHeight(videoFrame);
+ const size_t frameSize = width * height * 2;
+
+ VideoCaptureCapability tempCaptureCapability;
+ tempCaptureCapability.width = width;
+ tempCaptureCapability.height = height;
+ tempCaptureCapability.maxFPS = _capability.maxFPS;
+ tempCaptureCapability.videoType = VideoType::kUYVY;
+
+ _owner->IncomingFrame(baseAddress, frameSize, tempCaptureCapability, 0);
+
+ CVPixelBufferUnlockBaseAddress(videoFrame, kFlags);
+}
+
+- (void)signalCaptureChangeEnd {
+ [_captureChangingCondition lock];
+ _captureChanging = NO;
+ [_captureChangingCondition signal];
+ [_captureChangingCondition unlock];
+}
+
+- (void)waitForCaptureChangeToFinish {
+ [_captureChangingCondition lock];
+ while (_captureChanging) {
+ [_captureChangingCondition wait];
+ }
+ [_captureChangingCondition unlock];
+}
+@end
diff --git a/modules/video_capture/objc/video_capture.h b/modules/video_capture/objc/video_capture.h
new file mode 100644
index 0000000..0427d48
--- /dev/null
+++ b/modules/video_capture/objc/video_capture.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_VIDEO_CAPTURE_OBJC_VIDEO_CAPTURE_H_
+#define MODULES_VIDEO_CAPTURE_OBJC_VIDEO_CAPTURE_H_
+
+#include "modules/video_capture/video_capture_impl.h"
+#include "rtc_base/scoped_ref_ptr.h"
+
+@class RTCVideoCaptureIosObjC;
+
+namespace webrtc {
+namespace videocapturemodule {
+class VideoCaptureIos : public VideoCaptureImpl {
+ public:
+ VideoCaptureIos();
+ virtual ~VideoCaptureIos();
+
+ static rtc::scoped_refptr<VideoCaptureModule> Create(
+ const char* device_unique_id_utf8);
+
+ // Implementation of VideoCaptureImpl.
+ int32_t StartCapture(const VideoCaptureCapability& capability) override;
+ int32_t StopCapture() override;
+ bool CaptureStarted() override;
+ int32_t CaptureSettings(VideoCaptureCapability& settings) override;
+
+ private:
+ RTCVideoCaptureIosObjC* capture_device_;
+ bool is_capturing_;
+ VideoCaptureCapability capability_;
+};
+
+} // namespace videocapturemodule
+} // namespace webrtc
+
+#endif // MODULES_VIDEO_CAPTURE_OBJC_VIDEO_CAPTURE_H_
diff --git a/modules/video_capture/objc/video_capture.mm b/modules/video_capture/objc/video_capture.mm
new file mode 100644
index 0000000..6dd2fd6
--- /dev/null
+++ b/modules/video_capture/objc/video_capture.mm
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#include "modules/video_capture/objc/device_info_objc.h"
+#include "modules/video_capture/objc/rtc_video_capture_objc.h"
+#include "rtc_base/refcount.h"
+#include "rtc_base/refcountedobject.h"
+#include "rtc_base/scoped_ref_ptr.h"
+
+using namespace webrtc;
+using namespace videocapturemodule;
+
+rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
+ const char* deviceUniqueIdUTF8) {
+ return VideoCaptureIos::Create(deviceUniqueIdUTF8);
+}
+
+VideoCaptureIos::VideoCaptureIos()
+ : is_capturing_(false) {
+ capability_.width = kDefaultWidth;
+ capability_.height = kDefaultHeight;
+ capability_.maxFPS = kDefaultFrameRate;
+ capture_device_ = nil;
+}
+
+VideoCaptureIos::~VideoCaptureIos() {
+ if (is_capturing_) {
+ [capture_device_ stopCapture];
+ capture_device_ = nil;
+ }
+}
+
+rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(
+ const char* deviceUniqueIdUTF8) {
+ if (!deviceUniqueIdUTF8[0]) {
+ return NULL;
+ }
+
+ rtc::scoped_refptr<VideoCaptureIos> capture_module(
+ new rtc::RefCountedObject<VideoCaptureIos>());
+
+ const int32_t name_length = strlen(deviceUniqueIdUTF8);
+ if (name_length > kVideoCaptureUniqueNameLength)
+ return nullptr;
+
+ capture_module->_deviceUniqueId = new char[name_length + 1];
+ strncpy(capture_module->_deviceUniqueId, deviceUniqueIdUTF8, name_length + 1);
+ capture_module->_deviceUniqueId[name_length] = '\0';
+
+ capture_module->capture_device_ =
+ [[RTCVideoCaptureIosObjC alloc] initWithOwner:capture_module];
+ if (!capture_module->capture_device_) {
+ return nullptr;
+ }
+
+ if (![capture_module->capture_device_
+ setCaptureDeviceByUniqueId:
+ [[NSString alloc] initWithCString:deviceUniqueIdUTF8
+ encoding:NSUTF8StringEncoding]]) {
+ return nullptr;
+ }
+ return capture_module;
+}
+
+int32_t VideoCaptureIos::StartCapture(
+ const VideoCaptureCapability& capability) {
+ capability_ = capability;
+
+ if (![capture_device_ startCaptureWithCapability:capability]) {
+ return -1;
+ }
+
+ is_capturing_ = true;
+
+ return 0;
+}
+
+int32_t VideoCaptureIos::StopCapture() {
+ if (![capture_device_ stopCapture]) {
+ return -1;
+ }
+
+ is_capturing_ = false;
+ return 0;
+}
+
+bool VideoCaptureIos::CaptureStarted() {
+ return is_capturing_;
+}
+
+int32_t VideoCaptureIos::CaptureSettings(VideoCaptureCapability& settings) {
+ settings = capability_;
+ settings.videoType = VideoType::kNV12;
+ return 0;
+}
diff --git a/modules/video_capture/video_capture_factory.cc b/modules/video_capture/video_capture_factory.cc
index 1119853..28a61b8 100644
--- a/modules/video_capture/video_capture_factory.cc
+++ b/modules/video_capture/video_capture_factory.cc
@@ -16,7 +16,7 @@
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureFactory::Create(
const char* deviceUniqueIdUTF8) {
-#if defined(WEBRTC_ANDROID) || defined(WEBRTC_MAC)
+#if defined(WEBRTC_ANDROID)
return nullptr;
#else
return videocapturemodule::VideoCaptureImpl::Create(deviceUniqueIdUTF8);
@@ -29,7 +29,7 @@
}
VideoCaptureModule::DeviceInfo* VideoCaptureFactory::CreateDeviceInfo() {
-#if defined(WEBRTC_ANDROID) || defined(WEBRTC_MAC)
+#if defined(WEBRTC_ANDROID)
return nullptr;
#else
return videocapturemodule::VideoCaptureImpl::CreateDeviceInfo();