Skip to content

Commit

Permalink
Ability to override VideoView's rotation (iOS) (#122)
Browse files Browse the repository at this point in the history
* impl

* note
  • Loading branch information
hiroshihorie authored Aug 25, 2022
1 parent f05dc69 commit aa3902f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 20 deletions.
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

0 comments on commit aa3902f

Please sign in to comment.