Skip to content

Commit

Permalink
Cross-platform RTCMTLVideoView for both iOS / macOS (#40)
Browse files Browse the repository at this point in the history
* impl

* simplify

* tweaks

* fix osx rendering
  • Loading branch information
hiroshihorie authored and cloudwebrtc committed Jun 6, 2023
1 parent be5a771 commit 8285e1f
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 157 deletions.
7 changes: 2 additions & 5 deletions sdk/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -638,17 +638,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 @@ -1552,6 +1548,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

0 comments on commit 8285e1f

Please sign in to comment.