【问题标题】:Modifying Metadata from PHAsset with mediaType Video fails使用 mediaType Video 从 PHAsset 修改元数据失败
【发布时间】:2017-06-29 12:18:16
【问题描述】:

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

How to change video metadata using AVAssetWriter?

Add custom metadata to video using AVFoundation

关于这些问题中的答案,我构建了以下 sn-p,它是 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)
            }
        })
    }
})

当我执行这个 sn-p 时,exportSession 失败并出现以下错误:

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

【问题讨论】:

    标签: ios swift avassetexportsession avasset photokit


    【解决方案1】:

    我发现了我的错误。要使用MediaType MediaType.video 修改PHAsset 的元数据,可以使用以下sn-p,其中selfPHAsset

    首先,您需要创建一个PHContentEditingOutput,您可以通过从您要修改的PHAsset 请求一个PHContentEditingInput 来做到这一点。更改PHAsset 时,您还必须设置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))")
                            }
                        })
                    }
                })
            }
        })
    

    使用上面的sn-p,你在修改PHContentEditingOutput之后修改PHAsset,下面的sn-p你会看到,如何设置用户评分的元数据:

    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:,resultHandler:) 访问视频时,您必须传递一个PHVideoRequestOptions-对象,并将.version 变量设置为.current。它被设置为变量的默认值,但如果您将其更改为.original,您将从该方法获得未修改的视频。

    【讨论】:

    • 感谢分享一个好的解决方案!但是我不明白这部分,PHAdjustmentData(formatIdentifier: starRatingIdentifier, formatVersion: formatVersion, data: NSKeyedArchiver.archivedData(withRootObject: rating)),尤其是NSKeyedArchiver.archivedData(withRootObject: rating)。为什么使用rating 值?
    • PHContentEditingoutput 强制要求。一般来说,它背后的计划是,任何在编辑视频或照片数据时进行另一次迭代的应用程序都可以读取这些信息并进行处理。当您添加另一个过滤器时,这可能特别有用。在这种情况下,我只添加它来描述对资产所做的更改。 NSKeyedArchiver 不是强制性的,它只是将评级对象转换为 data 的一种简单方法,但您可以使用其他方式来归档,特别是如果您想添加可编码对象。
    猜你喜欢
    • 2017-11-15
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    • 2012-03-11
    • 2017-06-24
    • 1970-01-01
    相关资源
    最近更新 更多