Overview
I'm using AVPlayer to play remote videos in my app. We have .mp4 video assets and separate subtitles assets in .vtt format to a living on a CDN. We do not have the option to use HLS playlist containers at this time.
To play video and subtitles we're using AVMutableComposition with tracks for video and audio AVURLAsset instances to play the items simultaneously in AVPlayer. This is explained in this apple dev forums post. Some simple examples below.
Turns out that when using AVMutableComposition, regardless of whether we add a subtitle track to it, we see LOTS of requests for ~64k chunks of the video file as AVPlayer requests sequential byte ranges. In a high latency environment, or with a high bitrate video, the playback is choppy as the chunks are not received fast enough to keep up with playback and the experience is terrible. We can play the same video from the same url just fine, if we do not add it as a track to the AVMutableComposition but play it directly. This is illustrated below.
There is very little written on networking behavior around loading video, but it appears that the chunk size selection is happening in the CoreMedia framework.
Is there a way to control this networking behavior? Is there some workaround I don't know about to trick the player into loading the asset normally when subtitles are involved? Its causing a terrible user experience? Is this a bug in CoreMedia framework?
Examples
Example 1 - Viewing a video, using just AVURLAsset with the video url
let player = AVPlayer()
let asset = AVURLAsset(url: videoURL)
let playerItem = AVPlayerItem(asset: asset)
player.replaceCurrentItem(item: playerItem)
player.play()
We see fewer, larger chunks being requested by CoreMedia, and smooth playback.
Example 2 - Viewing the same video, adding it as a track on the AVMutableComposition player item.
let player = AVPlayer()
let videoAsset = AVURLAsset(url: videoURL)
let subtitleAsset = AVURLAsset(url: subtitleURL)
let composition = AVMutableComposition()
// add video to the mutable composition
composition.insertTimeRange(
CMTimeRangeMake(start: CMTime.zero, duration: videoAsset.duration),
of: videoAsset,
at: CMTime.zero)
/* not shown. adding subtitle track, since it produces same result */
let playerItem = AVPlayerItem(asset: composition)
player.replaceCurrentItem(item: playerItem)
player.play()
Many small video chunks requested by CoreMedia and playback is choppy.
This seems like a bug in the Core Media framework. Is there is any way to affect the progressive download byte range request size for the video stream?
Has anyone else seen this issue and found a workaround?
All I want to do is play .mp4 and .vtt assets simultaneously without crazy networking perf issues! We're not able to easily switch the video / subtitles assets setup at this time.
Already Tried - Doesn't Work
- using copy() to turn AVMutableCompositionItem into AVCompositionItem before instantiating AVAsset

