AVPlayer freezes when seeking between 2 videos

Hi everyone!

Me and my team have an issue that we can't fix for few weeks now.

When we seek forward between two videos in AVComposition - the preview freezes. It gets stuck on last frame of first video. It doesn’t freeze if it’s a simple playback (not a seek) or if seek is quick.

Here is screen recording of what's happening:
https://www.icloud.com/iclouddrive/0651H_IA679ENDk9fLANNvwXA#AVCompositionFreezeScreenRecording

It feels like we tried everything, and nothing helps. When adding second video, we ask AVMutableComposition for a compatible track, and it returns us existing track, thus we conclude that both assetTrack's are compatible.

All the ranges and duration checked many times.

It fails both when videoComposition is set on playerItem and when not.

My current theory is even tho composition says that existing compositionTrack is compatible for second video, we can’t just put second video in it for some reason, maybe the transform is incompatible or I don’t know. 
One more note - if we take range of source videoAssetTrack with duration that is shorter than videoAssetTrack.timeRange.duration - then everything works. Maybe some issue with segment time mapping, but anything that we tried with it failed.

I tried to minimize the amount of code needed to demonstrate the issue, so hopefully it will be easy to see what I’m talking about. Just seek slowly from end of video1 to start of video2 and it will get stuck.
https://www.icloud.com/iclouddrive/0tDFgcQHKsIS7obiCA9yMHAEA#AVCompositionFreezeDemo

Thanks very much in advance, any help would be much appreciated!
Does playback transition from one video to the next as expected if you just let it play (instead of seeking around)?

Does playback transition from one video to the next as expected if you just let it play (instead of seeking around)?

Yes, playback is ok! Freezes only on seek. Also, it doesn't freeze if I seek quickly to middle of second video.
That sounds worthy of a bug report via feedback assistant.
Done! FB8381760
Hi! I found on iOS 13/14 the same issue with AVPlayer and composition like:
Code Block
<AVMutableComposition: 0x2819a4000 tracks = (
    "<AVMutableCompositionTrack: 0x28195a540 trackID = 1, mediaType = vide, editCount = 2>",
    "<AVMutableCompositionTrack: 0x281960c40 trackID = 2, mediaType = soun, editCount = 2>"
)>

Also I noticed that it depends on video items duration - if videos is long (for example 7 seconds) - there is no bug, but with short videos - 2 seconds - it always appears with slow dragging the thumb of progress bar.

Thanks
I found solution after long time of experiments: call play and pause in completion handler when seekToTime set time from another segment of current item track.
In order to fix this, we had to add second composition track and alternate between them, even tho we don't need it because we don't have transitions :(

Looks like this bug still persists in iOS 15 as well. I see this when I have three videos with transition between first two. The returned frame on seek is incorrect, the only way to reset the player to display current frame is by firing AVPlayer.play(). I wonder how such basic bugs persist even after 10 years of AVFoundation framework release!

Still got this issue. Pausing/playing video makes my preview not smooth.

Anyone found a solution to this. I am trying to merge two or more videos but the output has this issue. I have tried to find a solution but there seems to be little to no information regarding this specific... bug?

Hey! I just solved this problem and am very happy to share my working solution. The trick here is that two videos can have different fps. And we need to update the frameDuration AVMutableVideoComposition parameter of our AVPlayerItem

in general, the code looks like this

enum Const {
	static let perciseValue = 1000000
}

struct SemgentModel {
	let framerate: Float
	let timeRange: CMTimeRange
}

var mySegments: [SemgentModel] = ..add segments
var player: AVPlayer?

func updateFramerateOfComposition(newRate: Float) {
	let mutableComposition = player?.playerItem?.videoComposition?.mutableCopy() as? AVMutableVideoComposition
    mutableComposition?.frameDuration = CMTime(value: CMTimeValue(1 * Const.perciseValue), timescale: CMTimeScale(newRate * Float(Const.perciseValue)))
    player?.playerItem?.videoComposition = mutableComposition
}

func setTime(time: CMTime) {
	if let segment = mySegments.first(where: { $0.timeRange.contains(time) }) {
		updateFramerateOfComposition(newRate: segment.framerate)
	}
	player?.seek( to: seekTargetTime, toleranceBefore: .zero, toleranceAfter: .zero) { ... }
}

Hello! It turned out to solve this problem with a trick when creating an AVComposition. Namely, when creating AVComposition, I began to use two instead of one AVCompositionTrack in a checkerboard pattern. This solves the problem of not only different fps for neighboring videos, but also a different transform, if it was applied.

let videoTracks = [
    composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)!, 
    composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)!
]

let timeRangeStart: CMTime = .zero
for (index, asset) in assets.enumerated() {
    let videoTrack = videoTracks[index % 2]
    let assetTrack = asset.tracks(withMediaType: .video).first
    let timeRange = CMTimeRange(start: .zero, duration: asset.duration)
    do {
        try videoTrack.insertTimeRange(
            timeRange,
            of: assetTrack,
            at: timeRangeStart
         )
         timeRangeStart = timeRangeStart + timeRange.duration
    } catch {
        logError()
    }
}

Found another solution here which may be helpful as it doesn't require adding multiple tracks.

Simply call seek time twice, once without specifying tolerance, and then AFTER, with specifying a tolerance for frame by frame increments.

 let seekTime = CMTime(seconds: timeToSeekTo, preferredTimescale: yourPreferredTimescale)
            playerItem?.seek(to: seekTime) { [weak self] _ in // where player item is an AVPlayerItem created using your composition
                
            }
            playerItem?.seek(to: seekTime, toleranceBefore: .zero, toleranceAfter: .zero) { [weak self] _ in
            }

has this issue been resolved by Apple? We are faced with similar issue when seeking very slowly between two videos.

AVPlayer freezes when seeking between 2 videos
 
 
Q