使用mediaType Video从PHAsset修改元数据失败 [英] Modifying Metadata from PHAsset with mediaType Video fails

查看:170
本文介绍了使用mediaType Video从PHAsset修改元数据失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I try adding/modifying the Metadata from an PHAsset with mediaType == .video I found some Questions refering to a similar problem:

如何使用AVAssetWriter更改视频元数据?

使用AVFoundation将自定义元数据添加到视频中

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆