使用mediaType Video从PHAsset修改元数据失败 [英] Modifying Metadata from PHAsset with mediaType Video fails
问题描述
我尝试使用mediaType == .video
从PHAsset
添加/修改元数据,我发现一些问题涉及类似的问题:
I try adding/modifying the Metadata from an PHAsset
with mediaType == .video
I found some Questions refering to a similar problem:
关于这些问题的答案,我构建了以下片段,它是PHAsset的扩展:
Regarding to the Answers in these Questions I build the following snippet which is a extension of a 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
失败,并出现以下错误:
When I execute this snippet, the exportSession
failed an has the following error:
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
的元数据,可以使用以下代码段,其中self
是PHAsset
:
I found my mistake. To modify the metadata of an PHAsset
with the MediaType
MediaType.video
you can use the following snippet, where self
is the PHAsset
:
首先,您需要创建一个PHContentEditingOutput
,您可以通过从要修改的PHAsset
请求一个PHContentEditingInput
来做到这一点.更改PHAsset
时,还必须设置PHContentEditingOutput
的.adjustmentData
值,否则.performChanges()
块将失败.
First you need to create an PHContentEditingOutput
you can do that with requesting an PHContentEditingInput
from the PHAsset
you want to modify. When changing an PHAsset
you also have to set the .adjustmentData
Value of the PHContentEditingOutput
or else the .performChanges()
Block will fail.
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
,您将看到如何设置用户评级的元数据:
With the snippet above, you change the PHAsset
after modifying the PHContentEditingOutput
in the following snippet you will see, how to set the Metadata for an User Rating:
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
设置多个具有相同标识符的项目.
Consider, that if you do not remove the AVMetadataItem
with the same Identifier as the one you want to add, the AVAssetExportSession
will set multiple Items with the same Identifier for the AVAsset
.
注意:
现在,当您通过PHImageManager
方法.requestAVAsset(forVideo:,options:,resultHandler:)
访问视频时,您必须传递一个PHVideoRequestOptions
对象,且.version
变量设置为.current
.它设置为变量的默认值,但是如果将其更改为.original
,则将从该方法中获取未修改的视频.
When you now access the Video through the PHImageManager
-method .requestAVAsset(forVideo:,options:,resultHandler:)
you have to pass an PHVideoRequestOptions
-object with the .version
variable set to .current
. It is set as default value of the variable but if you change it to .original
you will get the unmodified Video from that method.
这篇关于使用mediaType Video从PHAsset修改元数据失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!