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

Ability to override VideoView's rotation (iOS) #122

Merged
merged 2 commits into from
Aug 25, 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
3 changes: 3 additions & 0 deletions Sources/LiveKit/Types/VideoRotation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import WebRTC

public typealias VideoRotation = RTCVideoRotation
65 changes: 45 additions & 20 deletions Sources/LiveKit/Views/VideoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ public class VideoView: NativeView, MulticastDelegateCapable, Loggable {
set { _state.mutate { $0.mirrorMode = newValue } }
}

/// Force video to be rotated to preferred ``VideoRotation``
/// Currently, only for iOS.
public var rotationOverride: VideoRotation? {
get { _state.rotationOverride }
set { _state.mutate { $0.rotationOverride = newValue } }
}

/// Calls addRenderer and/or removeRenderer internally for convenience.
public weak var track: VideoTrack? {
get { _state.track }
Expand Down Expand Up @@ -113,6 +120,7 @@ public class VideoView: NativeView, MulticastDelegateCapable, Loggable {
var didLayout: Bool = false
var layoutMode: LayoutMode = .fill
var mirrorMode: MirrorMode = .auto
var rotationOverride: VideoRotation? // = ._90

var debugMode: Bool = false

Expand Down Expand Up @@ -245,6 +253,7 @@ public class VideoView: NativeView, MulticastDelegateCapable, Loggable {
if state.debugMode != oldState.debugMode ||
state.layoutMode != oldState.layoutMode ||
state.mirrorMode != oldState.mirrorMode ||
state.rotationOverride != oldState.rotationOverride ||
state.didRenderFirstFrame != oldState.didRenderFirstFrame ||
shouldRenderDidUpdate || trackDidUpdate {

Expand Down Expand Up @@ -347,8 +356,6 @@ public class VideoView: NativeView, MulticastDelegateCapable, Loggable {
width: size.width,
height: size.height)

nativeRenderer?.frame = rendererFrame

if _state.rendererSize != rendererFrame.size {
// mutate if required
_state.mutate { $0.rendererSize = rendererFrame.size }
Expand All @@ -358,25 +365,36 @@ public class VideoView: NativeView, MulticastDelegateCapable, Loggable {
// nativeRenderer.layer!.borderColor = NSColor.red.cgColor
// nativeRenderer.layer!.borderWidth = 3

if let nr = nativeRenderer {

if shouldMirror() {
#if os(macOS)
// this is required for macOS
nr.wantsLayer = true
nr.set(anchorPoint: CGPoint(x: 0.5, y: 0.5))
nr.layer!.sublayerTransform = VideoView.mirrorTransform
#elseif os(iOS)
nr.layer.transform = VideoView.mirrorTransform
#endif
guard let nativeRenderer = nativeRenderer else { return }

nativeRenderer.frame = rendererFrame

#if os(iOS)
if let mtlVideoView = nativeRenderer as? RTCMTLVideoView {
if let rotationOverride = _state.rotationOverride {
mtlVideoView.rotationOverride = NSNumber(value: rotationOverride.rawValue)
} else {
#if os(macOS)
nr.layer?.sublayerTransform = CATransform3DIdentity
#elseif os(iOS)
nr.layer.transform = CATransform3DIdentity
#endif
mtlVideoView.rotationOverride = nil
}
}
#endif

if shouldMirror() {
#if os(macOS)
// this is required for macOS
nativeRenderer.wantsLayer = true
nativeRenderer.set(anchorPoint: CGPoint(x: 0.5, y: 0.5))
nativeRenderer.layer!.sublayerTransform = VideoView.mirrorTransform
#elseif os(iOS)
nativeRenderer.layer.transform = VideoView.mirrorTransform
#endif
} else {
#if os(macOS)
nativeRenderer.layer?.sublayerTransform = CATransform3DIdentity
#elseif os(iOS)
nativeRenderer.layer.transform = CATransform3DIdentity
#endif
}
}
}

Expand Down Expand Up @@ -468,9 +486,15 @@ extension VideoView: RTCVideoRenderer {

if let frame = frame {

#if os(iOS)
let rotation = _state.rotationOverride ?? frame.rotation
#elseif os(macOS)
let rotation = frame.rotation
#endif

let dimensions = Dimensions(width: frame.width,
height: frame.height)
.apply(rotation: frame.rotation)
.apply(rotation: rotation)

guard dimensions.isRenderSafe else {
log("skipping render for dimension \(dimensions)", .warning)
Expand Down Expand Up @@ -566,7 +590,8 @@ extension VideoView {
#else
// macOS --------------------
logger.log("Using RTCMTLNSVideoView for VideoView's Renderer", type: VideoView.self)
result = RTCMTLNSVideoView()
let mtlView = RTCMTLNSVideoView()
result = mtlView
#endif
#endif

Expand Down