Skip to content

Add MetalView retinaScaleFactor handling #629

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

Closed
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
25 changes: 17 additions & 8 deletions Sources/LiveKit/Views/VideoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@
get { _state.rotationOverride }
set { _state.mutate { $0.rotationOverride = newValue } }
}

Check warning on line 96 in Sources/LiveKit/Views/VideoView.swift

View workflow job for this annotation

GitHub Actions / swiftformat

Remove trailing space at end of a line. (trailingSpace)
/// Updates internal MTKView to use proper contentScaleFactor
public var retinaScaleFactor: CGFloat {
get { _state.retinaScaleFactor }
set { _state.mutate { $0.retinaScaleFactor = newValue } }
}

/// Calls addRenderer and/or removeRenderer internally for convenience.
@objc
Expand Down Expand Up @@ -200,6 +206,7 @@
var mirrorMode: MirrorMode = .auto
var renderMode: RenderMode = .auto
var rotationOverride: VideoRotation?
var retinaScaleFactor: CGFloat = 1

var isDebugMode: Bool = false

Expand Down Expand Up @@ -270,6 +277,7 @@

let shouldRenderDidUpdate = newState.shouldRender != oldState.shouldRender
let renderModeDidUpdate = newState.renderMode != oldState.renderMode
let retinaScaleFactorDidUpdate = newState.retinaScaleFactor != oldState.retinaScaleFactor
let trackDidUpdate = !Self.track(oldState.track as? VideoTrack, isEqualWith: newState.track as? VideoTrack)

if trackDidUpdate || shouldRenderDidUpdate {
Expand All @@ -280,7 +288,7 @@
}

// Enter .main only if UI updates are required
if trackDidUpdate || shouldRenderDidUpdate || renderModeDidUpdate {
if trackDidUpdate || shouldRenderDidUpdate || renderModeDidUpdate || retinaScaleFactorDidUpdate {
self.mainSyncOrAsync {
var didReCreateNativeRenderer = false

Expand All @@ -298,7 +306,7 @@

// Set up new renderer if needed
if let track = newState.track as? VideoTrack, newState.shouldRender {
let nr = self.recreatePrimaryRenderer(for: newState.renderMode)
let nr = self.recreatePrimaryRenderer(for: newState.renderMode, retinaScaleFactor: newState.retinaScaleFactor)
didReCreateNativeRenderer = true

if let frame = track._state.videoFrame {
Expand All @@ -309,8 +317,8 @@
}
}

if renderModeDidUpdate, !didReCreateNativeRenderer {
self.recreatePrimaryRenderer(for: newState.renderMode)
if (renderModeDidUpdate || retinaScaleFactorDidUpdate), !didReCreateNativeRenderer {

Check warning on line 320 in Sources/LiveKit/Views/VideoView.swift

View workflow job for this annotation

GitHub Actions / swiftformat

Remove redundant parentheses. (redundantParens)
self.recreatePrimaryRenderer(for: newState.renderMode, retinaScaleFactor: newState.retinaScaleFactor)
}
}
}
Expand Down Expand Up @@ -526,11 +534,11 @@
}

@discardableResult
func recreatePrimaryRenderer(for renderMode: VideoView.RenderMode) -> NativeRendererView {
func recreatePrimaryRenderer(for renderMode: VideoView.RenderMode, retinaScaleFactor: CGFloat) -> NativeRendererView {
if !Thread.current.isMainThread { log("Must be called on main thread", .error) }

// create a new rendererView
let newView = VideoView.createNativeRendererView(for: renderMode)
let newView = VideoView.createNativeRendererView(for: renderMode, retinaScaleFactor: retinaScaleFactor)
addSubview(newView)

// keep the old rendererView
Expand Down Expand Up @@ -561,7 +569,7 @@
guard let _primaryRenderer else { return nil }

// Create renderer blow primary
let newView = VideoView.createNativeRendererView(for: _state.renderMode)
let newView = VideoView.createNativeRendererView(for: _state.renderMode, retinaScaleFactor: _state.retinaScaleFactor)
insertSubview(newView, belowSubview: _primaryRenderer)

// Copy frame from primary renderer
Expand Down Expand Up @@ -754,7 +762,7 @@
#endif
}

static func createNativeRendererView(for renderMode: VideoView.RenderMode) -> NativeRendererView {
static func createNativeRendererView(for renderMode: VideoView.RenderMode, retinaScaleFactor: CGFloat) -> NativeRendererView {
#if os(iOS) || os(macOS)
if case .sampleBuffer = renderMode {
logger.log("Using AVSampleBufferDisplayLayer for VideoView's Renderer", type: VideoView.self)
Expand All @@ -779,6 +787,7 @@
// https://developer.apple.com/documentation/metalkit/mtkview/1536027-preferredframespersecond
logger.log("preferredFramesPerSecond = 60", type: VideoView.self)
mtkView.preferredFramesPerSecond = 60
mtkView.contentScaleFactor = retinaScaleFactor

Check failure on line 790 in Sources/LiveKit/Views/VideoView.swift

View workflow job for this annotation

GitHub Actions / test (macos-15, 16.2, macOS)

value of type 'MTKView' has no member 'contentScaleFactor'

Check failure on line 790 in Sources/LiveKit/Views/VideoView.swift

View workflow job for this annotation

GitHub Actions / test (macos-13, 14.2, macOS)

value of type 'MTKView' has no member 'contentScaleFactor'

Check failure on line 790 in Sources/LiveKit/Views/VideoView.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, macOS)

value of type 'MTKView' has no member 'contentScaleFactor'
}

return result
Expand Down
Loading