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

SwiftUI VideoPlayer加载视频过慢及控制台报错的解决咨询

问题

我正在开发一款视频处理应用,使用SwiftUI的VideoPlayer组件及PHPickerViewController的封装类,将视频从相机胶卷复制至临时目录后,加载一段1分52秒的视频耗时长达10秒。相关代码如下:

import SwiftUI
import PhotosUI
import AVKit

struct ContentView: View {
    @State private var isShowingPicker = false
    @State private var videoURL: URL?
    
    var body: some View {
        VStack {
            Button("Select Video") {
                isShowingPicker = true
            }
            
            if let videoURL = videoURL {
                VideoPlayer(player: AVPlayer(url: videoURL))
                    .frame(height: 300)
            }
        }
        .sheet(isPresented: $isShowingPicker) {
            PHPickerViewControllerWrapper(videoURL: $videoURL)
        }
    }
}

struct PHPickerViewControllerWrapper: UIViewControllerRepresentable {
    @Binding var videoURL: URL?
    
    func makeUIViewController(context: Context) -> PHPickerViewController {
        var configuration = PHPickerConfiguration()
        configuration.filter = .videos
        configuration.selectionLimit = 1
        
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = context.coordinator
        
        return picker
    }
    
    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: PHPickerViewControllerDelegate {
        let parent: PHPickerViewControllerWrapper
        
        init(_ parent: PHPickerViewControllerWrapper) {
            self.parent = parent
        }
        
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            guard let result = results.first else { return }
            
            result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { (url, error) in
                guard let url = url else {return}
                let fileName = "\(Int(Date().timeIntervalSince1970)).\(url.pathExtension)"
                let newUrl = URL(fileURLWithPath: NSTemporaryDirectory() + fileName)
                try? FileManager.default.linkItem(at: url, to: newUrl)
                DispatchQueue.main.async {
                    self.parent.videoURL = newUrl
                    picker.dismiss(animated: true)
                }
            }
        }
    }
}

运行时控制台出现以下报错信息:

2023-05-24 08:01:06.964329-0300 videoLoader[2846:964095] [api] -[CIImage initWithCVPixelBuffer:options:] failed because the buffer is nil.
2023-05-24 08:01:07.041494-0300 videoLoader[2846:964651] [TextIdentificationService] Text LID dominant failure: lidInconclusive
2023-05-24 08:01:07.041839-0300 videoLoader[2846:964651] [VisualTranslationService] Visual isTranslatable: NO; not offering translation: lidInconclusive
2023-05-24 08:01:07.080261-0300 videoLoader[2846:964095] [api] -[CIImage initWithCVPixelBuffer:options:] failed because the buffer is nil.
2023-05-24 08:01:08.008267-0300 videoLoader[2846:964651] Metal API Validation Enabled

请问如何优化视频加载性能?如何消除这些控制台报错信息?


优化视频加载性能

1. 移除不必要的文件链接操作

loadFileRepresentation返回的URL本身就是沙盒内的临时文件,无需额外创建链接。删除linkItem相关代码,直接使用原URL,节省文件操作耗时:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    guard let result = results.first else { return }
    
    result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { (url, error) in
        guard let url = url else {return}
        DispatchQueue.main.async {
            self.parent.videoURL = url
            picker.dismiss(animated: true)
        }
    }
}

2. 异步预加载视频资源

避免主线程阻塞,后台加载视频元数据后再初始化播放器:

// 在ContentView中添加
@State private var player: AVPlayer?

.onChange(of: videoURL) { newURL in
    guard let newURL = newURL else {
        player = nil
        return
    }
    Task {
        let asset = AVAsset(url: newURL)
        await asset.loadValuesAsynchronously(forKeys: ["playable"])
        if asset.statusOfValue(forKey: "playable", error: nil) == .loaded {
            await MainActor.run {
                player = AVPlayer(playerItem: AVPlayerItem(asset: asset))
            }
        }
    }
}

// 修改视频显示部分
if let player = player {
    VideoPlayer(player: player)
        .frame(height: 300)
}

3. 调整播放器缓冲策略

通过AVPlayerItem设置缓冲时长,平衡加载速度与内存占用:

let playerItem = AVPlayerItem(asset: asset)
playerItem.preferredForwardBufferDuration = 5.0 // 提前缓冲5秒内容
player = AVPlayer(playerItem: playerItem)

消除控制台报错信息

1. 解决CIImage初始化失败报错

手动生成视频缩略图,避免系统自动尝试时出错:

// 新增缩略图生成方法
func generateThumbnail(for url: URL) async -> UIImage? {
    let asset = AVAsset(url: url)
    let generator = AVAssetImageGenerator(asset: asset)
    generator.appliesPreferredTrackTransform = true
    do {
        let cgImage = try generator.copyCGImage(at: .zero, actualTime: nil)
        return UIImage(cgImage: cgImage)
    } catch {
        return nil
    }
}

// 在加载视频时调用
Task {
    let _ = await generateThumbnail(for: newURL)
}

2. 禁用文本识别相关服务

修改PHPickerConfiguration,关闭自动文本识别功能:

var configuration = PHPickerConfiguration()
configuration.filter = .videos
configuration.selectionLimit = 1
configuration.preferredAssetRepresentationMode = .current
configuration.showsAssetBadges = false

3. 关闭Metal API Validation提示

在Xcode的Scheme设置中,进入Run -> Arguments -> Environment Variables,移除METAL_API_VALIDATION_ENABLED或设置为NO,发布版本会自动关闭该验证。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 18:40:45