We have videos encoded via bitmovin.com and provided as HTTP Live streams (Fairplay HLS), but the subtitles, although in WebVTT format, are displayed separately as direct URLs for the entire file, not separate segments and are not part of the H3 m3u8 list reproduction.
I am looking for a way that an external .vtt file, downloaded separately, can still be included in the HLS stream and be available as subtitles in AVPlayer.
I know that Apple's recommendation is to include VTT segmented subtitles in the HLS playlist, but now I can’t change the server implementation, so I want to clarify if it is even possible to provide subtitles for AVPlayer to play along with the HLS stream.
The only valid post on this topic claiming it is possible: Subtitles for AVPlayer / MPMoviePlayerController . However, the sample code loads the local mp4 file from the package, and I'm struggling to get it working in the m3u8 playlist via AVURLAsset. Actually, I am having a problem getting a video driver from a remote m3u8 stream since it asset.tracks(withMediaType: AVMediaTypeVideo)returns an empty array. Any ideas if this approach could work for a real HLS stream? Or is there another way to play individual WebVTT subtitles with an HLS stream without including them in the HLS playlist on the server? Thank.
func playFpsVideo(with asset: AVURLAsset, at context: UIViewController) {
let composition = AVMutableComposition()
let videoTrack = composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)
do {
let tracks = asset.tracks(withMediaType: AVMediaTypeVideo)
guard let track = tracks.first else {
Log.error("Can't get first video track")
return
}
try videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, asset.duration), of: track, at: kCMTimeZero)
} catch {
Log.error(error)
return
}
guard let subsUrl = Bundle.main.url(forResource: "subs", withExtension: "vtt") else {
Log.error("Can't load subs.vtt from bundle")
return
}
let subtitleAsset = AVURLAsset(url: subsUrl)
let subtitleTrack = composition.addMutableTrack(withMediaType: AVMediaTypeText, preferredTrackID: kCMPersistentTrackID_Invalid)
do {
let subTracks = subtitleAsset.tracks(withMediaType: AVMediaTypeText)
guard let subTrack = subTracks.first else {
Log.error("Can't get first subs track")
return
}
try subtitleTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, asset.duration), of: subTrack, at: kCMTimeZero)
} catch {
Log.error(error)
return
}
let item = AVPlayerItem(asset: composition)
let player = AVPlayer(playerItem: item)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.playerViewController = playerViewController
context.present(playerViewController, animated: true) {
playerViewController.player?.play()
}
}
source
share