Reputation: 297
I am developing a custom video player to stream HLS videos from a server. I can successfully play HLS videos using AVPlayerItem and AVPlayer.
After that I want to add subtitle tracks and audio tracks for my video player. So I used AVMutableComposition to do so. So now the issue is when I am creating AVURLAsset for HLS Videos, I am unable to get video tracks from AVURLAsset. It is always giving me 0 tracks. I tried loadValuesAsynchronously
of AVURLAsset and I tried adding KVO for tracks
of AVPlayerItem. But none of these produced any positive results.
I am using the following code.
func playVideo() {
let videoAsset = AVURLAsset(url: videoURL!)
let composition = AVMutableComposition()
// Video
let videoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
do {
let tracks = videoAsset.tracks(withMediaType: .video)
guard let track = tracks.first else {
print("Can't get first video track")
return
}
try videoTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), of: track, at: kCMTimeZero)
} catch {
print(error)
return
}
guard let subtitlesUrl = Bundle.main.url(forResource: "en", withExtension: "vtt") else {
print("Can't load en.vtt from bundle")
return
}
//Subtitles
let subtitleAsset = AVURLAsset(url: subtitlesUrl)
let subtitleTrack = composition.addMutableTrack(withMediaType: .text, preferredTrackID: kCMPersistentTrackID_Invalid)
do {
let subTracks = subtitleAsset.tracks(withMediaType: AVMediaType.text)
guard let subTrack = subTracks.first else {
print("Can't get first subtitles track")
return
}
try subtitleTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), of: subTrack, at: kCMTimeZero)
} catch {
print(error)
return
}
// Prepare item and play it
let item = AVPlayerItem(asset: composition)
self.player = AVPlayer(playerItem: item)
self.playerLayer = AVPlayerLayer.init()
self.playerLayer.frame = self.bounds
self.playerLayer.contentsGravity = kCAGravityResizeAspect
self.playerLayer.player = player
self.layer.addSublayer(self.playerLayer)
self.player.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
self.player.play()
}
This procedure working well for .mp4 videos but not for HLS Videos(.m3u8). Does anyone have some working solution for this?
or
How can we get tracks from HLS videos using AVURLAsset? If this is not possible then how can I achieve a similar result?
Upvotes: 9
Views: 2547
Reputation: 1
If you're having trouble getting video tracks from AVURLAsset for HLS videos (.m3u8 format) in AVPlayer, here are some possible reasons and solutions:
Unlike MP4 files, HLS streams don’t always expose video tracks in the same way.
If the stream is DRM-protected, you may not be able to access tracks directly.
Make sure the .m3u8 file is accessible and properly formatted.
AVURLAsset needs to be loaded asynchronously before accessing tracks.
Upvotes: -1
Reputation: 11
I didn't have the exact same problem as you. But I got around a similar problem (querying for HDR) by instead of querying the tracks on the AVURLAsset, I queried the tracks on the AVPlayerItem.
Set up an observer on the item status:
player?.observe(\AVPlayer.currentItem?.status,
options: [.new, .initial], changeHandler: { [weak self] player, _ in
DispatchQueue.main.async {
self?.observedItemStatus(from: player)
}
})
Then query the AVMediaType of your choice (in your case text).
func observedItemStatus(from avPlayer: AVPlayer) {
guard let currentItem = avPlayer.currentItem else { return }
// ideally execute code based on currentItem.status...for the brevity of this example I won't.
let hasLegibleMedia = currentItem.tracks.first(where: {
$0.assetTrack?.mediaType == AVMediaType.text
})?.assetTrack.hasMediaCharacteristic(.legible)
}
Alternatively if you need more than just a Bool, you could do a loop to access the assetTrack you really want.
Upvotes: 1
Reputation: 31
For HLS video tracks(withMediaType: .video)
will return an empty array.
Use this instead: player.currentItem.presentationSize.width
and player.currentItem.presentationSize.height
.
Pls let me know if it works.
Upvotes: 2