Ios 使用mediaType视频修改PHAsset中的元数据失败

Ios 使用mediaType视频修改PHAsset中的元数据失败,ios,swift,avassetexportsession,avasset,photokit,Ios,Swift,Avassetexportsession,Avasset,Photokit,我尝试使用mediaType==从PHAsset添加/修改元数据。视频我发现了一些与类似问题相关的问题: 关于这些问题的答案,我构建了以下片段,它是PHAsset的扩展: let options = PHVideoRequestOptions() options.version = .original PHImageManager.default().requestAVAsset(forVideo: self, options: options, resultHandler: {

我尝试使用
mediaType==从
PHAsset
添加/修改元数据。视频
我发现了一些与类似问题相关的问题:

关于这些问题的答案,我构建了以下片段,它是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
修改
phaset
的元数据,可以使用以下代码段,其中
self
phaset

首先,您需要创建一个
PHContentEditingOutput
,您可以通过从要修改的
PHAsset
请求一个
PHContentEditingOutput
。更改
相位集时
还必须设置
PHContentEditingOutput
.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))")
                        }
                    })
                }
            })
        }
    })
在上面的代码段中,修改
PHContentEditingOutput
后,您将更改
PHAsset
,在下面的代码段中,您将看到如何为用户评级设置元数据:

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
将为
AVAsset
设置具有相同标识符的多个项

注意:

当您现在通过
PHImageManager
-方法
.requestAVAsset(forVideo:,options:,resultandler:)
访问视频时,您必须传递一个
PHVideoRequestOptions
-对象,其中
.version
变量设置为
.current
。它被设置为变量的默认值,但如果将其更改为
.original
,则将从该方法获得未修改的视频