Can AVAssetResourceLoader (and AVAssetResourceLoaderDelegate) be used to limit the choices of streams to increase quality?

367 views Asked by At

iOS (seemingly especially with iOS 15), isn't always the best at taking an HLS m3u8 playlist with multiple playback quality options and selecting the best one to play. For instance even with a great internet connection, iOS will often pick one of the lower qualities of the available options and take quite awhile to transition to the higher quality one. Users aren't too happy about this, and understandably, since I can paste the direct link to a high quality video stream in the playlist (without audio) into Safari and it loads instantly when I do it manually, versus the slower AVPlayer implementation.

Is it possible to use AVAssetResourceLoader to intercept the HLS playlist and strip out a few of the lower quality options and thus prevent iOS from choosing the lower quality options more?

I noticed in this question on the Apple Developer forums it was indicated by an employee it might be possible, however alongside Apple's demo code I've been unable to find a clear way to do this.

An example might be the following HLS manifest:

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=308000,AVERAGE-BANDWIDTH=279000,RESOLUTION=162x288,CODECS="avc1.42001e"
HLS_224.m3u8
#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=522000,AVERAGE-BANDWIDTH=481000,RESOLUTION=180x320,CODECS="avc1.42001e"
HLS_270.m3u8
#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=969000,AVERAGE-BANDWIDTH=886000,RESOLUTION=244x432,CODECS="avc1.4d001e"
HLS_360.m3u8
#EXT-X-STREAM-INF:CLOSED-CAPTIONS=NONE,BANDWIDTH=1529000,AVERAGE-BANDWIDTH=1388000,RESOLUTION=360x640,CODECS="avc1.4d001f"
HLS_540.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=20113,RESOLUTION=162x288,CODECS="avc1.42001e",URI="HLS_224-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=29898,RESOLUTION=180x320,CODECS="avc1.42001e",URI="HLS_270-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=51637,RESOLUTION=244x432,CODECS="avc1.4d001e",URI="HLS_360-iframe.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=79210,RESOLUTION=360x640,CODECS="avc1.4d001f",URI="HLS_540-iframe.m3u8"

Wherein I'd like to strip out the 224 and 227 options and leave the 360 and 540 options. This is of course with the assumption that the HLS playlist is hosted on a server I don't implicitly have access to so I can't edit the files directly.

1

There are 1 answers

0
Mr.SwiftOak On

The answers on Apple development forum are a little bit old. The good news is that iOS 15 introduced some new APIs to work with bitrates in multi-variant playlists. When loading video, use the AVURLAsset and AVAssetResourceLoader as you suggested. After loading the asset you get info which playlist variant the system selected by accesing all variants with calling AVURLAsset.variants , currently selected variant by calling following code on AVPlayerItem:

if let lastEvent = self.playerItem?.accessLog()?.events.last {
    let selectedBitRate = lastEvent.indicatedAverageBitrate
    selectedAverageBitRate = selectedBitRate
    selectedIndex = variants.firstIndex(where: {$0.averageBitRate ?? 0 == selectedBitRate})
}

For settingplaylist variant preferrences you can use:

playerItem?.variantPreferences

On the other hand , if you somehow want to limit the preferred bit rate use following:

playerItem?.preferredPeakBitRate