You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AVAssetTrack获取高速视频nominalFrameRate始终为30的问题

问题:AVAssetTrack.nominalFrameRate在120/240FPS高速视频中始终返回30,60FPS视频正常

现象

使用PHPickerViewController读取视频后,通过AVAssetTrack获取nominalFrameRate时,120FPS和240FPS的高速视频始终返回30,但60FPS视频能正确返回60。

相关代码

PHPicker配置

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

选择器结果处理

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
}

帧率检查代码

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 videoTrack.load(.duration)
        
   print(fps) // 120/240FPS视频这里输出30
}

解决方案

1. 使用effectiveFrameRate替代nominalFrameRate

高速慢动作视频的nominalFrameRate对应的是播放帧率(比如30FPS,用于慢动作播放),而effectiveFrameRate才是视频实际的采样帧率(即拍摄时的120/240FPS)。修改帧率读取代码:

let fps = try? await videoTrack.load(.effectiveFrameRate)
print(fps) // 现在应该能正确返回120/240

2. 通过帧时长计算实际帧率

如果effectiveFrameRate仍无法获取正确值,可以通过视频轨道的minFrameDuration或maxFrameDuration计算真实帧率:

if let frameDuration = try? await videoTrack.load(.minFrameDuration) {
    let frameRate = Double(frameDuration.timescale) / Double(frameDuration.value)
    print("实际帧率:\(frameRate)")
}

原理:帧率 = 时间刻度(timescale) / 帧时长数值(value)

3. 确保PHPicker获取原始视频文件

默认情况下PHPicker可能返回适配过的视频版本,而非原始文件。修改配置强制获取原始视频:

configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = .videos
configuration.selectionLimit = 0
// 添加这行配置
configuration.preferredAssetRepresentationMode = .original

内容的提问来源于stack exchange,提问作者alwaysmemin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:02:07