Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross-platform RTCMTLVideoView for both iOS / macOS #40

Merged
merged 4 commits into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions sdk/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -617,17 +617,13 @@ if (is_ios || is_mac) {
"Metal.framework",
"MetalKit.framework",
]
if (is_ios) {
if (is_ios || is_mac) {
sources += [
"objc/components/renderer/metal/RTCMTLVideoView.h",
"objc/components/renderer/metal/RTCMTLVideoView.m",
]
}
if (is_mac) {
sources += [
"objc/components/renderer/metal/RTCMTLNSVideoView.h",
"objc/components/renderer/metal/RTCMTLNSVideoView.m",
]
frameworks += [ "AppKit.framework" ]
}
deps = [
Expand Down Expand Up @@ -1553,6 +1549,7 @@ if (is_ios || is_mac) {
"objc/components/capturer/RTCDesktopCapturer.h",
"objc/components/capturer/RTCDesktopSource.h",
"objc/components/capturer/RTCDesktopMediaList.h",
"objc/components/renderer/metal/RTCMTLVideoView.h",
"objc/components/renderer/metal/RTCMTLNSVideoView.h",
"objc/components/renderer/opengl/RTCNSGLVideoView.h",
"objc/components/renderer/opengl/RTCVideoViewShading.h",
Expand Down
16 changes: 2 additions & 14 deletions sdk/objc/components/renderer/metal/RTCMTLNSVideoView.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,5 @@
* be found in the AUTHORS file in the root of the source tree.
*/

#import <AppKit/AppKit.h>

#import "RTCVideoRenderer.h"

NS_AVAILABLE_MAC(10.11)

RTC_OBJC_EXPORT
@interface RTC_OBJC_TYPE (RTCMTLNSVideoView) : NSView <RTC_OBJC_TYPE(RTCVideoRenderer)>

@property(nonatomic, weak) id<RTC_OBJC_TYPE(RTCVideoViewDelegate)> delegate;

+ (BOOL)isMetalAvailable;

@end
// Deprecated: Use RTCMTLVideoView instead
@compatibility_alias RTCMTLNSVideoView RTCMTLVideoView;
122 changes: 0 additions & 122 deletions sdk/objc/components/renderer/metal/RTCMTLNSVideoView.m

This file was deleted.

22 changes: 20 additions & 2 deletions sdk/objc/components/renderer/metal/RTCMTLVideoView.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

#import <Foundation/Foundation.h>

#if TARGET_OS_OSX
#import <AppKit/AppKit.h>
#endif

#import "RTCMacros.h"
#import "RTCVideoFrame.h"
#import "RTCVideoRenderer.h"
Expand All @@ -22,22 +26,36 @@ NS_ASSUME_NONNULL_BEGIN
* It has id<RTCVideoRenderer> property that renders video frames in the view's
* bounds using Metal.
*/
#if TARGET_OS_IPHONE
NS_CLASS_AVAILABLE_IOS(9)
#elif TARGET_OS_OSX
NS_AVAILABLE_MAC(10.11)
#endif

RTC_OBJC_EXPORT
@interface RTC_OBJC_TYPE (RTCMTLVideoView) : UIView<RTC_OBJC_TYPE(RTCVideoRenderer)>
@interface RTC_OBJC_TYPE (RTCMTLVideoView) :

#if TARGET_OS_IPHONE
UIView<RTC_OBJC_TYPE(RTCVideoRenderer)>
#elif TARGET_OS_OSX
NSView<RTC_OBJC_TYPE(RTCVideoRenderer)>
#endif

@property(nonatomic, weak) id<RTC_OBJC_TYPE(RTCVideoViewDelegate)> delegate;

#if TARGET_OS_IPHONE
@property(nonatomic) UIViewContentMode videoContentMode;
#endif

/** @abstract Enables/disables rendering.
*/
@property(nonatomic, getter=isEnabled) BOOL enabled;

/** @abstract Wrapped RTCVideoRotation, or nil.
*/
@property(nonatomic, nullable) NSValue* rotationOverride;
@property(nonatomic, assign, nullable) NSValue* rotationOverride;

+ (BOOL)isMetalAvailable;

@end

Expand Down
69 changes: 55 additions & 14 deletions sdk/objc/components/renderer/metal/RTCMTLVideoView.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ @implementation RTC_OBJC_TYPE (RTCMTLVideoView)
@synthesize lastFrameTimeNs = _lastFrameTimeNs;
@synthesize rotationOverride = _rotationOverride;

+ (BOOL)isMetalAvailable {
#if TARGET_OS_IPHONE
return MTLCreateSystemDefaultDevice() != nil;
#elif TARGET_OS_OSX
return [MTLCopyAllDevices() count] > 0;
#endif
}

- (instancetype)initWithFrame:(CGRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
Expand All @@ -75,20 +83,18 @@ - (void)setEnabled:(BOOL)enabled {
self.metalView.paused = !enabled;
}

#if TARGET_OS_IPHONE
- (UIViewContentMode)videoContentMode {
return self.metalView.contentMode;
}

- (void)setVideoContentMode:(UIViewContentMode)mode {
self.metalView.contentMode = mode;
}
#endif

#pragma mark - Private

+ (BOOL)isMetalAvailable {
return MTLCreateSystemDefaultDevice() != nil;
}

+ (MTKView *)createMetalView:(CGRect)frame {
return [[MTKViewClass alloc] initWithFrame:frame];
}
Expand All @@ -102,7 +108,7 @@ + (RTCMTLI420Renderer *)createI420Renderer {
}

+ (RTCMTLRGBRenderer *)createRGBRenderer {
return [[RTCMTLRGBRenderer alloc] init];
return [[RTCMTLRGBRendererClass alloc] init];
}

- (void)configure {
Expand All @@ -111,19 +117,24 @@ - (void)configure {

self.metalView = [RTC_OBJC_TYPE(RTCMTLVideoView) createMetalView:self.bounds];
self.metalView.delegate = self;
#if TARGET_OS_IPHONE
self.metalView.contentMode = UIViewContentModeScaleAspectFill;
#elif TARGET_OS_OSX
self.metalView.layerContentsPlacement = NSViewLayerContentsPlacementScaleProportionallyToFit;
#endif

[self addSubview:self.metalView];
self.videoFrameSize = CGSizeZero;
}

#if TARGET_OS_IPHONE
- (void)setMultipleTouchEnabled:(BOOL)multipleTouchEnabled {
[super setMultipleTouchEnabled:multipleTouchEnabled];
self.metalView.multipleTouchEnabled = multipleTouchEnabled;
[super setMultipleTouchEnabled:multipleTouchEnabled];
self.metalView.multipleTouchEnabled = multipleTouchEnabled;
}
#endif

- (void)layoutSubviews {
[super layoutSubviews];

- (void)performLayout {
CGRect bounds = self.bounds;
self.metalView.frame = bounds;
if (!CGSizeEqualToSize(self.videoFrameSize, CGSizeZero)) {
Expand Down Expand Up @@ -203,10 +214,10 @@ - (void)setRotationOverride:(NSValue *)rotationOverride {
[self setNeedsLayout];
}

- (RTCVideoRotation)frameRotation {
- (RTCVideoRotation)videoRotation {
if (self.rotationOverride) {
RTCVideoRotation rotation;
if (@available(iOS 11, *)) {
if (@available(iOS 11, macos 10.13, *)) {
[self.rotationOverride getValue:&rotation size:sizeof(rotation)];
} else {
[self.rotationOverride getValue:&rotation];
Expand All @@ -220,10 +231,10 @@ - (RTCVideoRotation)frameRotation {
- (CGSize)drawableSize {
// Flip width/height if the rotations are not the same.
CGSize videoFrameSize = self.videoFrameSize;
RTCVideoRotation frameRotation = [self frameRotation];
RTCVideoRotation videoRotation = [self videoRotation];

BOOL useLandscape =
(frameRotation == RTCVideoRotation_0) || (frameRotation == RTCVideoRotation_180);
(videoRotation == RTCVideoRotation_0) || (videoRotation == RTCVideoRotation_180);
BOOL sizeIsLandscape = (self.videoFrame.rotation == RTCVideoRotation_0) ||
(self.videoFrame.rotation == RTCVideoRotation_180);

Expand Down Expand Up @@ -259,7 +270,37 @@ - (void)renderFrame:(nullable RTC_OBJC_TYPE(RTCVideoFrame) *)frame {
RTCLogInfo(@"Incoming frame is nil. Exiting render callback.");
return;
}

#if TARGET_OS_IPHONE
self.videoFrame = frame;
#elif TARGET_OS_OSX
// Rendering native CVPixelBuffer is not supported on OS X.
BOOL useI420 = NO;
if ([frame.buffer isKindOfClass:[RTC_OBJC_TYPE(RTCCVPixelBuffer) class]]) {
RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer = (RTC_OBJC_TYPE(RTCCVPixelBuffer) *)frame.buffer;
const OSType pixelFormat = CVPixelBufferGetPixelFormatType(buffer.pixelBuffer);
useI420 = pixelFormat == kCVPixelFormatType_32BGRA || pixelFormat == kCVPixelFormatType_32ARGB;
}
self.videoFrame = useI420 ? [frame newI420VideoFrame] : frame;
#endif
}

#pragma mark - Cross platform

#if TARGET_OS_IPHONE
- (void)layoutSubviews {
[super layoutSubviews];
[self performLayout];
}
#elif TARGET_OS_OSX
- (void)layout {
[super layout];
[self performLayout];
}

- (void)setNeedsLayout {
self.needsLayout = YES;
}
#endif

@end