使用mediaTypevideo从PHAsset修改元数据失败

我尝试使用mediaType == .videoPHAsset添加/修改元数据我发现一些问题mediaType == .video了类似的问题:

如何使用AVAssetWriter更改video元数据?

使用AVFoundation将自定义元数据添加到video

关于这些问题的答案,我构build了以下代码片段,它是PHAsset的扩展:

 let options = PHVideoRequestOptions() options.version = .original PHImageManager.default().requestAVAsset(forVideo: self, options: options, resultHandler: { asset, audioMix, info in if asset != nil && asset!.isKind(of: AVURLAsset.self) { let urlAsset = asset as! AVURLAsset let start = CMTimeMakeWithSeconds(0.0, 1) let duration = asset!.duration var exportSession = AVAssetExportSession(asset: asset!, presetName: AVAssetExportPresetPassthrough) exportSession!.outputURL = urlAsset.url exportSession!.outputFileType = AVFileTypeAppleM4V exportSession!.timeRange = CMTimeRange(start: start, duration: duration) var modifiedMetadata = asset!.metadata let metadataItem = AVMutableMetadataItem() metadataItem.keySpace = AVMetadataKeySpaceQuickTimeUserData metadataItem.key = AVMetadataQuickTimeMetadataKeyRatingUser as NSString metadataItem.value = NSNumber(floatLiteral: Double(rating)) modifiedMetadata.append(metadataItem) exportSession!.metadata = modifiedMetadata LogInfo("\(modifiedMetadata)") exportSession!.exportAsynchronously(completionHandler: { let status = exportSession?.status let success = status == AVAssetExportSessionStatus.completed if success { completion(true) } else { LogError("\(exportSession!.error!)") completion(false) } }) } }) 

当我执行这段代码时, exportSession失败了,出现以下错误:

 Error Domain=NSURLErrorDomain Code=-3000 "Cannot create file" UserInfo={NSLocalizedDescription=Cannot create file, NSUnderlyingError=0x1702439f0 {Error Domain=NSOSStatusErrorDomain Code=-12124 "(null)"}} 

我发现我的错误。 要使用MediaType MediaType.video修改PHAsset的元数据,您可以使用以下片段,其中selfPHAsset

首先,您需要创build一个PHContentEditingOutput您可以通过请求您要修改的PHContentEditingInput来请求PHContentEditingInput 。 更改PHAsset ,还必须设置.adjustmentData值,否则.performChanges()块将失败。

  self.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput, _) -> Void in if contentEditingInput != nil { let adjustmentData = PHAdjustmentData(formatIdentifier: starRatingIdentifier, formatVersion: formatVersion, data: NSKeyedArchiver.archivedData(withRootObject: rating)) let contentEditingOutput = PHContentEditingOutput(contentEditingInput: contentEditingInput!) contentEditingOutput.adjustmentData = adjustmentData self.applyRatingToVideo(rating, contentEditingInput, contentEditingOutput, completion: { output in if output != nil { PHPhotoLibrary.shared().performChanged({ let request = PHAssetChangeRequest(for: self) request.contentEditingOutput = output }, completionHandler: { success, error in if !success { print("can't edit asset: \(String(describing: error))") } }) } }) } }) 

通过上面的代码片段,您PHAsset在修改PHAsset之后更改PHContentEditingOutput ,您将看到以下代码片段:如何为用户设置元数据评级:

 private func applyRatingToVideo(_ rating: Int, input: PHContentEditingInput, output: PHContentEditingOutput, completion: @escaping (PHContentEditingOutput?) -> Void) { guard let avAsset = input.audiovisualAsset else { return } guard let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough) else { return } var mutableMetadata = exportSession.asset.metadata let metadataCopy = mutableMetadata for item in metadataCopy { if item.identifier == AVMetadataIdentifierQuickTimeMetadataRatingUser { mutableMetadata.remove(object: item) } } let metadataItem = AVMutableMetadataItem() metadataItem.identifier = AVMetadataIdentifierQuickTimeMetadataRatingUser metadataItem.keySpace = AVMetadataKeySpaceQuickTimeMetadata metadataItem.key = AVMetadataQuickTimeMetadataKeyRatingUser as NSString metadataItem.value = NSNumber(floatLiteral: Double(rating)) exportSession.outputURL = output.renderedContentURL mutableMetadata.append(metadataItem) exportSession.metadata = mutableMetadata exportSession.outputFileType = AVFileTypeQuickTimeMovie exportSession.shouldOptimizeForNetworkUse = true exportSession.exportAsynchronously(completionHandler: { if exportSession.status == .completed { completion(output) } else if exportSession.error != nil { completion(nil) } }) } 

考虑一下,如果你不删除AVMetadataItem和你想添加的标识符相同的标识符, AVAssetExportSession将为AVAssetExportSession设置多个具有相同标识符的AVAsset

注意:

当您现在通过PHImageManager -method .requestAVAsset(forVideo:,options:,resultHandler:)访问video时.requestAVAsset(forVideo:,options:,resultHandler:)必须传递一个PHVideoRequestOptions ,其中.versionvariables设置为.current 。 它被设置为variables的默认值,但是如果将其更改为.original ,则将从该方法获取未修改的video。