AVFoundation Features
AVFoundation provides the API for a broad spectrum of multimedia operations including the playback, image capture, export, and a bunch of editing options.
Playback types:
From local storage: file:///.../example.MOV.
From a web server where the file is uploaded to, followed by the progressive download: https://example.com/example.MOV.
A more dynamic way is HTTP Live Streaming (HLS). HLS plays playlists. A playlist is a .txt file. It contains #EXTINF tags. Tags contain segments (segment1.ts, etc.) Each one of them is 10 seconds long (#EXTINF 10.001).
video 6Mbit playlist;
video 4Mbit playlist;
video 2Mbit playlist audio stereo playlist;
audio surround playlist;
The playlist.txt file:
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-MAP:URI="patpmt.ts"
#EXTINF 10.001
segment1.ts
#EXTINF 10.001
segment2.ts
Generally, the default URL is related to the basic playback list which contains several playlists for the same content but is configured depending on the speed of transmission, format, and sometimes, language.
Playback Through The Network
Today, AVPlayerItem
has three properties: playbackLikelyToKeepUp
, playbackBufferFull
, and playbackBufferEmpty
.
In iOS 9 and before,the AVFoundation clients were supposed to control the Progressive Download properties and wait till the playbackLikelyToKeepUp
and the playbackBufferEmpty
properties are true before they set up the AVPlayer.rate = 1
.
For HTTP Live Streaming, you can set the AVPlayer.rate
to 1, as soon as a user starts the playback and it automatically waits for the data to buffer sufficiently to start playing.
In iOS 10, macOS Sierra, and tvOS 10, the same rules are applied as for Progressive Download and HTTP Live Streaming. You can set up the AVPlayer.rate = 1
on the tapping play event or request playback method – same thing. In this case, AVFoundation automatically waits to avoid buffering.
If the network connection is lost during the playback, the AVPlayer.rate = 1
value remains. The buffering continues and whenever enough data loads up, the playback resumes.
If you use AVKit and MediaPlayer for the UI, they already support the automatic buffering wait. The application that uses AVFoundation directly uses the new APIs (automaticallyWaitsToMinimizeStalling). If the AVPlayer.automaticallyWaitsToMinimizeStalling
value is false, the playback starts immediately.
Playback through the network has three states: paused, waiting and playing. The initial state is paused.
AVPlayer.rate
is the requested speed of application playback.
AVPlayerItem.timebase.rate
is the speed of the playback.
iOS 10 AVFoundation Staples
Automatically, the AVPlayer.automaticallyWaitsToMinimizeStalling
parameter value is true. The AVPlayer.timeControlStatus - (Paused, WaitingToPlayAtSpecifiedRate, Playing)
is the stausof the player. When in a waiting mode (WaitingToPlayAtSpecifiedRate)
, the AVPlayer.reasonForWaitingToPlay
parameter reports the reason for this wait.
The AVQueuePlayer
is the playback queue, used for optimization of transitions between different elements (AVPlaerItem)
. In case of a cycle, you create multiple AVPlayer elements out of one AVAsset. AVQueuePlayer
provides the information about the elements which are to be played and for the AVFoundation optimization of these transitions.
The Treadmill Effect
Create the AVPlayerItem
elements and add them to the AVQueuePlayer
queue and while doing so, set up the .end
property. When the playback reaches the end of the element, it will be deleted from the queue as the list moves along to the next item. Upon the receipt of a notification that this happened, you can get this element, set its current time to the start, and place the element in the end of the queue. The stopObserving
and startObserving
methods are used to avoid recursion.
override func observeValue(forKeyPath keyPath: String?, of object: AnyObject?, change:
[NSKeyValueChangeKey : AnyObject]?, context: UnsafeMutablePointer<Void>?) {
if context == &ObserverContexts.currentItem {
guard let player = player else { return }
if player.items().isEmpty {
// Play queue emptied out due to bad player item. End looping.
}
else {
if let itemRemoved = change?[.oldKey] as? AVPlayerItem {
itemRemoved.seek(to: kCMTimeZero)
stopObserving()
player.insert(itemRemoved, after: nil)
startObserving()
} }
}
// else ... }
AVPlayerLooper
The AVplayerLoop
implements the Treadmill effect, creates several AVPleyerItem
copies that cyclically move across the playback queue.
player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()
