swift - 无法从 AVURLAsset 为 AVPlayer 获取 HLS 视频(.m3u8 格式)的视频轨道?

标签 swift avfoundation avplayer m3u8 avkit

我正在开发一个自定义视频播放器来从服务器流式传输 HLS 视频。我可以使用 AVPlayerItem 和 AVPlayer 成功播放 HLS 视频。

之后,我想为我的视频播放器添加字幕轨道和音轨。所以我使用 AVMutableComposition 来做到这一点。所以现在的问题是,当我为 HLS 视频创建 AVURLAsset 时,我无法从 AVURLAsset 获取视频轨道。它总是给我 0 首轨道。我尝试了 AVURLAsset 的“loadValuesAsynchronously”,并尝试为 AVPlayerItem 的“轨道”添加 KVO。但这些都没有给我带来任何积极的结果。

我正在使用以下代码。

  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()
}

此过程适用于 .mp4 视频,但不适用于 HLS 视频 (.m3u8)。有人对此有一些可行的解决方案吗?

或者

我们如何使用 AVURLAsset 从 HLS 视频中获取轨道?如果这是不可能的,那么如何才能达到类似的结果?

请让我知道您的反馈。

提前致谢。

最佳答案

我没有和你完全一样的问题。但是我解决了一个类似的问题(查询 HDR),而不是查询 AVURLAsset 上的轨道,而是查询 AVPlayerItem 上的轨道。
在项目状态上设置观察者:

player?.observe(\AVPlayer.currentItem?.status,
                                         options: [.new, .initial], changeHandler: { [weak self] player, _ in
                                            DispatchQueue.main.async {
                                                self?.observedItemStatus(from: player)
                                            }
                                         })
然后查询您选择的 AVMediaType(在您的情况下为文本)。
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)
}
或者,如果您需要的不仅仅是一个 Bool,您可以执行一个循环来访问您真正想要的 assetTrack。

关于swift - 无法从 AVURLAsset 为 AVPlayer 获取 HLS 视频(.m3u8 格式)的视频轨道?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52409687/

相关文章:

ios - Swift 3 核心数据 NSExpression 始终返回 0

swift - 无法更改闭包中的结构实例值

swift - UIprogressview 栏根据进度和条件使用多种颜色

swift - 将 CoreMIDI 输入与 AVAudioUnit 结合使用

ios - 获取 mp3 文件指定时间范围的字节范围位置

swift - 如何使用 swift 为 sqlite 提供数据库路径

objective-c - 如何为 AVMetadataFormatiTunesMetadata 创建 AVMutableMetadataItem

ios - AVPlayerLayer 显示黑屏但声音正常

objective-c - 如何在 AVPlayer 中播放 Youtube 视频?

ios - AVPlayer 不播放没有音频的 HTTP 直播流