iOS AVFoundation Playback Benchmarks

With the introduction of iOS 11, the AVFoundation framework underwent some changes and was extended with new functionality. So for better understanding and the ability to leverage the framework capabilities, here’s the rendition and comments to advances in AVFoundation Playback benchmarks firstly introduced at last year’s Apple WWDC.

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.

iOS AVFoundation Playback Benchmarks | Shakuro

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()

iOS AVFoundation Playback Benchmarks | Shakuro