Swift AVPlayer seekToTime issue
Solution 1
For AVPlayer, there are different ways to let the play seeking time;
player.seekToTime(<#time: CMTime#CMTime#>)
for this method,player will seek to seekingTime quickly but not seeking the exactly where the seekingTime is, it means there will be some offset of the seekingTime.
Apple's Doc
Use this method to seek to a specified time for the current player item.
The time seeked to may differ from the specified time for efficiency.
For sample accurate seeking see seekToTime:toleranceBefore:toleranceAfter:.
player.seekToTime(<#T##time: CMTime##CMTime#>, completionHandler: <#T##(Bool) -> Void#>)
for this method,player will seek to seekingTime quickly and also,with the offset,you can do something with completionHandler
Apple's Doc
Use this method to seek to a specified time for the current player item and to be notified when the seek operation is complete.
The completion handler for any prior seek request that is still in process will be invoked immediately with the finished parameter
set to NO. If the new request completes without being interrupted by another seek request or by any other operation the specified
completion handler will be invoked with the finished parameter set to YES.
If you want to seeking more accurate, use the following method instead
player.seekToTime(<#T##time: CMTime##CMTime#>, toleranceBefore: <#T##CMTime#>, toleranceAfter: <#T##CMTime#>)
player.seekToTime(<#T##time: CMTime##CMTime#>, toleranceBefore: <#T##CMTime#>, toleranceAfter: <#T##CMTime#>, completionHandler: <#T##(Bool) -> Void#>)
this method will let the player seeking to specified time you asking,but will be slower(well..mostly depending on current media)
Apple's Doc
Use this method to seek to a specified time for the current player item.
The time seeked to will be within the range [time-toleranceBefore, time+toleranceAfter] and may differ from the specified time for efficiency.
Pass kCMTimeZero for both toleranceBefore and toleranceAfter to request sample accurate seeking which may incur additional decoding delay.
Messaging this method with beforeTolerance:kCMTimePositiveInfinity and afterTolerance:kCMTimePositiveInfinity is the same as messaging seekToTime: directly.
i've notice that current you are using
avPlayer?.currentItem?.seekToTime(CMTimeMakeWithSeconds(secondo, frameRate))
you can try to use this method to seeking the specified time (slower of course)
avPlayer?.currentItem?.seekToTime(CMTimeMakeWithSeconds(secondo, frameRate), toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
Wish could help u out
Solution 2
In Swift 4.2 and Xcode 10.1
player?.seek(to: CMTimeMakeWithSeconds(100, preferredTimescale: 1), toleranceBefore: CMTime.zero, toleranceAfter: CMTime.zero)
Solution 3
I doubt any of the answers supplied actually worked. Try this:
Technical Q&A QA1820 How do I achieve smooth video scrubbing with AVPlayer seekToTime:?
Q: My app allows the user to scrub video files using a slider control in combination with AVPlayer seekToTime: but there is a considerable lag in the display of the video frames. How can I achieve smoother scrubbing?
A: Avoid making calls to AVPlayer seekToTime: in rapid succession. This will cancel the seeks in progress, resulting in a lot of seeking and not a lot of displaying of the target frames. Instead, use the completion handler variant of AVPlayer seekToTime:, and wait for a seek in progress to complete first before issuing another. Listing 1 and Listing 2 give examples of this technique (Note: these examples assume a valid player object has been created and the player's current item status is being maintained via key-value observing. See the AV Foundation Programming Guide for more information):
Using the completion handler variant of AVPlayer seekToTime: for smoother scrubbing (Swift).
import AVFoundation
class MyClass {
var isSeekInProgress = false
let player = <#A valid player object #>
var chaseTime = kCMTimeZero
// your player.currentItem.status
var playerCurrentItemStatus:AVPlayerItemStatus = .Unknown
...
func stopPlayingAndSeekSmoothlyToTime(newChaseTime:CMTime)
{
player.pause()
if CMTimeCompare(newChaseTime, chaseTime) != 0
{
chaseTime = newChaseTime;
if !isSeekInProgress
{
trySeekToChaseTime()
}
}
}
func trySeekToChaseTime()
{
if playerCurrentItemStatus == .Unknown
{
// wait until item becomes ready (KVO player.currentItem.status)
}
else if playerCurrentItemStatus == .ReadyToPlay
{
actuallySeekToTime()
}
}
func actuallySeekToTime()
{
isSeekInProgress = true
let seekTimeInProgress = chaseTime
player.seekToTime(seekTimeInProgress, toleranceBefore: kCMTimeZero,
toleranceAfter: kCMTimeZero, completionHandler:
{ (isFinished:Bool) -> Void in
if CMTimeCompare(seekTimeInProgress, chaseTime) == 0
{
isSeekInProgress = false
}
else
{
trySeekToChaseTime()
}
})
}
}
Alessandro Zago
Updated on June 07, 2022Comments
-
Alessandro Zago almost 2 years
i have this code :
let punto = sender.locationInView(self.barraVideo).x let larghezzaImg : Double = Double((self.barraVideoInvisTocco?.frame.width)!) let percTocco : Double = (100 / larghezzaImg) * Double(punto) let lunghezzaVideo : Double = Double(CGFloat((avPlayer?.currentItem?.asset.duration.value)!) / CGFloat(1000.0)); let frameRate : Int32 = (avPlayer?.currentItem?.currentTime().timescale)! let secondo : Float64 = Float64((lunghezzaVideo/100)*percTocco) print("Val : \(secondo)"); avPlayer?.currentItem?.seekToTime(CMTimeMakeWithSeconds(secondo, frameRate)) avPlayer?.play() videoInPlay = true; playPauseBtn!.image = UIImage(named: "iconaPausa.png")!;
That recive a x cordinate of a tap on the seekBar and seek the video. The code works with logs video but work very bad with short videos. When i tap on the short video the AVPlayer seek only near the begining or near the end of the video, not in the middle
print :
Val : 3.36008475976495 Val : 7.14189817632069 Val : 13.3303201306846 Val : 3.70388597945183 Val : 3.93308679257642 Val : 3.24548435320265 Val : 3.70388597945183 Val : 18.8311396456748 Val : 27.0823689181601 Val : 40.1468152662618 Val : 51.3776551093667 Val : 17.2267339538027 Val : 9.54850671412889 Val : 23.4151559081666 Val : 37.6256063218913
The val rappresents the right value of seconds where i wont to seek. Sorry for bad english, i'm italian