🐈

AVPlayerのdurationの取得

2024/04/24に公開

AVPlayerのdurationの取得

解決策

AVPlayerからではなく、AVAssetからdurationを取得する。

# これで正しい値が取得できました。
let asset = AVURLAsset(url: validURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
let assetDuration = try await CMTimeGetSeconds(asset.load(.duration))
print ("asset duration :", assetDuration)

これでも1秒2秒の誤差があるものの、使える程度の値が取得できました。

private var player = AVPlayer()
var duration: TimeInterval {
guard let playerItem = player.currentItem, playerItem.status == .readyToPlay else {
    return 0.0
}
return CMTimeGetSeconds(playerItem.duration)
}

もしくは、これでも誤差がありますが取得できました。
(これだとduplicatedしているという警告が出ます。)

private var player = AVPlayer()
var duration: TimeInterval {
guard let playerItem = player.currentItem, playerItem.status == .readyToPlay else {
    return 0.0
}
return CMTimeGetSeconds(playerItem.asset.duration)
}

背景と試したこと

AVPlayerでmp3のdurationを取得したかったのですが、
以下のコードではdurationの値が大きくなったり小さくなったりして正しく取得できませんでした。


# 試したコード1

do {
    if let currentItem = self.audioPlayer?.currentItem {
        let durationSeconds = try await CMTimeGetSeconds(currentItem.asset.load(.duration))
        print ("durationSeconds :", durationSeconds)
    }
} catch {
    print("Error: \(error)")
}


# 試したコード2
# 読み込みのタイミング関連しているかもしれないと思い以下のコードを試しましたが同じ結果でした。

func loadDuration(of url: URL) async {
    let asset = AVAsset(url: url)
    
    // Create an array containing the asset keys we need to be loaded
    let keys = ["duration"]
    
    await withCheckedContinuation { continuation in
        // Load the asset's keys asynchronously
        asset.loadValuesAsynchronously(forKeys: keys) {
            // The keys are loaded, now access the duration
            var error: NSError?
            let status = asset.statusOfValue(forKey: "duration", error: &error)
            
            if status == .loaded {
                let duration = asset.duration
                let durationSeconds = CMTimeGetSeconds(duration)
                
                DispatchQueue.main.async {
                    print("Duration seconds:", self.timeString(time: durationSeconds))
                    continuation.resume()
                }

            } else if status == .failed {
                print("Failed to load duration with error: \(String(describing: error))")
                continuation.resume(throwing: (error ?? NSError(domain: "AVAssetDurationError", code: 0, userInfo: nil)) as! Never)
            } else {
                print("Duration not available yet.")
                continuation.resume()
            }
        }
    }
}
  

環境

Xcode Version 15.2

参考

iOS 11 AVPlayer/mp3 currentTime not accurate

GitHubで編集を提案

Discussion