How to seek to the last frame of AVPlayer

Viewed 725

Is it possible to seek AVPlayer to the last frame of an HLS video? Whenever I seek to the time (which is equal to the current item duration), I always end up at a position a bit before the final destination. I even tried using zero before and after tolerance while seeking, but it didn't work.

How can I programmatically seek to the end of a video in AVPlayer?

2 Answers

I am not sure if it helps but I faced a similar issue.

My task was to seek the last frame of a video played by AVPlayer.

I did that by seeking to duration value of a current item of AVPlayer instance. But after running the code below AVPlayer displayed the blank frame instead of the last frame of the video.

guard let duration = player?.currentItem?.asset.duration else {
  return
}
    
player?.seek(to: duration, toleranceBefore: .zero, toleranceAfter: .zero)

Finally, I hopefully found the reason for the issue.

We should take into consideration that the AVAsset instance can contain both video and audio tracks (usually it is a single video track and a single audio track) and there could be a case when the duration of the audio track is larger than the duration of the video track. So we should get the duration of the video track (AVAssetTrack instance has an appropriate property timeRange) of AVAsset and use it to seek the last frame of AVPlayer. The code below solved my issue.

guard let firstVideoTrack = player?.currentItem?.asset.tracks(withMediaType: .video).first else {
  return
}
    
let duration = firstVideoTrack.timeRange.duration
    
player?.seek(to: duration, toleranceBefore: .zero, toleranceAfter: .zero)

There could be more complex cases when an audio track starts before a video track or there are several video and/ or audio tracks inside a single asset. In this case, please check start property of timeRange struct of AVAssetTrack and perform appropriate actions.

Please also keep in mind that some AVAsset fields (for instance, tracks) are loaded asynchronously. Ensure you used loadValuesAsynchronously(forKeys:completionHandler:) method of AVAsset to load them before reading.

Related