Skip to content

Commit

Permalink
Optimize SampleBufferVideoRenderer (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
hiroshihorie authored Jul 29, 2024
1 parent de16a17 commit 9e3a152
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Sources/LiveKit/Protocols/Mirrorable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ import Foundation

// Internal only
protocol Mirrorable {
func set(mirrored: Bool)
func set(isMirrored: Bool)
}
71 changes: 43 additions & 28 deletions Sources/LiveKit/Views/SampleBufferVideoRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ internal import LiveKitWebRTC

class SampleBufferVideoRenderer: NativeView, Loggable {
public let sampleBufferDisplayLayer: AVSampleBufferDisplayLayer

private var firstFrameReceived = false
private var bufferTransform = CATransform3DIdentity
private var mirroredTransform = CATransform3DIdentity
private var displayLayerTransform: CATransform3D {
return CATransform3DConcat(bufferTransform, mirroredTransform)

private struct State {
var isMirrored: Bool = false
var videoRotation: VideoRotation = ._0
}

private let _state = StateSync(State())

override init(frame: CGRect) {
sampleBufferDisplayLayer = AVSampleBufferDisplayLayer()
super.init(frame: frame)
Expand All @@ -53,14 +53,16 @@ class SampleBufferVideoRenderer: NativeView, Loggable {
override func performLayout() {
super.performLayout()
sampleBufferDisplayLayer.frame = bounds

let (rotation, isMirrored) = _state.read { ($0.videoRotation, $0.isMirrored) }
sampleBufferDisplayLayer.transform = CATransform3D.from(rotation: rotation, isMirrored: isMirrored)

sampleBufferDisplayLayer.removeAllAnimations()
}
}

extension SampleBufferVideoRenderer: LKRTCVideoRenderer {
func setSize(_: CGSize) {
//
}
func setSize(_: CGSize) {}

func renderFrame(_ frame: LKRTCVideoFrame?) {
guard let frame else { return }
Expand All @@ -82,43 +84,56 @@ extension SampleBufferVideoRenderer: LKRTCVideoRenderer {
log("Failed to convert CVPixelBuffer to CMSampleBuffer", .error)
return
}

if !firstFrameReceived {
bufferTransform = .fromFrameRotation(frame)
updateSampleBufferTransform()
firstFrameReceived = true

let rotation = frame.rotation.toLKType()
let didUpdateRotation = _state.mutate {
let result = $0.videoRotation != rotation
$0.videoRotation = rotation
return result
}

Task.detached { @MainActor in
self.sampleBufferDisplayLayer.enqueue(sampleBuffer)
if didUpdateRotation {
self.setNeedsLayout()
}
}
}
}

extension SampleBufferVideoRenderer: Mirrorable {
func set(mirrored: Bool) {
mirroredTransform = mirrored ? VideoView.mirrorTransform : CATransform3DIdentity
updateSampleBufferTransform()
}
}
func set(isMirrored: Bool) {
let didUpdateIsMirrored = _state.mutate {
let result = $0.isMirrored != isMirrored
$0.isMirrored = isMirrored
return result
}

private extension SampleBufferVideoRenderer {
private func updateSampleBufferTransform() {
sampleBufferDisplayLayer.transform = displayLayerTransform
if didUpdateIsMirrored {
setNeedsLayout()
}
}
}

private extension CATransform3D {
static func fromFrameRotation(_ frame: LKRTCVideoFrame) -> CATransform3D {
switch frame.rotation {
static func from(rotation: VideoRotation, isMirrored: Bool) -> CATransform3D {
var transform: CATransform3D

switch rotation {
case ._0:
return CATransform3DIdentity
transform = CATransform3DIdentity
case ._90:
return CATransform3DMakeRotation(.pi / 2.0, 0, 0, 1)
transform = CATransform3DMakeRotation(.pi / 2.0, 0, 0, 1)
case ._180:
return CATransform3DMakeRotation(.pi, 0, 0, 1)
transform = CATransform3DMakeRotation(.pi, 0, 0, 1)
case ._270:
return CATransform3DMakeRotation(-.pi / 0, 0, 0, 1)
transform = CATransform3DMakeRotation(-.pi / 2.0, 0, 0, 1)
}

if isMirrored {
transform = CATransform3DConcat(transform, VideoView.mirrorTransform)
}

return transform
}
}
8 changes: 4 additions & 4 deletions Sources/LiveKit/Views/VideoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -500,9 +500,9 @@ public class VideoView: NativeView, Loggable {

if let _secondaryRenderer {
_secondaryRenderer.frame = rendererFrame
_secondaryRenderer.set(mirrored: _shouldMirror())
_secondaryRenderer.set(isMirrored: _shouldMirror())
} else {
_primaryRenderer.set(mirrored: _shouldMirror())
_primaryRenderer.set(isMirrored: _shouldMirror())
}
}
}
Expand Down Expand Up @@ -810,8 +810,8 @@ extension NSView {
#endif

extension LKRTCMTLVideoView: Mirrorable {
func set(mirrored: Bool) {
if mirrored {
func set(isMirrored: Bool) {
if isMirrored {
#if os(macOS)
// This is required for macOS
wantsLayer = true
Expand Down

0 comments on commit 9e3a152

Please sign in to comment.