I have a 30 second video I want to loop and uses an AVVideoComposition. It works flawlessly in the Catalina Simulator, but fails on my iPad 9.7". Originally I thought the problem was with the CIFilters, but in the end it was the simple existence of the composition block:
func runMovie() {
playerItem = AVPlayerItem(asset: asset)
let videoComposition = AVVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in
let outputImage = request.sourceImage
request.finish(with: outputImage, context: nil)
})
playerItem.videoComposition = videoComposition
let duration = CMTime(seconds: 30.0, preferredTimescale: CMTimeScale(1))
let plyr = AVQueuePlayer()
let timeRange = CMTimeRange(start: CMTime.zero, duration: duration)
playerLooper = AVPlayerLooper(player: plyr, templateItem: playerItem, timeRange: timeRange)
playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = view.bounds //bounds of the view in which AVPlayer should be displayed
playerLayer.videoGravity = .resizeAspect
view.layer.addSublayer(playerLayer)
plyr.play()
print("PLAY VIDEO", player.status.rawValue)
startDate = Date()
let _ = timer// starts 1 second timer
}
The player runs one or more loops, then the video stops. I have a timer running checking the AVLooper status, and this is the error I see:
//if playerLooper.status == .failed {
// print("ERROR:", playerLooper.error ?? "No Error")
// ERROR: Error Domain=AVFoundationErrorDomain Code=-11819 "Cannot Complete Action" UserInfo={NSLocalizedDescription=Cannot Complete Action, NSLocalizedRecoverySuggestion=Try again later.}
Leave the video composition out, it loops forever, add the compostion, it fails in a min or two.
PS: this is a HEVC video I created from a standard mov per the 2019 WWDC 506 Session:
guard let export = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHEVCHighestQualityWithAlpha) else { fatalError() }
let scale = CMTimeScale(1)
export.timeRange = CMTimeRange(start: CMTime.zero, duration: CMTime(seconds: 31.0, preferredTimescale: scale))
export.outputFileType = AVFileType.mov
//let url = URL(fileURLWithPath: "/tmp/Original-transparent.mov")
let url = URL(fileURLWithPath: "/tmp/Original-transparent.mov")
try? FileManager.default.removeItem(at: url)
export.outputURL = url
export.videoComposition = videoComposition
export.exportAsynchronously(completionHandler: {
DispatchQueue.main.async {
NSLog("...VIDEO DONE")
self.makingVideoNow = false
}
})
NSLog("START VIDEO...")