Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2021 Audio & Video

WWDC21 · 9 min · Audio & Video

Explore HLS variants in AVFoundation

Discover how you can use AVFoundation APIs to highlight different variants of your content within your app. We’ll show you how you can inspect HLS content using these APIs for different video characteristics, including attributes like SDR/HDR, FPS, and the like. And we’ll explore the AVAssetVariant, which represents streaming and offline content.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 7 snippets

HLS Master Playlist swift · at 0:40 ↗
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS

#EXT-X-MEDIA:TYPE=AUDIO,NAME="English",GROUP-ID="stereo",LANGUAGE="en",DEFAULT=YES, AUTOSELECT=YES,CHANNELS="2",URI="en_stereo.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,NAME="French",GROUP-ID="stereo",LANGUAGE="fr",DEFAULT=NO, AUTOSELECT=YES,CHANNELS="2",URI="fr_stereo.m3u8"

#EXT-X-MEDIA:TYPE=AUDIO,NAME="English",GROUP-ID="atmos",LANGUAGE="en",DEFAULT=YES, AUTOSELECT=YES,CHANNELS="16/JOC",URI="en_atmos.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,NAME="French",GROUP-ID="atmos",LANGUAGE="fr",DEFAULT=NO, AUTOSELECT=YES,CHANNELS="16/JOC",URI="fr_atmos.m3u8"

#EXT-X-STREAM-INF:BANDWIDTH=14516883,VIDEO-RANGE=SDR,CODECS="avc1.64001f,mp4a.40.5", AUDIO="stereo",FRAME-RATE=23.976,RESOLUTION=1920x1080
sdr_variant.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=34516883,VIDEO-RANGE=PQ,CODECS="dvh1.05.06,ec-3", AUDIO="atmos",FRAME-RATE=23.976,RESOLUTION=3840x1920
dovi_variant.m3u8
Peak bitrate cap predicate swift · at 3:38 ↗
let peakBitRateCap = NSPredicate(format: "peakBitRate < 5000000")

let peakBitRateCapQualifier = AVAssetVariantQualifier(predicate: peakBitRateCap)
HDR predicate swift · at 3:55 ↗
let hdrOnlyPredicate = NSPredicate(format: "videoAttributes.videoRange == %@", argumentArray: [AVVideoRange.pq])

let hdrOnlyQualifier = AVAssetVariantQualifier(predicate: hdrOnlyPredicate)
Content configuration swift · at 4:46 ↗
let variantPref = AVAssetVariantQualifier(predicate: NSPredicate(format: "videoAttributes.videoRange == %@ && peakBitRate < 5000000", argumentArray: [AVVideoRange.pq]))

let myMediaSelections : [AVMediaSelection] = [enAudioMS, frAudioMS, enLegibleMS] //English, French audio and English subtitle renditions 

let contentConfig = AVAssetDownloadContentConfiguration()

contentConfig.variantQualifiers = [variantPref]

contentConfig.mediaSelections = myMediaSelections
Download configuration swift · at 6:29 ↗
let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!)
let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: "my-title")

/* Primary content config */
let varPref = NSPredicate(format: "videoAttributes.videoRange == %@ && peakBitRate < 5000000", argumentArray: [AVVideoRange.pq])
let varQf = AVAssetVariantQualifier(predicate: varPref)

dwConfig.primaryContentConfiguration.variantQualifiers = [varQf]
dwConfig.primaryContentConfiguration.mediaSelections = [enAudioMS, frAudioMS, enLegibleMS] //English, French audio and English subtitle renditions 

/* Aux content config */
let auxVarPref = NSPredicate(format: "%d IN audioAttributes.formatIDs", argumentArray: [kAudioFormatAppleLossless])
let auxVarQf = AVAssetVariantQualifier(predicate: auxVarPref)

let auxContentConfig = AVAssetDownloadContentConfiguration()
auxContentConfig.variantQualifiers = [auxVarQf]
auxContentConfig.mediaSelections = [enAudioMS] //english audio
dwConfig.auxiliaryContentConfigurations = [auxContentConfig]

dwConfig.optimizesAuxiliaryContentConfigurations = true
Download task swift · at 7:42 ↗
let myAssetDownloadDelegate = MyDownloadDelegate()
let avurlsession = AVAssetDownloadURLSession(configuration: URLSessionConfiguration.background(withIdentifier: "my-background-session"), assetDownloadDelegate: myAssetDownloadDelegate, delegateQueue: OperationQueue.main)

let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!)
let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: “my-title”)

...

let downloadTask = avurlsession.makeAssetDownloadTask(downloadConfiguration: dwConfig)

downloadTask.resume()

let progress = downloadTask.progress
Direct variant selection swift · at 8:10 ↗
/* Example for direct variant selection */

let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!)
let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: "my-title")

/* Primary content config */
let myVariant : AVAssetVariant = ...
let myMediaSelections : [AVMediaSelection] = ...

let variantQf = AVAssetVariantQualifier(variant: myVariant)

dwConfig.primaryContentConfiguration.variantQualifiers = [variantQf]
dwConfig.primaryContentConfiguration.mediaSelections = myMediaSelections

/* Aux content config */
let myAuxVariant : AVAssetVariant = ...
let myAuxMediaSelections : [AVMediaSelection] = ...

let auxVariantQf = AVAssetVariantQualifier(variant: myAuxVariant)

let auxContentConfig = AVAssetDownloadContentConfiguration()
auxContentConfig.variantQualifiers = [auxVariantQf]
auxContentConfig.mediaSelections = myAuxMediaSelections
dwConfig.auxiliaryContentConfigurations = [auxContentConfig]

Resources