Skip to content

Commit 8285e1f

Browse files
hiroshihoriecloudwebrtc
authored andcommitted
Cross-platform RTCMTLVideoView for both iOS / macOS (#40)
* impl * simplify * tweaks * fix osx rendering
1 parent be5a771 commit 8285e1f

File tree

5 files changed

+79
-157
lines changed

5 files changed

+79
-157
lines changed

sdk/BUILD.gn

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -638,17 +638,13 @@ if (is_ios || is_mac) {
638638
"Metal.framework",
639639
"MetalKit.framework",
640640
]
641-
if (is_ios) {
641+
if (is_ios || is_mac) {
642642
sources += [
643643
"objc/components/renderer/metal/RTCMTLVideoView.h",
644644
"objc/components/renderer/metal/RTCMTLVideoView.m",
645645
]
646646
}
647647
if (is_mac) {
648-
sources += [
649-
"objc/components/renderer/metal/RTCMTLNSVideoView.h",
650-
"objc/components/renderer/metal/RTCMTLNSVideoView.m",
651-
]
652648
frameworks += [ "AppKit.framework" ]
653649
}
654650
deps = [
@@ -1552,6 +1548,7 @@ if (is_ios || is_mac) {
15521548
"objc/components/capturer/RTCDesktopCapturer.h",
15531549
"objc/components/capturer/RTCDesktopSource.h",
15541550
"objc/components/capturer/RTCDesktopMediaList.h",
1551+
"objc/components/renderer/metal/RTCMTLVideoView.h",
15551552
"objc/components/renderer/metal/RTCMTLNSVideoView.h",
15561553
"objc/components/renderer/opengl/RTCNSGLVideoView.h",
15571554
"objc/components/renderer/opengl/RTCVideoViewShading.h",

sdk/objc/components/renderer/metal/RTCMTLNSVideoView.h

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,5 @@
88
* be found in the AUTHORS file in the root of the source tree.
99
*/
1010

11-
#import <AppKit/AppKit.h>
12-
13-
#import "RTCVideoRenderer.h"
14-
15-
NS_AVAILABLE_MAC(10.11)
16-
17-
RTC_OBJC_EXPORT
18-
@interface RTC_OBJC_TYPE (RTCMTLNSVideoView) : NSView <RTC_OBJC_TYPE(RTCVideoRenderer)>
19-
20-
@property(nonatomic, weak) id<RTC_OBJC_TYPE(RTCVideoViewDelegate)> delegate;
21-
22-
+ (BOOL)isMetalAvailable;
23-
24-
@end
11+
// Deprecated: Use RTCMTLVideoView instead
12+
@compatibility_alias RTCMTLNSVideoView RTCMTLVideoView;

sdk/objc/components/renderer/metal/RTCMTLNSVideoView.m

Lines changed: 0 additions & 122 deletions
This file was deleted.

sdk/objc/components/renderer/metal/RTCMTLVideoView.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
#import <Foundation/Foundation.h>
1212

13+
#if TARGET_OS_OSX
14+
#import <AppKit/AppKit.h>
15+
#endif
16+
1317
#import "RTCMacros.h"
1418
#import "RTCVideoFrame.h"
1519
#import "RTCVideoRenderer.h"
@@ -22,22 +26,36 @@ NS_ASSUME_NONNULL_BEGIN
2226
* It has id<RTCVideoRenderer> property that renders video frames in the view's
2327
* bounds using Metal.
2428
*/
29+
#if TARGET_OS_IPHONE
2530
NS_CLASS_AVAILABLE_IOS(9)
31+
#elif TARGET_OS_OSX
32+
NS_AVAILABLE_MAC(10.11)
33+
#endif
2634

2735
RTC_OBJC_EXPORT
28-
@interface RTC_OBJC_TYPE (RTCMTLVideoView) : UIView<RTC_OBJC_TYPE(RTCVideoRenderer)>
36+
@interface RTC_OBJC_TYPE (RTCMTLVideoView) :
37+
38+
#if TARGET_OS_IPHONE
39+
UIView<RTC_OBJC_TYPE(RTCVideoRenderer)>
40+
#elif TARGET_OS_OSX
41+
NSView<RTC_OBJC_TYPE(RTCVideoRenderer)>
42+
#endif
2943

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

46+
#if TARGET_OS_IPHONE
3247
@property(nonatomic) UIViewContentMode videoContentMode;
48+
#endif
3349

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

3854
/** @abstract Wrapped RTCVideoRotation, or nil.
3955
*/
40-
@property(nonatomic, nullable) NSValue* rotationOverride;
56+
@property(nonatomic, assign, nullable) NSValue* rotationOverride;
57+
58+
+ (BOOL)isMetalAvailable;
4159

4260
@end
4361

sdk/objc/components/renderer/metal/RTCMTLVideoView.m

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ @implementation RTC_OBJC_TYPE (RTCMTLVideoView)
5151
@synthesize lastFrameTimeNs = _lastFrameTimeNs;
5252
@synthesize rotationOverride = _rotationOverride;
5353

54+
+ (BOOL)isMetalAvailable {
55+
#if TARGET_OS_IPHONE
56+
return MTLCreateSystemDefaultDevice() != nil;
57+
#elif TARGET_OS_OSX
58+
return [MTLCopyAllDevices() count] > 0;
59+
#endif
60+
}
61+
5462
- (instancetype)initWithFrame:(CGRect)frameRect {
5563
self = [super initWithFrame:frameRect];
5664
if (self) {
@@ -75,20 +83,18 @@ - (void)setEnabled:(BOOL)enabled {
7583
self.metalView.paused = !enabled;
7684
}
7785

86+
#if TARGET_OS_IPHONE
7887
- (UIViewContentMode)videoContentMode {
7988
return self.metalView.contentMode;
8089
}
8190

8291
- (void)setVideoContentMode:(UIViewContentMode)mode {
8392
self.metalView.contentMode = mode;
8493
}
94+
#endif
8595

8696
#pragma mark - Private
8797

88-
+ (BOOL)isMetalAvailable {
89-
return MTLCreateSystemDefaultDevice() != nil;
90-
}
91-
9298
+ (MTKView *)createMetalView:(CGRect)frame {
9399
return [[MTKViewClass alloc] initWithFrame:frame];
94100
}
@@ -102,7 +108,7 @@ + (RTCMTLI420Renderer *)createI420Renderer {
102108
}
103109

104110
+ (RTCMTLRGBRenderer *)createRGBRenderer {
105-
return [[RTCMTLRGBRenderer alloc] init];
111+
return [[RTCMTLRGBRendererClass alloc] init];
106112
}
107113

108114
- (void)configure {
@@ -111,19 +117,24 @@ - (void)configure {
111117

112118
self.metalView = [RTC_OBJC_TYPE(RTCMTLVideoView) createMetalView:self.bounds];
113119
self.metalView.delegate = self;
120+
#if TARGET_OS_IPHONE
114121
self.metalView.contentMode = UIViewContentModeScaleAspectFill;
122+
#elif TARGET_OS_OSX
123+
self.metalView.layerContentsPlacement = NSViewLayerContentsPlacementScaleProportionallyToFit;
124+
#endif
125+
115126
[self addSubview:self.metalView];
116127
self.videoFrameSize = CGSizeZero;
117128
}
118129

130+
#if TARGET_OS_IPHONE
119131
- (void)setMultipleTouchEnabled:(BOOL)multipleTouchEnabled {
120-
[super setMultipleTouchEnabled:multipleTouchEnabled];
121-
self.metalView.multipleTouchEnabled = multipleTouchEnabled;
132+
[super setMultipleTouchEnabled:multipleTouchEnabled];
133+
self.metalView.multipleTouchEnabled = multipleTouchEnabled;
122134
}
135+
#endif
123136

124-
- (void)layoutSubviews {
125-
[super layoutSubviews];
126-
137+
- (void)performLayout {
127138
CGRect bounds = self.bounds;
128139
self.metalView.frame = bounds;
129140
if (!CGSizeEqualToSize(self.videoFrameSize, CGSizeZero)) {
@@ -203,10 +214,10 @@ - (void)setRotationOverride:(NSValue *)rotationOverride {
203214
[self setNeedsLayout];
204215
}
205216

206-
- (RTCVideoRotation)frameRotation {
217+
- (RTCVideoRotation)videoRotation {
207218
if (self.rotationOverride) {
208219
RTCVideoRotation rotation;
209-
if (@available(iOS 11, *)) {
220+
if (@available(iOS 11, macos 10.13, *)) {
210221
[self.rotationOverride getValue:&rotation size:sizeof(rotation)];
211222
} else {
212223
[self.rotationOverride getValue:&rotation];
@@ -220,10 +231,10 @@ - (RTCVideoRotation)frameRotation {
220231
- (CGSize)drawableSize {
221232
// Flip width/height if the rotations are not the same.
222233
CGSize videoFrameSize = self.videoFrameSize;
223-
RTCVideoRotation frameRotation = [self frameRotation];
234+
RTCVideoRotation videoRotation = [self videoRotation];
224235

225236
BOOL useLandscape =
226-
(frameRotation == RTCVideoRotation_0) || (frameRotation == RTCVideoRotation_180);
237+
(videoRotation == RTCVideoRotation_0) || (videoRotation == RTCVideoRotation_180);
227238
BOOL sizeIsLandscape = (self.videoFrame.rotation == RTCVideoRotation_0) ||
228239
(self.videoFrame.rotation == RTCVideoRotation_180);
229240

@@ -259,7 +270,37 @@ - (void)renderFrame:(nullable RTC_OBJC_TYPE(RTCVideoFrame) *)frame {
259270
RTCLogInfo(@"Incoming frame is nil. Exiting render callback.");
260271
return;
261272
}
273+
274+
#if TARGET_OS_IPHONE
262275
self.videoFrame = frame;
276+
#elif TARGET_OS_OSX
277+
// Rendering native CVPixelBuffer is not supported on OS X.
278+
BOOL useI420 = NO;
279+
if ([frame.buffer isKindOfClass:[RTC_OBJC_TYPE(RTCCVPixelBuffer) class]]) {
280+
RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer = (RTC_OBJC_TYPE(RTCCVPixelBuffer) *)frame.buffer;
281+
const OSType pixelFormat = CVPixelBufferGetPixelFormatType(buffer.pixelBuffer);
282+
useI420 = pixelFormat == kCVPixelFormatType_32BGRA || pixelFormat == kCVPixelFormatType_32ARGB;
283+
}
284+
self.videoFrame = useI420 ? [frame newI420VideoFrame] : frame;
285+
#endif
286+
}
287+
288+
#pragma mark - Cross platform
289+
290+
#if TARGET_OS_IPHONE
291+
- (void)layoutSubviews {
292+
[super layoutSubviews];
293+
[self performLayout];
294+
}
295+
#elif TARGET_OS_OSX
296+
- (void)layout {
297+
[super layout];
298+
[self performLayout];
299+
}
300+
301+
- (void)setNeedsLayout {
302+
self.needsLayout = YES;
263303
}
304+
#endif
264305

265306
@end

0 commit comments

Comments
 (0)