Skip to content

Instantly share code, notes, and snippets.

@shaps80
Last active June 12, 2024 00:09
Show Gist options
  • Save shaps80/ac16b906938ad256e1f47b52b4809512 to your computer and use it in GitHub Desktop.
Save shaps80/ac16b906938ad256e1f47b52b4809512 to your computer and use it in GitHub Desktop.
Enables smooth frame-by-frame scrubbing (in both directions) – similar to Apple's applications.
public enum Direction {
case forward
case backward
}
internal var player: AVPlayer?
private var isSeekInProgress = false
private var chaseTime = kCMTimeZero
private var preferredFrameRate: Float = 23.98
public func seek(to time: CMTime) {
seekSmoothlyToTime(newChaseTime: time)
}
public func stepByFrame(in direction: Direction) {
let frameRate = preferredFrameRate
?? player?.currentItem?.tracks
.first(where: { $0.assetTrack.mediaType == .video })?
.currentVideoFrameRate
?? -1
let time = player?.currentItem?.currentTime() ?? kCMTimeZero
let seconds = Double(1) / Double(frameRate)
let timescale = Double(seconds) / Double(time.timescale) < 1 ? 600 : time.timescale
let oneFrame = CMTime(seconds: seconds, preferredTimescale: timescale)
let next = direction == .forward
? CMTimeAdd(time, oneFrame)
: CMTimeSubtract(time, oneFrame)
seekSmoothlyToTime(newChaseTime: next)
}
private func seekSmoothlyToTime(newChaseTime: CMTime) {
if CMTimeCompare(newChaseTime, chaseTime) != 0 {
chaseTime = newChaseTime
if !isSeekInProgress {
trySeekToChaseTime()
}
}
}
private func trySeekToChaseTime() {
guard player?.status == .readyToPlay else { return }
actuallySeekToTime()
}
private func actuallySeekToTime() {
isSeekInProgress = true
let seekTimeInProgress = chaseTime
player?.seek(to: seekTimeInProgress, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero) { [weak self] _ in
guard let `self` = self else { return }
if CMTimeCompare(seekTimeInProgress, self.chaseTime) == 0 {
self.isSeekInProgress = false
} else {
self.trySeekToChaseTime()
}
}
}
@defagos
Copy link

defagos commented May 18, 2024

Oh that’s amazing thanks! Unfortunately your beta isn’t accepting lol but I trust you.

Should be fixed now, sorry, there was no recent build enabled for external testing 😇

@shaps80
Copy link
Author

shaps80 commented May 18, 2024

👍👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment