How to find AVPlayer current bitrate
Asked Answered
T

2

6

I am trying to fetch bit rate at which the AVPlayer is playing the video stream . I tried with observed bit rate property of AVPlayerItemAccessLogEvent , but it gives very high value.After exploring further on Observed-bit-rate property I understood that this property shows the value of download rate of a segment.I need to know the bit rate at which the player is playing the stream.

The graph below shows Observed bit vs Indicated bit rate for the LIVE stream. enter image description here

Kindly give your suggestion on this issue.

I tried the following link but no luck :

https://mcmap.net/q/1769814/-determening-mpmoviecontroller-bit-rate.

MPMoviePlayerController MovieAccessLogEvent - Inflated observedBitrate.

Trochilus answered 4/9, 2015 at 21:29 Comment(0)
E
13

You are right about observedBitrate. That shows the download speed.

The indicatedBitrate should tell you the advertised bitrate required to play the current stream. I believe that value comes from the HLS master manifest. When playing a stream that does not have multiple bitrate variants, and there's only one bitrate variant available, the value of indicatedBitrate will be -1.

If you are always dealing with streams that have a master manifest, then indicatedBitrate is the best option.

If you are dealing with streams that don't have a master manifest, then one way to estimate the bitrate is to grab the last AVPlayerItemAccessLogEvent entry, and calculate it using:

numberOfBitsTransferred = (numberOfBytesTransferred * 8)
numberOfBitsTransferred / segmentsDownloadedDuration

Empirically speaking, every time the player switches bitrate, it will post a new access log entry. The latest access log entry will contain data about the most recently selected stream.

Espresso answered 8/9, 2015 at 2:55 Comment(13)
thanks for your reply , regarding indicatedBitrate - as per my understanding this is the required bit rate to play the stream and it is indicated by the server . I want to find the bit rate at which the avplayer is playing the stream . Can you please help me to understand the indicatedBitrate and also I want to know whether this indicates the current bit rate of the player . FYI - all my streams have master manifest.Trochilus
As Anurag said, the indicatedBitrate is simply the 'BANDWIDTH' parameter from the currently playing m3u8 variant playlist. Depending on your HLS server, this could have any value in it. If there is no master playlist, then this value is set to -1 meaning that the playlist 'does not indicate a bitrate'. With a well-behaved HLS server, using variant playlists, this value should be fairly accurate but to get the current network bitrate, use Anurag's formula: bitrate(in bits/second) = (logEvent.numberOfBytesTransferred * 8) / logEvent.segmentsDownloadedDurationHoofbound
@Trochilus - I hope Simon's comment further clarifies the purpose of the indicatedBitrate property. Please let me know if you have additional questions regarding that.Espresso
Thanks @SimonTillson, anurag, I will check with the formula that you have and update you on this ... Thanks.Trochilus
@Anurag, I find your formula is good with most of the cases however I find sometimes segmentsDownloadedDuration is 0 where as numberOfBytesTransferred is175990 , so the calculation goes wrong , do you have any idea on why access logs throws zero for segmentsDownloadedDuration.Trochilus
@Trochilus - I'm not sure but you should file a bug with Apple at radar.apple.com because according to the documentation this value should be negative if unknown, and not zero - The value of this property is negative if unknown. In pretty much all cases, I would imagine that 175KB worth of video data should represent data for some amount of time that is greater than zero.Espresso
I wonder if maybe segmentsDownloadedDuration of zero means that the player timed out while trying to download a chunk? Seems best to ignore logEvents with that value :-)Hoofbound
@Anurag, Sure I will do it . Do you have an idea about when the access logs will generate in AVPlayer , I mean when I will get new access logs .Trochilus
@Trochilus - afaik, everytime the a different bitrate is selected by AVPlayer, a new access log entry gets addedEspresso
Also you can register for the notification AVPlayerItemNewAccessLogEntryNotification to know when a new log entry has been added.Hoofbound
Thanks for the info simon , @Espresso , In your formula segmentsDownloadedDuration is used to calculate the observed bit rate , whereas here https://mcmap.net/q/1769814/-determening-mpmoviecontroller-bit-rate , durationWatched is used to calculate the observed bit rate.Can you please explain why you have included segmentsDownloadedDuration instead of durationWatched and the difference between the two.Trochilus
durationWatched tells us how much of the content has been watched/listened to by the user. That is purely dependent on the user. A movie may be fully downloaded but the user could have watched just 1 second of it. Suppose if the movie was 100MB, and 1 second was watched, that will give 100MBps which doesn't make any sense.Espresso
@Espresso one small observation, why is Event. observedBitrate is not same as the download speed calculated by the formula? - bitrate(in bits/second) = (logEvent.numberOfBytesTransferred * 8) / logEvent.segmentsDownloadedDuration. I could see a huge difference and usually observed bitrate is bigger than the result formed by the formula.Festal
M
1

I followed Anurag's answer and it gave me the desired solution, however I noticed the same value could be obtained using the AVPlayerItem's access log event's averageAudioBitrate or averageVideoBitrate property depending on what interests you.

Here is how I set this up in Swift 5

NotificationCenter.default.addObserver(forName: .AVPlayerItemNewAccessLogEntry,
                                             object: playerItem,
                                             queue: nil) { [weak self] notification in
        if let event = self?.playerItem?.accessLog()?.events.last {
          
          let bitsTransferred = Double(event.numberOfBytesTransferred * 8)
          let bitrate =  bitsTransferred / Double(event.segmentsDownloadedDuration)
          
          print("Calculated Bit Rate: \(bitrate)")
          
          // This gives the same value as Anurag's answer
          print("Average Bit Rate: \(event.averageAudioBitrate)")
        }
}

I would also like to add that getting this notification to be fired is far from reliable with live streams.

Miso answered 19/6, 2021 at 17:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.