import AVFoundation import UIKit import os.log /// 媒体工具类,提供视频处理相关功能 enum MediaUtils { private static let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "com.example.app", category: "MediaUtils") /// 从视频URL中提取第一帧 /// - Parameters: /// - videoURL: 视频文件的URL /// - completion: 完成回调,返回UIImage或错误 static func extractFirstFrame(from videoURL: URL, completion: @escaping (Result) -> Void) { let asset = AVURLAsset(url: videoURL) let assetImgGenerate = AVAssetImageGenerator(asset: asset) assetImgGenerate.appliesPreferredTrackTransform = true // 获取视频时长 let duration = asset.duration let durationTime = CMTimeGetSeconds(duration) // 如果视频时长小于等于0,返回错误 guard durationTime > 0 else { let error = NSError(domain: "com.yourapp.media", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid video duration"]) completion(.failure(error)) return } // 获取第一帧(时间点为0) let time = CMTime(seconds: 0, preferredTimescale: 600) // 生成图片 assetImgGenerate.generateCGImagesAsynchronously(forTimes: [NSValue(time: time)]) { (_, cgImage, _, result, error) in if let error = error { logger.error("Failed to generate image: \(error.localizedDescription)") DispatchQueue.main.async { completion(.failure(error)) } return } guard result == .succeeded, let cgImage = cgImage else { let error = NSError(domain: "com.yourapp.media", code: -2, userInfo: [NSLocalizedDescriptionKey: "Failed to generate image from video"]) logger.error("Failed to generate image: \(error.localizedDescription)") DispatchQueue.main.async { completion(.failure(error)) } return } // 创建UIImage并返回 let image = UIImage(cgImage: cgImage) DispatchQueue.main.async { completion(.success(image)) } } } /// 从视频数据中提取第一帧 /// - Parameters: /// - videoData: 视频数据 /// - completion: 完成回调,返回UIImage或错误 static func extractFirstFrame(from videoData: Data, completion: @escaping (Result) -> Void) { // 创建临时文件URL let tempDirectoryURL = FileManager.default.temporaryDirectory let fileName = "tempVideo_\(UUID().uuidString).mov" let fileURL = tempDirectoryURL.appendingPathComponent(fileName) do { // 将数据写入临时文件 try videoData.write(to: fileURL) // 调用URL版本的方法 extractFirstFrame(from: fileURL) { result in // 清理临时文件 try? FileManager.default.removeItem(at: fileURL) completion(result) } } catch { logger.error("Failed to write video data to temporary file: \(error.localizedDescription)") completion(.failure(error)) } } }