How to loop video with AVPlayerLooper
I fixed the problem myself.
The playerLooper must be a member variable in the class otherwise it doesn't work because a local variable is gone after the method has been called. So I put this line at the beginning of the class to declare it. I didn't declare it as an AVPlayerLooper because this is only for tvos10.0 and newer versions. I want my class to be adaptive to tvos9.0.
This is my working code.
var playerLooper: NSObject?
var playerLayer:AVPlayerLayer!
var queuePlayer: AVQueuePlayer?
func playVideo(_ filmName: String){
if let path = Bundle.main.path(forResource: filmName, ofType: "mov") {
let url = URL(fileURLWithPath: path)
if #available(tvOS 10.0, *) {
// Use a new player looper with the queue player and template item
let playerItem = AVPlayerItem(url: url as URL)
self.player = AVQueuePlayer(items: [playerItem])
self.playerLayer = AVPlayerLayer(player: self.player)
self.playerLooper = AVPlayerLooper(player: self.player! as! AVQueuePlayer, templateItem: playerItem)
self.view.layer.addSublayer(self.playerLayer!)
self.playerLayer?.frame = self.view.frame
self.player?.play()
} else {
// Fallback on earlier versions, this solution has hicup at end
player = AVPlayer(url: url)
player?.play()
loopVideo(player!)
}
}
}
func loopVideo(_ videoPlayer: AVPlayer) {
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
if(!self.isStopped){
videoPlayer.seek(to: kCMTimeZero)
videoPlayer.play()
}
}
}
AVPlayerLoop not seamlessly looping - Swift 4
One thing to to keep in mind when looping assets is that audio and video tracks can have different offsets and different durations, resulting in 'blips' when looping. Such small differences are quite common in recorded assets.
Iterating over the tracks and printing the time ranges can help to detect such situations: for track in asset.tracks { print( track.mediaType); CMTimeRangeShow( track.timeRange); }
To trim audio and video tracks to equal start times and equal durations, get the common time range of the tracks, and then insert this time range from the original asset into a new AVMutableComposition
. Normally, you also want to preserve properties like the orientation of the video track:
let asset: AVAsset = (your asset initialization here)
let videoTrack: AVAssetTrack = asset.tracks(withMediaType: .video).first!
let audioTrack: AVAssetTrack = asset.tracks(withMediaType: .audio).first!
// calculate common time range of audio and video track
let timeRange: CMTimeRange = CMTimeRangeGetIntersection( (videoTrack.timeRange), (audioTrack.timeRange))
let composition: AVMutableComposition = AVMutableComposition()
try composition.insertTimeRange(timeRange, of: asset, at: kCMTimeZero)
// preserve orientation
composition.tracks(withMediaType: .video).first!.preferredTransform = videoTrack.preferredTransform
Since AVMutableComposition is a subclass of AVAsset, it can be used for AVPlayerLooper
-based looping playback, or exporting with AVAssetExportSession
.
I've put a more complete trimming implementation on github: https://github.com/fluthaus/NHBAVAssetTrimming. It's more robust, handles multiple tracks, preserves more properties and can either be easily integrated in projects or be build as a standalone macOS command line movie trimming utility.
AVPlayerLooper doesn't loop through multiple videos
After finding the solution that had been previously answered and posting it in the comments, @andy asked me to post it as a solution. HERE is the previous answer by Harish that solved his problem.
Looping a video with AVFoundation AVPlayer?
You can get a Notification when the player ends. Check AVPlayerItemDidPlayToEndTimeNotification
When setting up the player:
ObjC
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[avPlayer currentItem]];
this will prevent the player to pause at the end.
in the notification:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[p seekToTime:kCMTimeZero];
}
this will rewind the movie.
Don't forget un unregister the notification when releasing the player.
Swift
avPlayer?.actionAtItemEnd = .none
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: avPlayer?.currentItem)
@objc func playerItemDidReachEnd(notification: Notification) {
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: kCMTimeZero)
}
}
Swift 4+
@objc func playerItemDidReachEnd(notification: Notification) {
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: CMTime.zero, completionHandler: nil)
}
}
Issue looping video non-stop | Swift
You could use the AVPlayerLooper
and AVQueuePlayer
to loop your media. The trick here is that you need the reference to AVPlayerLooper
as an instance variable.
class ViewController: UIViewController {
var playerLooper: AVPlayerLooper! // needs to be defined here
func playVideo() {
guard let path = Bundle.main.path(forResource: "intro", ofType: "mp4") else {
return
}
let asset: AVAsset = AVAsset(url: URL(fileURLWithPath: path))
let playerItem = AVPlayerItem(asset: asset)
let queuePlayer = AVQueuePlayer(playerItem: playerItem)
self.playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)
let playerLayer = AVPlayerLayer(player: queuePlayer)
playerLayer.frame = self.view.bounds
playerLayer.videoGravity = .resizeAspectFill
self.view.layer.addSublayer(playerLayer)
queuePlayer.play()
}
}
Related Topics
App Crashing When Using Firebase Auth, Reason: 'Default App Has Already Been Configured.'
Google Analytics 3.08 iOS Idfa Class Missing, Won't Collect Idfa
Gem Native Extension Error While Installing Cocoapods
Disable Autolayout Localization Behavior (Rtl - Right to Left Behavior )
Calling Function from Another Viewcontroller in Swift
Autolayout Aspect Ratio for Uiimageview/Uiview
How to Implement Uitableview's Swipe to Delete for Uicollectionview
How to Set Status Bar Tint Color on iOS 6
Is There Any Limitation to Distribution of Apps in iOS Enterprise Program
Pop the Current View Using Segues/Storyboard on iOS 5
Are There Any Analogues of [Nsstring Stringwithformat:] for Nsattributedstring
Using Multiple Storyboards with a Tabbarcontroller
Autosizing Cells: Cell Width Equal to the Collectionview
View Controller Responds to App Delegate Notifications in iOS 12 But Not in iOS 13