如何在AVPlayer中获取HLS流的视频大小?

23

我正在尝试在播放HLS流时获取视频分辨率。 我有典型的播放器初始化:

let urlAsset = AVURLAsset(URL: currentVideoUrl)
 self.player=AVPlayer(playerItem: AVPlayerItem(asset:urlAsset))
 .......

我使用KVO,当AVPlayerItem的状态为.ReadyToPlay时,我试图获取视频大小:

    func resolutionSizeForVideo() {

    guard let videoTrack = self.player.currentItem?.asset.tracksWithMediaType(AVMediaTypeVideo).first else
    { return
    }

    let size = CGSizeApplyAffineTransform(videoTrack.naturalSize, videoTrack.preferredTransform)
    let frameSize = CGSize(width: fabs(size.width), height: fabs(size.height))
    print ("video size: \(frameSize)")

}

问题在于tracksWithMediaType()总是返回空数组(但对于非流文件有效,例如.mov文件)。

如何获取AVPlayer内播放的HLS视频的大小(CGRect)?


“Size” 是指什么?视频的实际分辨率还是播放器层的矩形区域? - JAL
视频分辨率,是的(编辑了问题)。 - DixieFlatline
4个回答

15

你能用这种方法至少记录视频信息吗?

extension AVAsset{
    func videoSize()->CGSize{
        let tracks = self.tracks(withMediaType: AVMediaType.video)
        if (tracks.count > 0){
            let videoTrack = tracks[0]
            let size = videoTrack.naturalSize
            let txf = videoTrack.preferredTransform
            let realVidSize = size.applying(txf)
            print(videoTrack)
            print(txf)
            print(size)
            print(realVidSize)
            return realVidSize
        }
        return CGSize(width: 0, height: 0)
    }

}

let videoAssetSource = AVAsset.init(URL: videoURL)
print("size:",videoAssetSource.videoSize())

10
对于m3u8资产,调用tracksWithMediaType(AVMediaTypeVideo)方法返回一个空的数组,因此这段代码会导致索引越界异常。 - FateNuller
对于 HLS,这个 let tracks = self.tracks(withMediaType: AVMediaType.video) 将会是一个空数组。 - mgyky

14

当使用HLS时,轨道(tracks)将始终返回nil。如果您有一个UIView子类,其使用AVPlayerLayer覆盖其layerClass以播放视频,则可以使用以下代码获取视频大小:

playerView.layer.videoRect

这是仅视频的大小,不包括整个图层。

或者您可以使用KVO来观察项目的presentationSize。

player.addObserver(self, forKeyPath: "currentItem.presentationSize", options: [.Initial, .New], context: nil)

我之前尝试使用KVO(presentationSize)但它没有返回视频分辨率。 - DixieFlatline
3
你可以随时使用player.currentItem.presentationSize来获取媒体的分辨率,KVO只是为了方便而已。这将提供给你分辨率信息。在定期观察器中输出此命令是 print(self?.mediaPlayer?.currentItem?.presentationSize) --> Optional((853.333312988281, 480.0)) - Max
2
曾经评论说presentationSize不是资产的本机大小,而实际上是播放器中视频的大小,但这似乎不正确。在我的应用程序中,即使在横向和纵向之间切换时,持续打印出的大小仍然是1280x720。由于技术上不正确,因此删除了先前的评论。 - FateNuller
1
我想指出一些事情 - 在currentItem.presentationSize上进行KVO是正确的方法,但如果播放器项目尚未准备好播放,则仍可能返回CGSizeZero - Anjan Biswas
这不提供显示前的访问权限。 - ScottyBlades

4
你可以简洁地这样做:
import AVKit

extension AVAsset {

    var videoSize: CGSize? {
        tracks(withMediaType: .video).first.flatMap {
            tracks.count > 0 ? $0.naturalSize.applying($0.preferredTransform) : nil
        }
    }
}


0
我们可以使用新的实现方式,因为之前的方式已经被废弃了(自iOS 16及更高版本开始)。
import AVKit
import Foundation

extension AVAsset {
    func videoSize() async throws -> CGSize? {
        guard let track = try await loadTracks(withMediaType: .video).first else { return nil }
        let size = try await track.load(.naturalSize)
        return size
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接