From 6c24a94d5997789b5396efbb0644d3adcf74da7c Mon Sep 17 00:00:00 2001 From: kintan <kingslay@icloud.com> Date: Sun, 5 Nov 2023 22:56:57 +0800 Subject: [PATCH] add videoBitrate and audioBitrate --- Sources/KSPlayer/AVPlayer/KSAVPlayer.swift | 3 ++- .../AVPlayer/MediaPlayerProtocol.swift | 2 ++ Sources/KSPlayer/MEPlayer/KSMEPlayer.swift | 4 ++++ Sources/KSPlayer/MEPlayer/MEPlayerItem.swift | 20 +++++++++---------- .../KSPlayer/MEPlayer/MEPlayerItemTrack.swift | 17 ++++++++++++++++ Sources/KSPlayer/MEPlayer/Model.swift | 12 +++++++++++ .../MEPlayer/VideoToolboxDecode.swift | 6 +++--- .../KSPlayer/SwiftUI/KSVideoPlayerView.swift | 2 ++ 8 files changed, 52 insertions(+), 14 deletions(-) diff --git a/Sources/KSPlayer/AVPlayer/KSAVPlayer.swift b/Sources/KSPlayer/AVPlayer/KSAVPlayer.swift index 786bfa60c..a37c866f2 100644 --- a/Sources/KSPlayer/AVPlayer/KSAVPlayer.swift +++ b/Sources/KSPlayer/AVPlayer/KSAVPlayer.swift @@ -126,7 +126,8 @@ public class KSAVPlayer { public private(set) var duration: TimeInterval = 0 public private(set) var fileSize: Double = 0 public private(set) var playableTime: TimeInterval = 0 - + public var audioBitrate: Int = 0 + public var videoBitrate: Int = 0 public var playbackRate: Float = 1 { didSet { if playbackState == .playing { diff --git a/Sources/KSPlayer/AVPlayer/MediaPlayerProtocol.swift b/Sources/KSPlayer/AVPlayer/MediaPlayerProtocol.swift index 248e58f0c..0a0ed68ee 100644 --- a/Sources/KSPlayer/AVPlayer/MediaPlayerProtocol.swift +++ b/Sources/KSPlayer/AVPlayer/MediaPlayerProtocol.swift @@ -18,6 +18,8 @@ public protocol MediaPlayback: AnyObject { var fileSize: Double { get } var metadata: [String: String] { get } var naturalSize: CGSize { get } + var audioBitrate: Int { get } + var videoBitrate: Int { get } var currentPlaybackTime: TimeInterval { get } func prepareToPlay() func shutdown() diff --git a/Sources/KSPlayer/MEPlayer/KSMEPlayer.swift b/Sources/KSPlayer/MEPlayer/KSMEPlayer.swift index 64b3dddc0..748730884 100644 --- a/Sources/KSPlayer/MEPlayer/KSMEPlayer.swift +++ b/Sources/KSPlayer/MEPlayer/KSMEPlayer.swift @@ -327,6 +327,10 @@ extension KSMEPlayer: MediaPlayerProtocol { public var seekable: Bool { playerItem.seekable } + public var videoBitrate: Int { playerItem.videoBitrate } + + public var audioBitrate: Int { playerItem.audioBitrate } + public func seek(time: TimeInterval, completion: @escaping ((Bool) -> Void)) { let time = max(time, 0) playbackState = .seeking diff --git a/Sources/KSPlayer/MEPlayer/MEPlayerItem.swift b/Sources/KSPlayer/MEPlayer/MEPlayerItem.swift index f8ed4c18d..89815bc30 100644 --- a/Sources/KSPlayer/MEPlayer/MEPlayerItem.swift +++ b/Sources/KSPlayer/MEPlayer/MEPlayerItem.swift @@ -569,6 +569,14 @@ extension MEPlayerItem { // MARK: MediaPlayback extension MEPlayerItem: MediaPlayback { + var videoBitrate: Int { + Int(8 * (videoTrack?.bitrate ?? 0)) + } + + var audioBitrate: Int { + Int(8 * (audioTrack?.bitrate ?? 0)) + } + var seekable: Bool { guard let formatCtx else { return false @@ -766,11 +774,7 @@ extension MEPlayerItem: OutputRenderSourceDelegate { case .dropNextPacket: if let videoTrack = videoTrack as? AsyncPlayerItemTrack { _ = videoTrack.packetQueue.pop { item, _ -> Bool in - if let corePacket = item.corePacket { - return corePacket.pointee.flags & AV_PKT_FLAG_KEY != AV_PKT_FLAG_KEY - } else { - return false - } + !item.isKeyFrame } } case .dropGOPPacket: @@ -778,11 +782,7 @@ extension MEPlayerItem: OutputRenderSourceDelegate { var packet: Packet? = nil repeat { packet = videoTrack.packetQueue.pop { item, _ -> Bool in - if let corePacket = item.corePacket { - return corePacket.pointee.flags & AV_PKT_FLAG_KEY != AV_PKT_FLAG_KEY - } else { - return false - } + !item.isKeyFrame } } while packet != nil } diff --git a/Sources/KSPlayer/MEPlayer/MEPlayerItemTrack.swift b/Sources/KSPlayer/MEPlayer/MEPlayerItemTrack.swift index 96368488d..dfbe6f03f 100644 --- a/Sources/KSPlayer/MEPlayer/MEPlayerItemTrack.swift +++ b/Sources/KSPlayer/MEPlayer/MEPlayerItemTrack.swift @@ -107,7 +107,24 @@ class SyncPlayerItemTrack<Frame: MEFrame>: PlayerItemTrackProtocol, CustomString outputRenderQueue.shutdown() } + private var lastPacketBytes = Int32(0) + private var lastPacketSeconds = Double(-1) + var bitrate = Double(0) fileprivate func doDecode(packet: Packet) { + if packet.isKeyFrame, packet.assetTrack.mediaType != .subtitle { + let seconds = packet.seconds + let diff = seconds - lastPacketSeconds + if lastPacketSeconds < 0 || diff < 0 { + bitrate = 0 + lastPacketBytes = 0 + lastPacketSeconds = seconds + } else if diff > 0.5 { + bitrate = Double(lastPacketBytes) / diff + lastPacketBytes = 0 + lastPacketSeconds = seconds + } + } + lastPacketBytes += packet.size let decoder = decoderMap.value(for: packet.assetTrack.trackID, default: makeDecode(assetTrack: packet.assetTrack)) decoder.decodeFrame(from: packet) { [weak self] result in guard let self else { diff --git a/Sources/KSPlayer/MEPlayer/Model.swift b/Sources/KSPlayer/MEPlayer/Model.swift index f21c96840..54bad2d21 100644 --- a/Sources/KSPlayer/MEPlayer/Model.swift +++ b/Sources/KSPlayer/MEPlayer/Model.swift @@ -176,6 +176,18 @@ final class Packet: ObjectQueueItem { var size: Int32 = 0 var assetTrack: FFmpegAssetTrack! private(set) var corePacket = av_packet_alloc() + var isKeyFrame: Bool { + if let corePacket { + return corePacket.pointee.flags & AV_PKT_FLAG_KEY == AV_PKT_FLAG_KEY + } else { + return false + } + } + + var seconds: Double { + assetTrack.timebase.cmtime(for: position).seconds + } + func fill() { guard let corePacket else { return diff --git a/Sources/KSPlayer/MEPlayer/VideoToolboxDecode.swift b/Sources/KSPlayer/MEPlayer/VideoToolboxDecode.swift index f673c096e..b8d7b40f5 100644 --- a/Sources/KSPlayer/MEPlayer/VideoToolboxDecode.swift +++ b/Sources/KSPlayer/MEPlayer/VideoToolboxDecode.swift @@ -50,7 +50,7 @@ class VideoToolboxDecode: DecodeProtocol { } guard status == noErr else { if status == kVTInvalidSessionErr || status == kVTVideoDecoderMalfunctionErr || status == kVTVideoDecoderBadDataErr { - if corePacket.flags & AV_PKT_FLAG_KEY == 1 { + if packet.isKeyFrame { completionHandler(.failure(NSError(errorCode: .codecVideoReceiveFrame, avErrorCode: status))) } } @@ -59,7 +59,7 @@ class VideoToolboxDecode: DecodeProtocol { let frame = VideoVTBFrame(fps: session.assetTrack.nominalFrameRate) frame.corePixelBuffer = imageBuffer frame.timebase = session.assetTrack.timebase - if packetFlags & AV_PKT_FLAG_KEY == 1, packetFlags & AV_PKT_FLAG_DISCARD != 0, self.lastPosition > 0 { + if packet.isKeyFrame, packetFlags & AV_PKT_FLAG_DISCARD != 0, self.lastPosition > 0 { self.startTime = self.lastPosition - pts } self.lastPosition = max(self.lastPosition, pts) @@ -72,7 +72,7 @@ class VideoToolboxDecode: DecodeProtocol { if status == noErr { VTDecompressionSessionWaitForAsynchronousFrames(session.decompressionSession) } else if status == kVTInvalidSessionErr || status == kVTVideoDecoderMalfunctionErr || status == kVTVideoDecoderBadDataErr { - if corePacket.flags & AV_PKT_FLAG_KEY == 1 { + if packet.isKeyFrame { throw NSError(errorCode: .codecVideoReceiveFrame, avErrorCode: status) } else { // 解决从后台切换到前台,解码失败的问题 diff --git a/Sources/KSPlayer/SwiftUI/KSVideoPlayerView.swift b/Sources/KSPlayer/SwiftUI/KSVideoPlayerView.swift index 1b6a67784..8642da4e5 100644 --- a/Sources/KSPlayer/SwiftUI/KSVideoPlayerView.swift +++ b/Sources/KSPlayer/SwiftUI/KSVideoPlayerView.swift @@ -523,6 +523,8 @@ struct VideoSettingView: View { subtitleModel.searchSubtitle(query: subtitleTitle, languages: ["zh-cn"]) } Text("Stream Type: \((videoTracks?.first { $0.isEnabled }?.fieldOrder ?? .progressive).description)") + Text("Audio bitrate: \(config.playerLayer?.player.audioBitrate ?? 0) b/s") + Text("Video bitrate: \(config.playerLayer?.player.videoBitrate ?? 0) b/s") if let fileSize = config.playerLayer?.player.fileSize, fileSize > 0 { Text("File Size: \(String(format: "%.1f", fileSize / 1_000_000))MB") }