如何在 Swift 中获取 AVAsset 的视频持续时间

问题描述 投票:0回答:1

当尝试使用 .duration 来获取视频的长度时,我收到警告“'duration' 在 iOS 16.0 中被弃用:改为使用 load(.duration)”,但是当我尝试使用 load(.duration) 时,我得到FileStorage.uploadVideo(videoData, directory: fileDirectory) 上的错误“没有更多上下文的表达式类型不明确”。

使用时长

   func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true, completion: nil)
        let currentUser = FUser.currentUser()!

        let message = Message()

        message.id = UUID().uuidString
        message.chatRoomId = chatId
        message.senderId = currentUser.objectId
        message.senderName = currentUser.username

        message.sentDate = Date()
        message.senderInitials = String(currentUser.username.first!)
        message.status = kSENT
        message.message = "Video Message"

        if let videoUrl = info[.mediaURL] as? URL {
            let fileName = Date().stringDate()
            let fileDirectory = "MediaMessages/Video/" + "\(chatId)/" + "_\(fileName)" + ".mov"

            do {
                let videoData = try NSData(contentsOf: videoUrl, options: .mappedIfSafe)
                FileStorage.saveVideoLocally(videoData: videoData , fileName: fileName)
                FileStorage.uploadVideo(videoData, directory: fileDirectory) { (videoURL) in

                    if let videoURL = videoURL, let url = URL(string: videoURL) {
                        let video = AVURLAsset(url: url)
                        let duration = video.duration.seconds

                        if duration > 30 {
                            let alert = UIAlertController(title: "Error", message: "The selected video must be less than 30 seconds.", preferredStyle: .alert)
                            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                            self.present(alert, animated: true, completion: nil)
                        } else {
                            let outgoingMessage = OutgoingMessage(message: message, videoURL: videoURL, memberId: [FUser.currentId(), self.recipientId])
                            outgoingMessage.sendMessage(chatRoomId: self.chatId, messageId: message.id, memberIds: [FUser.currentId(), self.recipientId])
                            PushNotificationService.shared.sendPushNotificationTo(userIds: [self.recipientId], body: message.message)
                        }
                    } else {
                        print("Error: invalid video URL")
                        return
                    }
                }

            } catch {
                print(error)
                return
            }

            FirebaseListener.shared.updateRecents(chatRoomId: chatId, lastMessage: message.message)
        }

使用 load.duration

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true, completion: nil)
        let currentUser = FUser.currentUser()!

        let message = Message()

        message.id = UUID().uuidString
        message.chatRoomId = chatId
        message.senderId = currentUser.objectId
        message.senderName = currentUser.username

        message.sentDate = Date()
        message.senderInitials = String(currentUser.username.first!)
        message.status = kSENT
        message.message = "Video Message"

        if let videoUrl = info[.mediaURL] as? URL {
            let fileName = Date().stringDate()
            let fileDirectory = "MediaMessages/Video/" + "\(chatId)/" + "_\(fileName)" + ".mov"

            do {
                let videoData = try NSData(contentsOf: videoUrl, options: .mappedIfSafe)
                FileStorage.saveVideoLocally(videoData: videoData , fileName: fileName)
                FileStorage.uploadVideo(videoData, directory: fileDirectory) { (videoURL: String?) in

                    if let videoURL = videoURL, let url = URL(string: videoURL) {
                        let video = AVURLAsset(url: url)
                        video.load(.duration) { result in
                            switch result {
                            case .success(let durationValue):
                                let duration = CMTimeGetSeconds(durationValue as! CMTime)

                                if duration > 30 {
                                    let alert = UIAlertController(title: "Error", message: "The selected video must be less than 30 seconds.", preferredStyle: .alert)
                                    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                                    self.present(alert, animated: true, completion: nil)
                                } else {
                                    let outgoingMessage = OutgoingMessage(message: message, videoURL: videoURL,  memberId: [FUser.currentId(), self.recipientId])
                                    outgoingMessage.sendMessage(chatRoomId: self.chatId, messageId: message.id, memberIds: [FUser.currentId(), self.recipientId])
                                    PushNotificationService.shared.sendPushNotificationTo(userIds: [self.recipientId], body: message.message)
                                }
                            case .failure(let error):
                                print("Error: \(error)")
                                return
                            }
                        }
                    } else {
                        print("Error: invalid video URL")
                        return
                    }
                }

            } catch {
`                print(error)
                return
            }

            FirebaseListener.shared.updateRecents(chatRoomId: chatId, lastMessage: message.message)
        }
    }

    
    class func uploadVideo(_ video: NSData, directory: String, completion: @escaping (_ documentLink: String?) -> Void) {
            let storageRef = storage.reference(forURL: kFILEREFERENCE).child(directory)
            
           //let imageData = image.jpegData(compressionQuality: 0.6)
            
            var task: StorageUploadTask!
            
            task = storageRef.putData(video as Data, metadata: nil, completion: { (metaData, error) in
                
                task.removeAllObservers()
                ProgressHUD.dismiss()
                
                if error != nil {
                    print("error uploading video", error!.localizedDescription)
                    return
                }
                
                storageRef.downloadURL { (url, error) in
                    
                    guard let downloadUrl = url else {
                        completion(nil)
                        return
                    }
                    print("we have uploaded video to ", downloadUrl.absoluteString)
                    completion(downloadUrl.absoluteString)
                }
            })
            
            
            task.observe(StorageTaskStatus.progress) { (snapshot) in
                
                let progress = snapshot.progress!.completedUnitCount / snapshot.progress!.totalUnitCount
                ProgressHUD.showProgress(CGFloat(progress))
            }
            
            
        }
swift avasset
1个回答
0
投票

.load()
是一种异步方法。我不确定你从哪里得到闭包语法。您需要将此工作移至异步上下文,并等待结果:

    if let videoURL = videoURL, let url = URL(string: videoURL) {
        let video = AVURLAsset(url: url)
        Task { @MainActor in
            let duration = try await video.load(.duration).seconds
            // ...
        }
    } else {
       // ...
    }

我已将任务移至 MainActor,因为您在块中执行与 UIKit 相关的操作。 (这可能隐含在 UIViewController 中,所以我不能 100% 确定您的情况需要

@MainActor in
。)

请注意,您在此处的主队列上执行了很多可能代价高昂的 I/O 操作。例如,

NSData(contentsOf:options:)
不适合在主队列上加载大文件(它几乎不适合读取小文件)。这可能会导致 UI 线程挂起,如果时间过长甚至会终止应用程序(请求内存映射并不能保证不会发生这种情况)。大部分代码应该直接围绕 AVAsset 及其相关的 Reader 和 Writer 构建,而不是尝试使用 NSData 手动管理。

© www.soinside.com 2019 - 2024. All rights reserved.