IOS AVPlayer get fps

前端 未结 6 662
渐次进展
渐次进展 2021-01-18 10:59

Im trying to figure out how to retrieve a videos frame rate via AVPlayer. AVPlayerItem has a rate variable but it only returns a value between 0 and 2 (usually 1 when playin

相关标签:
6条回答
  • 2021-01-18 11:15

    This is not gonna work anymore, API has changed, and this post is old. :( The swift 4 answer is also cool, this is answer is similar.

    You get the video track from the AVPlayerItem, and you check the FPS there. :)

    private var numberOfRenderingFailures = 0
    func isVideoRendering() -> Bool {
        guard let currentItem = player.currentItem else { return false }
    
        // Check if we are playing video tracks
        let isRendering = currentItem.tracks.contains { ($0.assetTrack?.mediaType == .video) && ($0.currentVideoFrameRate > 5) }
        if isRendering {
            numberOfRenderingFailures = 0
            return true
        }
        numberOfRenderingFailures += 1
        if numberOfRenderingFailures < 5 {
            return true
        }
        return false
    }
    
    0 讨论(0)
  • 2021-01-18 11:17

    There seems to be a discrepancy in this nominalFrameRate returned for the same media played on different versions of iOS. I have a video I encoded with ffmpeg at 1 frame per second (125 frames) with keyframes every 25 frames and when loading in an app on iOS 7.x the (nominal) frame rate is 1.0, while on iOS 8.x the (nominal) frame rate is 0.99. This seems like a very small difference, however in my case I need to navigate precisely to a given frame in the movie and this difference screws up such navigation (the movie is an encoding of a sequence of presentation slides). Given that I already know the frame rate of the videos my app needs to play (e.g. 1 fps) I can simply rely on this value instead of determining the frame rate dynamically (via nominalFrameRate value), however I wonder WHY there is such discrepancy between iOS versions as far as this nominalFrameRate goes. Any ideas?

    0 讨论(0)
  • 2021-01-18 11:24

    The rate value on AVPlayer is the speed relative to real time to which it's playing, eg 0.5 is slow motion, 2 is double speed.

    As Paresh Navadiya points out a track also has a nominalFrameRate variable however this seems to sometimes give strange results. the best solution I've found so far is to use the following:

    CMTime frameDuration = [myAsset tracksWithMediaType:AVMediaTypeVideo][0].minFrameDuration;
    float fps = frameDuration.timescale/(float)frameDuration.value;
    

    The above gives slightly unexpected results for variable frame rate but variable frame rate has slightly odd behavior anyway. Other than that it matches ffmpeg -i in my tests.

    EDIT ----

    I've found sometimes the above gives time kCMTimeZero. The workaround I've used for this is to create an AVAssetReader with a track output,get the pts of the first frame and second frame then do a subtraction of the two.

    0 讨论(0)
  • 2021-01-18 11:25

    Use AVAssetTrack's nominalFrameRate property.

    Below method to get FrameRate : Here queuePlayer is AVPlayer

    -(float)getFrameRateFromAVPlayer
    {
      float fps=0.00;
      if (self.queuePlayer.currentItem.asset) {
        AVAssetTrack * videoATrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] lastObject];
        if(videoATrack)
        {
            fps = videoATrack.nominalFrameRate;
        }
      }
      return fps;
    }
    
    0 讨论(0)
  • 2021-01-18 11:33

    I don't know anything in AVPlayer that can help you to calculate the frame rate.

    AVPlayerItem rate property is the playback rate, nothing to do with the frame rate.

    The easier options is to obtain a AVAssetTrack and read its nominalFrameRate property. Just create an AVAsset and you'll get an array of tracks.

    Or use AVAssetReader to read the video frame by frame, get its presentation time and count how many frames are in the same second, then average for a few seconds or the whole video.

    0 讨论(0)
  • 2021-01-18 11:39

    Swift 4 version of the answer:

    let asset = avplayer.currentItem.asset
    
    let tracks = asset.tracks(withMediaType: .video)
    
    let fps = tracks?.first?.nominalFrameRate
    

    Remember to handle nil checking.

    0 讨论(0)
提交回复
热议问题