swiftavassetphpickerviewcontroller

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.


Solution

  • 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!