HLS Streaming with AVKit and SwiftUI

By the end of this article, you will be able to understand the basic of HTTP Live Streaming (HLS) and how to use it with the VideoPlayer in SwiftUI

HLS Streaming with AVKit and SwiftUI

For playing media files in apps, the AVKit framework provides all necessary components to create the necessary interfaces for media playback, transport controls, etc. It also provides a generic structure VideoPlayer for SwiftUI that displays media content with a native user interface to control playback. It is initialized with an AVPlayer object that provides the VideoPlayer with the interface to control the player’s transport behavior

AVPlayer is used to play single media files, alternatively, an AVQueuePlayer is also available to play a sequence of media items. The AVPlayer is initialized by providing either an AVPlayerItem object or by providing an URL to reference and play a single audiovisual resource.

The latter is certainly very convenient and allows a simple video player to be created in SwiftUI with just a few lines of code.

import SwiftUI
import AVKit

struct SimpleVideoPlayer: View {
    
    private let player = AVPlayer(url: URL(string: "YOUR-URL.mp4")
    
    var body: some View {
        VideoPlayer(player: player)
        .onAppear() {
            player.play()
        }
    }
}

HTTP Live Streaming (HLS)

The AVPlayer supports a broad variety of media files and among those HTTP Live Streaming (HLS) is a nice option to stream live or on-demand video content inside apps on iPhone, iPad, Mac, Apple Watch, or Apple TV. The beauty of HLS allows separate streams with different resolutions to be supported, which can make the playback experience more reliable as it dynamically adapts to network conditions.

An HLS stream is addressed through an HLS playlist .m3u8 file, which is a manifest that links to chunks of media files that are played in sequence. For example, a playlist file could look like this:

#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
fileSequenceA.ts
#EXTINF:10.0,
fileSequenceB.ts
#EXTINF:10.0,
fileSequenceC.ts
#EXTINF:9.0,
fileSequenceD.ts
#EXT-X-ENDLIST
c

The manifest provided some information that applies to the entire playlist. For example, the EXT-X-PLAYLIST-TYPE indicates whether the playlist is mutable. It can be set to EVENT or VOD. In the case of EVENT, the server may append more files to the sequence as they become available. In the case of VOD, the playlist file cannot change.

Other metadata indicates the maximum duration of any media file inside the playlist (EXT-X-TARGETDURATION), the compatibility version of the playlist (EXT-X-VERSION), or the sequence number of the first URL in the playlist (EXT-X-MEDIA-SEQUENCE). The EXTINF marker describes the following media file identified by its URL with a float value for the duration of the media segment in seconds. Finally, at the end of the playlist, EXT-X-ENDLIST closes the file.

The individual media segments are loaded in sequence, making the playback more reliable. The technology also allows the creation of a primary playlist that links to different playlists, for example, to have multiple streams with different resolutions. HLS allows the playlist to be determined based on the network conditions.

An example playlist looks like this:

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=8743534,AVERAGE-BANDWIDTH=8743534,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=29.970
1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5177606,AVERAGE-BANDWIDTH=5177606,CODECS="avc1.4d401f,mp4a.40.5",RESOLUTION=1280x720,FRAME-RATE=29.970
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3664591,AVERAGE-BANDWIDTH=3664591,CODECS="avc1.4d401f,mp4a.40.5",RESOLUTION=960x540,FRAME-RATE=29.970
540p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1345110,AVERAGE-BANDWIDTH=1345110,CODECS="avc1.4d401f,mp4a.40.5",RESOLUTION=640x360,FRAME-RATE=29.970
360p.m3u8

In this case, EXT-X-STREAM-INF provides information about each stream, its bandwidth, the used codecs, resolution, and framerate (among others). This information is then used to determine the appropriate stream for playback. A primary playlist is only checked once though. Once the variations are evaluated, it is assumed that the data is not changing.


HTTP Live Streaming (HLS) with SwiftUI and VideoPlayer

The beauty is, non of this matters very much when using the AVPlayer as HLS is supported out of the box without any additional steps required. The only difference is that the URL for the media element directs to the .m3u8 playlist file. The rest works "automagically".

import SwiftUI
import AVKit

struct SimpleVideoPlayer: View {
    
    private let player = AVPlayer(url: URL(string: "YOUR-URL.m3u8")!)
    
    var body: some View {
        VideoPlayer(player: player)
        .onAppear() {
            player.play()
        }
    }
}

The leverage different bandwidth options on deeper levels of, also consider our other article about Switching between HLS streams with AVKit. The approach was used in the Alles Neu Land Media Library app. To learn more about it, check out our article Developing A Media Streaming App Using SwiftUI In 7 Days. To learn more about how HTTP Live Streaming (HLS) works, explore the article Using HLS for live and on-demand audio and video.


This article is part of a series of articles derived from the presentation "How to create a media streaming app with SwiftUI and AWS" presented at the NSSpain 2021 conference on November 18-19, 2021.