Bug 1451394 - Integrate with the libwebrtc camera backend for Mac. r=webrtc-reviewers,jib

Differential Revision: https://phabricator.services.mozilla.com/D163684
This commit is contained in:
Andreas Pehrson 2022-12-12 15:47:22 +00:00
parent ace3a99c63
commit 47c24b8bab
13 changed files with 533 additions and 13 deletions

View File

@ -36,9 +36,15 @@ if CONFIG["MOZ_WEBRTC"]:
REQUIRES_UNIFIED_BUILD = True
UNIFIED_SOURCES += [
"objc_video_capture/device_info.mm",
"objc_video_capture/device_info_avfoundation.mm",
"objc_video_capture/device_info_objc.mm",
"objc_video_capture/rtc_video_capture_objc.mm",
"objc_video_capture/video_capture.mm",
"objc_video_capture/video_capture_avfoundation.mm",
]
LOCAL_INCLUDES += [
"/third_party/libwebrtc/sdk/objc",
"/third_party/libwebrtc/sdk/objc/base",
]
CMMFLAGS += [
"-fobjc-arc",

View File

@ -18,8 +18,7 @@
@class DeviceInfoIosObjC;
namespace webrtc {
namespace videocapturemodule {
namespace webrtc::videocapturemodule {
class DeviceInfoIos : public DeviceInfoImpl {
public:
DeviceInfoIos();
@ -52,7 +51,6 @@ class DeviceInfoIos : public DeviceInfoImpl {
DeviceInfoIosObjC* _captureInfo;
};
} // namespace videocapturemodule
} // namespace webrtc
} // namespace webrtc::videocapturemodule
#endif // MODULES_VIDEO_CAPTURE_OBJC_DEVICE_INFO_H_

View File

@ -19,8 +19,11 @@
#include "device_info.h"
#include "device_info_objc.h"
#include "modules/video_capture/video_capture_impl.h"
#include "mozilla/StaticPrefs_media.h"
#include "objc_video_capture/device_info_avfoundation.h"
#include "rtc_base/logging.h"
using namespace mozilla;
using namespace webrtc;
using namespace videocapturemodule;
@ -32,7 +35,12 @@ static NSArray* camera_presets = @[
RTC_LOG(LS_ERROR) << __FUNCTION__ << " is not supported on the iOS platform."; \
return -1;
VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() { return new DeviceInfoIos(); }
VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
if (StaticPrefs::media_getusermedia_camera_macavf_enabled_AtStartup()) {
return new DeviceInfoAvFoundation();
}
return new DeviceInfoIos();
}
DeviceInfoIos::DeviceInfoIos() { this->Init(); }

View File

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_MEDIA_SYSTEMSERVICES_OBJC_VIDEO_CAPTURE_DEVICE_INFO_AVFOUNDATION_H_
#define DOM_MEDIA_SYSTEMSERVICES_OBJC_VIDEO_CAPTURE_DEVICE_INFO_AVFOUNDATION_H_
#include <map>
#include <string>
#include "api/sequence_checker.h"
#include "device_info_objc.h"
#include "modules/video_capture/device_info_impl.h"
namespace webrtc::videocapturemodule {
/**
* DeviceInfo implementation for the libwebrtc ios/mac sdk camera backend.
* Single threaded except for DeviceChange() that happens on a platform callback
* thread.
*/
class DeviceInfoAvFoundation : public DeviceInfoImpl {
public:
static int32_t ConvertAVFrameRateToCapabilityFPS(Float64 aRate);
static webrtc::VideoType ConvertFourCCToVideoType(FourCharCode aCode);
DeviceInfoAvFoundation();
virtual ~DeviceInfoAvFoundation();
// Implementation of DeviceInfoImpl.
int32_t Init() override { return 0; }
void DeviceChange() override;
uint32_t NumberOfDevices() override;
int32_t GetDeviceName(uint32_t aDeviceNumber, char* aDeviceNameUTF8,
uint32_t aDeviceNameLength, char* aDeviceUniqueIdUTF8,
uint32_t aDeviceUniqueIdUTF8Length,
char* aProductUniqueIdUTF8 = nullptr,
uint32_t aProductUniqueIdUTF8Length = 0,
pid_t* aPid = nullptr) override;
int32_t NumberOfCapabilities(const char* aDeviceUniqueIdUTF8) override;
int32_t GetCapability(const char* aDeviceUniqueIdUTF8,
const uint32_t aDeviceCapabilityNumber,
VideoCaptureCapability& aCapability) override;
int32_t DisplayCaptureSettingsDialogBox(const char* aDeviceUniqueIdUTF8,
const char* aDialogTitleUTF8,
void* aParentWindow,
uint32_t aPositionX,
uint32_t aPositionY) override {
return -1;
}
int32_t CreateCapabilityMap(const char* aDeviceUniqueIdUTF8) override
RTC_EXCLUSIVE_LOCKS_REQUIRED(_apiLock);
private:
const std::tuple<std::string, std::string, VideoCaptureCapabilities>*
FindDeviceAndCapabilities(const std::string& aDeviceUniqueId) const;
void EnsureCapabilitiesMap();
SequenceChecker mChecker;
std::atomic<bool> mInvalidateCapabilities;
// [{uniqueId, name, capabilities}]
std::vector<std::tuple<std::string, std::string, VideoCaptureCapabilities>>
mDevicesAndCapabilities RTC_GUARDED_BY(mChecker);
const DeviceInfoIosObjC* mDeviceChangeCaptureInfo RTC_GUARDED_BY(mChecker);
};
} // namespace webrtc::videocapturemodule
#endif

View File

@ -0,0 +1,213 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "device_info_avfoundation.h"
#include <CoreVideo/CVPixelBuffer.h>
#include <string>
#include "components/capturer/RTCCameraVideoCapturer.h"
#import "helpers/NSString+StdString.h"
#include "media/base/video_common.h"
#include "modules/video_capture/video_capture_defines.h"
#include "rtc_base/logging.h"
namespace webrtc::videocapturemodule {
/* static */
int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(Float64 aRate) {
return static_cast<int32_t>(aRate);
}
/* static */
webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(FourCharCode aCode) {
switch (aCode) {
case kCVPixelFormatType_420YpCbCr8Planar:
case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
return webrtc::VideoType::kI420;
case kCVPixelFormatType_24BGR:
return webrtc::VideoType::kRGB24;
case kCVPixelFormatType_32ABGR:
return webrtc::VideoType::kABGR;
case kCMPixelFormat_32ARGB:
return webrtc::VideoType::kBGRA;
case kCMPixelFormat_32BGRA:
return webrtc::VideoType::kARGB;
case kCMPixelFormat_16LE565:
return webrtc::VideoType::kRGB565;
case kCMPixelFormat_16LE555:
case kCMPixelFormat_16LE5551:
return webrtc::VideoType::kARGB1555;
case kCMPixelFormat_422YpCbCr8_yuvs:
return webrtc::VideoType::kYUY2;
case kCMPixelFormat_422YpCbCr8:
return webrtc::VideoType::kUYVY;
case kCMVideoCodecType_JPEG:
case kCMVideoCodecType_JPEG_OpenDML:
return webrtc::VideoType::kMJPEG;
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
return webrtc::VideoType::kNV12;
default:
RTC_LOG(LS_WARNING) << "Unhandled FourCharCode" << aCode;
return webrtc::VideoType::kUnknown;
}
}
DeviceInfoAvFoundation::DeviceInfoAvFoundation()
: mInvalidateCapabilities(false), mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) {
[mDeviceChangeCaptureInfo registerOwner:this];
}
DeviceInfoAvFoundation::~DeviceInfoAvFoundation() { [mDeviceChangeCaptureInfo registerOwner:nil]; }
void DeviceInfoAvFoundation::DeviceChange() {
mInvalidateCapabilities = true;
DeviceInfo::DeviceChange();
}
uint32_t DeviceInfoAvFoundation::NumberOfDevices() {
RTC_DCHECK_RUN_ON(&mChecker);
EnsureCapabilitiesMap();
return mDevicesAndCapabilities.size();
}
int32_t DeviceInfoAvFoundation::GetDeviceName(uint32_t aDeviceNumber, char* aDeviceNameUTF8,
uint32_t aDeviceNameLength, char* aDeviceUniqueIdUTF8,
uint32_t aDeviceUniqueIdUTF8Length,
char* /* aProductUniqueIdUTF8 */,
uint32_t /* aProductUniqueIdUTF8Length */,
pid_t* /* aPid */) {
RTC_DCHECK_RUN_ON(&mChecker);
// Don't EnsureCapabilitiesMap() here, since:
// 1) That might invalidate the capabilities map
// 2) This function depends on the device index
if (aDeviceNumber >= mDevicesAndCapabilities.size()) {
return -1;
}
const auto& [uniqueId, name, _] = mDevicesAndCapabilities[aDeviceNumber];
strncpy(aDeviceUniqueIdUTF8, uniqueId.c_str(), aDeviceUniqueIdUTF8Length);
aDeviceUniqueIdUTF8[aDeviceUniqueIdUTF8Length - 1] = '\0';
strncpy(aDeviceNameUTF8, name.c_str(), aDeviceNameLength);
aDeviceNameUTF8[aDeviceNameLength - 1] = '\0';
return 0;
}
int32_t DeviceInfoAvFoundation::NumberOfCapabilities(const char* aDeviceUniqueIdUTF8) {
RTC_DCHECK_RUN_ON(&mChecker);
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
if (!tup) {
return 0;
}
const auto& [_, __, capabilities] = *tup;
return static_cast<int32_t>(capabilities.size());
}
int32_t DeviceInfoAvFoundation::GetCapability(const char* aDeviceUniqueIdUTF8,
const uint32_t aDeviceCapabilityNumber,
VideoCaptureCapability& aCapability) {
RTC_DCHECK_RUN_ON(&mChecker);
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
if (!tup) {
return -1;
}
const auto& [_, __, capabilities] = *tup;
if (aDeviceCapabilityNumber >= capabilities.size()) {
return -1;
}
aCapability = capabilities[aDeviceCapabilityNumber];
return 0;
}
int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdUTF8) {
RTC_DCHECK_RUN_ON(&mChecker);
const size_t deviceUniqueIdUTF8Length = strlen(aDeviceUniqueIdUTF8);
if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength) {
RTC_LOG(LS_INFO) << "Device name too long";
return -1;
}
RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device " << aDeviceUniqueIdUTF8;
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
if (!tup) {
RTC_LOG(LS_INFO) << "no matching device found";
return -1;
}
// Store the new used device name
_lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
_lastUsedDeviceName =
static_cast<char*>(realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8, _lastUsedDeviceNameLength + 1);
const auto& [_, __, capabilities] = *tup;
_captureCapabilities = capabilities;
return static_cast<int32_t>(_captureCapabilities.size());
}
auto DeviceInfoAvFoundation::FindDeviceAndCapabilities(const std::string& aDeviceUniqueId) const
-> const std::tuple<std::string, std::string, VideoCaptureCapabilities>* {
RTC_DCHECK_RUN_ON(&mChecker);
for (const auto& tup : mDevicesAndCapabilities) {
if (std::get<0>(tup) == aDeviceUniqueId) {
return &tup;
}
}
return nullptr;
}
void DeviceInfoAvFoundation::EnsureCapabilitiesMap() {
RTC_DCHECK_RUN_ON(&mChecker);
if (mInvalidateCapabilities.exchange(false)) {
mDevicesAndCapabilities.clear();
}
if (!mDevicesAndCapabilities.empty()) {
return;
}
for (AVCaptureDevice* device in [RTCCameraVideoCapturer captureDevices]) {
std::string uniqueId = [NSString stdStringForString:device.uniqueID];
std::string name = [NSString stdStringForString:device.localizedName];
auto& [_, __, capabilities] =
mDevicesAndCapabilities.emplace_back(uniqueId, name, VideoCaptureCapabilities());
for (AVCaptureDeviceFormat* format in
[RTCCameraVideoCapturer supportedFormatsForDevice:device]) {
VideoCaptureCapability cap;
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription);
cap.videoType = ConvertFourCCToVideoType(fourcc);
CMVideoDimensions dimensions =
CMVideoFormatDescriptionGetDimensions(format.formatDescription);
cap.width = dimensions.width;
cap.height = dimensions.height;
for (AVFrameRateRange* range in format.videoSupportedFrameRateRanges) {
cap.maxFPS = ConvertAVFrameRateToCapabilityFPS(range.maxFrameRate);
capabilities.push_back(cap);
}
if (capabilities.empty()) {
cap.maxFPS = 30;
capabilities.push_back(cap);
}
}
}
}
} // namespace webrtc::videocapturemodule

View File

@ -14,11 +14,12 @@
#import <AVFoundation/AVFoundation.h>
#include "modules/video_capture/video_capture_defines.h"
#include "device_info.h"
@interface DeviceInfoIosObjC : NSObject {
NSArray* _observers;
NSLock* _lock;
webrtc::videocapturemodule::DeviceInfoIos* _owner;
webrtc::VideoCaptureModule::DeviceInfo* _owner;
}
+ (int)captureDeviceCount;
@ -29,7 +30,7 @@
+ (NSString*)deviceNameForUniqueId:(NSString*)uniqueId;
+ (webrtc::VideoCaptureCapability)capabilityForPreset:(NSString*)preset;
- (void)registerOwner:(webrtc::videocapturemodule::DeviceInfoIos*)owner;
- (void)registerOwner:(webrtc::VideoCaptureModule::DeviceInfo*)owner;
- (void)configureObservers;
@end

View File

@ -15,7 +15,6 @@
#import <AVFoundation/AVFoundation.h>
#import "device_info_objc.h"
#include "modules/video_capture/video_capture_config.h"
@implementation DeviceInfoIosObjC
@ -30,7 +29,7 @@
- (void)dealloc {
}
- (void)registerOwner:(DeviceInfoIos*)owner {
- (void)registerOwner:(webrtc::VideoCaptureModule::DeviceInfo*)owner {
[_lock lock];
if (!_owner && owner) {
[self configureObservers];

View File

@ -11,6 +11,7 @@
#ifndef MODULES_VIDEO_CAPTURE_OBJC_RTC_VIDEO_CAPTURE_OBJC_H_
#define MODULES_VIDEO_CAPTURE_OBJC_RTC_VIDEO_CAPTURE_OBJC_H_
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#ifdef WEBRTC_IOS
# import <UIKit/UIKit.h>

View File

@ -16,8 +16,7 @@
@class RTCVideoCaptureIosObjC;
namespace webrtc {
namespace videocapturemodule {
namespace webrtc::videocapturemodule {
class VideoCaptureIos : public VideoCaptureImpl {
public:
VideoCaptureIos();
@ -37,7 +36,6 @@ class VideoCaptureIos : public VideoCaptureImpl {
VideoCaptureCapability capability_;
};
} // namespace videocapturemodule
} // namespace webrtc
} // namespace webrtc::videocapturemodule
#endif // MODULES_VIDEO_CAPTURE_OBJC_VIDEO_CAPTURE_H_

View File

@ -16,11 +16,17 @@
#include "rtc_video_capture_objc.h"
#include "rtc_base/ref_counted_object.h"
#include "api/scoped_refptr.h"
#include "video_capture_avfoundation.h"
#include "mozilla/StaticPrefs_media.h"
using namespace mozilla;
using namespace webrtc;
using namespace videocapturemodule;
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(const char* deviceUniqueIdUTF8) {
if (StaticPrefs::media_getusermedia_camera_macavf_enabled_AtStartup()) {
return VideoCaptureAvFoundation::Create(deviceUniqueIdUTF8);
}
return VideoCaptureIos::Create(deviceUniqueIdUTF8);
}

View File

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_MEDIA_SYSTEMSERVICES_OBJC_VIDEO_CAPTURE_VIDEO_CAPTURE2_H_
#define DOM_MEDIA_SYSTEMSERVICES_OBJC_VIDEO_CAPTURE_VIDEO_CAPTURE2_H_
#import "components/capturer/RTCCameraVideoCapturer.h"
#include "api/sequence_checker.h"
#include "modules/video_capture/video_capture_impl.h"
#include "mozilla/Maybe.h"
@class VideoCaptureAdapter;
namespace webrtc::videocapturemodule {
/**
* VideoCaptureImpl implementation of the libwebrtc ios/mac sdk camera backend.
* Single threaded except for OnFrame() that happens on a platform callback thread.
*/
class VideoCaptureAvFoundation : public VideoCaptureImpl {
public:
VideoCaptureAvFoundation(AVCaptureDevice* _Nonnull aDevice);
virtual ~VideoCaptureAvFoundation();
static rtc::scoped_refptr<VideoCaptureModule> Create(const char* _Nullable aDeviceUniqueIdUTF8);
// Implementation of VideoCaptureImpl. Single threaded.
int32_t StartCapture(const VideoCaptureCapability& aCapability) override;
int32_t StopCapture() override;
bool CaptureStarted() override;
int32_t CaptureSettings(VideoCaptureCapability& aSettings) override;
// Callback. This can be called on any thread.
int32_t OnFrame(webrtc::VideoFrame& aFrame) MOZ_EXCLUDES(api_lock_);
private:
SequenceChecker mChecker;
AVCaptureDevice* _Nonnull mDevice RTC_GUARDED_BY(mChecker);
VideoCaptureAdapter* _Nonnull mAdapter RTC_GUARDED_BY(mChecker);
RTC_OBJC_TYPE(RTCCameraVideoCapturer) * _Nullable mCapturer RTC_GUARDED_BY(mChecker);
mozilla::Maybe<VideoCaptureCapability> mCapability RTC_GUARDED_BY(mChecker);
};
} // namespace webrtc::videocapturemodule
@interface VideoCaptureAdapter : NSObject <RTC_OBJC_TYPE (RTCVideoCapturerDelegate)>
@property(nonatomic) webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable capturer;
@end
#endif

View File

@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "video_capture_avfoundation.h"
#import "api/video_frame_buffer/RTCNativeI420Buffer+Private.h"
#import "base/RTCI420Buffer.h"
#import "base/RTCVideoFrame.h"
#import "base/RTCVideoFrameBuffer.h"
#import "components/capturer/RTCCameraVideoCapturer.h"
#import "helpers/NSString+StdString.h"
#include "api/scoped_refptr.h"
#include "api/video/video_rotation.h"
#include "device_info_avfoundation.h"
#include "modules/video_capture/video_capture_defines.h"
#include "mozilla/Assertions.h"
#include "rtc_base/time_utils.h"
using namespace mozilla;
using namespace webrtc::videocapturemodule;
namespace {
webrtc::VideoRotation ToNativeRotation(RTCVideoRotation aRotation) {
switch (aRotation) {
case RTCVideoRotation_0:
return webrtc::kVideoRotation_0;
case RTCVideoRotation_90:
return webrtc::kVideoRotation_90;
case RTCVideoRotation_180:
return webrtc::kVideoRotation_180;
case RTCVideoRotation_270:
return webrtc::kVideoRotation_270;
default:
MOZ_CRASH_UNSAFE_PRINTF("Unexpected rotation %d", static_cast<int>(aRotation));
return webrtc::kVideoRotation_0;
}
}
AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
webrtc::VideoCaptureCapability aCapability) {
for (AVCaptureDeviceFormat* format in [aDevice formats]) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
if (dimensions.width != aCapability.width) {
continue;
}
if (dimensions.height != aCapability.height) {
continue;
}
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription);
if (aCapability.videoType != DeviceInfoAvFoundation::ConvertFourCCToVideoType(fourcc)) {
continue;
}
if ([format.videoSupportedFrameRateRanges
indexOfObjectPassingTest:^BOOL(AVFrameRateRange* _Nonnull obj, NSUInteger idx,
BOOL* _Nonnull stop) {
return static_cast<BOOL>(DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
obj.maxFrameRate) == aCapability.maxFPS);
}] == NSNotFound) {
continue;
}
return format;
}
return nullptr;
}
} // namespace
@implementation VideoCaptureAdapter
@synthesize capturer = _capturer;
- (void)capturer:(RTC_OBJC_TYPE(RTCVideoCapturer) * _Nonnull)capturer
didCaptureVideoFrame:(RTC_OBJC_TYPE(RTCVideoFrame) * _Nonnull)frame {
const int64_t timestamp_us = frame.timeStampNs / rtc::kNumNanosecsPerMicrosec;
RTC_OBJC_TYPE(RTCI420Buffer)* buffer = [[frame buffer] toI420];
// Accessing the (intended-to-be-private) native buffer directly is hacky but lets us skip two
// copies
rtc::scoped_refptr<webrtc::I420BufferInterface> nativeBuffer = [buffer nativeI420Buffer];
webrtc::VideoFrame nativeFrame = webrtc::VideoFrame::Builder()
.set_video_frame_buffer(nativeBuffer)
.set_rotation(ToNativeRotation(frame.rotation))
.set_timestamp_us(timestamp_us)
.build();
_capturer->OnFrame(nativeFrame);
}
@end
namespace webrtc::videocapturemodule {
VideoCaptureAvFoundation::VideoCaptureAvFoundation(AVCaptureDevice* _Nonnull aDevice)
: mDevice(aDevice), mAdapter([[VideoCaptureAdapter alloc] init]), mCapturer(nullptr) {
{
const char* uniqueId = [[aDevice uniqueID] UTF8String];
size_t len = strlen(uniqueId);
_deviceUniqueId = new (std::nothrow) char[len + 1];
if (_deviceUniqueId) {
memcpy(_deviceUniqueId, uniqueId, len + 1);
}
}
mAdapter.capturer = this;
mCapturer = [[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc] initWithDelegate:mAdapter];
}
VideoCaptureAvFoundation::~VideoCaptureAvFoundation() = default;
/* static */
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureAvFoundation::Create(
const char* _Nullable aDeviceUniqueIdUTF8) {
std::string uniqueId(aDeviceUniqueIdUTF8);
for (AVCaptureDevice* device in [RTCCameraVideoCapturer captureDevices]) {
if ([NSString stdStringForString:device.uniqueID] == uniqueId) {
rtc::scoped_refptr<VideoCaptureModule> module(
new rtc::RefCountedObject<VideoCaptureAvFoundation>(device));
return module;
}
}
return nullptr;
}
int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCapability) {
RTC_DCHECK_RUN_ON(&mChecker);
if (AVCaptureDeviceFormat* format = FindFormat(mDevice, aCapability)) {
mCapability = Some(aCapability);
[mCapturer startCaptureWithDevice:mDevice
format:format
fps:aCapability.maxFPS
completionHandler:nullptr];
return 0;
}
return -1;
}
int32_t VideoCaptureAvFoundation::StopCapture() {
RTC_DCHECK_RUN_ON(&mChecker);
mCapability = Nothing();
[mCapturer stopCapture];
return 0;
}
bool VideoCaptureAvFoundation::CaptureStarted() {
RTC_DCHECK_RUN_ON(&mChecker);
return mCapability.isSome();
}
int32_t VideoCaptureAvFoundation::CaptureSettings(VideoCaptureCapability& aSettings) {
MOZ_CRASH("Unexpected call");
return -1;
}
int32_t VideoCaptureAvFoundation::OnFrame(webrtc::VideoFrame& aFrame) {
MutexLock lock(&api_lock_);
return DeliverCapturedFrame(aFrame);
}
} // namespace webrtc::videocapturemodule

View File

@ -10355,6 +10355,13 @@
value: @IS_ANDROID@
mirror: always
# Use the libwebrtc AVFoundation camera backend on Mac by default. When
# disabled, an older forked capture module is used.
- name: media.getusermedia.camera.macavf.enabled
type: bool
value: false
mirror: once
# WebRTC prefs follow
# Enables RTCPeerConnection support. Note that, when true, this pref enables