AVAssetTrack nominalFrameRate is always 30 for high speed videos

For some reason the AVAssetTrack nominalFrameRate is always 30 for high speed videos. 120 FPS and 240 FPS videos' nominalFrameRate property is always 30. However, 60 FPS videos' nominalFrameRate is 60. I'm reading in the video url through the PHPickerViewController. I have a configuration for the picker set up as follows.

configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = .videos
configuration.selectionLimit = 0

and the gathering of the picker results as follows

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    for result in results {
        var currentVideo = Video()
        let provider = result.itemProvider
                
        provider.loadFileRepresentation(forTypeIdentifier: "public.movie") { url, error in
            guard error == nil else {
                return
            }
                    
            guard let url = url else {return}
                    
            // create a new filename
            let fileName = "\(Int(Date().timeIntervalSince1970)).\(url.pathExtension)"
            let newUrl = URL(fileURLWithPath: NSTemporaryDirectory() + fileName)
                    
            // copy item to APP Storage
            try? FileManager.default.copyItem(at: url, to: newUrl)
            currentVideo.url = newUrl.absoluteString
            self.parent.selectedVideos.append(currentVideo)
        }
    }

    // Set isPresented to false because picking has finished.
    parent.isPresented = false
}

I'm creating an AVAsset and AVAssetTrack to check the FPS of the video as follows.

var asset: AVAsset? = AVAsset(url: url)
    if let asset = asset,
       let videoTrack = try? await asset.loadTracks(withMediaType: .video).last {

       let size = try? await videoTrack.load(.naturalSize)
       let fps = try? await videoTrack.load(.nominalFrameRate)
       let duration = try? await test.load(.duration)
            
       print(fps) // This shows 30 for 120 fps and 240 fps videos
    }

I'm not sure if there's some other configuration that needs to be set to handle high speed videos or what. I'm really confused.

Answered by alwaysmemin in 759829022

I figured it out. The issue was the way I was creating the AVAssets. Instead of pulling them in from a copied url I used the localIdentifiers to fetch the assets with a defined set of options. The code below works for obtaining the correct FPS for a selected asset.

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            let identifiers = results.compactMap(\.assetIdentifier)
            let assets = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
            
            if (assets.count == 0) {
                parent.isPresented = false
                return
            }
            
            var assetArray: [PHAsset] = []
            for i in 0...(assets.count - 1) {
                assetArray.append(assets[i])
            }
            
            let options = PHVideoRequestOptions()
            options.version = .original

            for asset in assetArray {
                PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { avAsset, avAudioMix, info in
                   var currentVideo = Video()
                   currentVideo.asset = avAsset
                   self.parent.selectedVideos.append(currentVideo)
                }
            }
            // Set isPresented to false because picking has finished.
            parent.isPresented = false
        }

I hope this helps!

Accepted Answer

I figured it out. The issue was the way I was creating the AVAssets. Instead of pulling them in from a copied url I used the localIdentifiers to fetch the assets with a defined set of options. The code below works for obtaining the correct FPS for a selected asset.

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            let identifiers = results.compactMap(\.assetIdentifier)
            let assets = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
            
            if (assets.count == 0) {
                parent.isPresented = false
                return
            }
            
            var assetArray: [PHAsset] = []
            for i in 0...(assets.count - 1) {
                assetArray.append(assets[i])
            }
            
            let options = PHVideoRequestOptions()
            options.version = .original

            for asset in assetArray {
                PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { avAsset, avAudioMix, info in
                   var currentVideo = Video()
                   currentVideo.asset = avAsset
                   self.parent.selectedVideos.append(currentVideo)
                }
            }
            // Set isPresented to false because picking has finished.
            parent.isPresented = false
        }

I hope this helps!

AVAssetTrack nominalFrameRate is always 30 for high speed videos
 
 
Q