Change metadata from PHAsset when MediaType video does not match

I am trying to add / change metadata from PHAssetusing mediaType == .video. I found several questions related to a similar problem:

How to change video metadata using AVAssetWriter?

Add custom metadata to videos using AVFoundation

As for the answers in these questions, I am creating the following snippet, which is an extension of 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)
            }
        })
    }
})

When I execute this snippet, the failure of exportSessionan 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)"}}
0
source share
1 answer

. PHAsset MediaType MediaType.video, , self - PHAsset:

PHContentEditingOutput, PHContentEditingInput PHAsset, . PHAsset .adjustmentData PHContentEditingOutput, .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 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 AVAsset.

:

PHImageManager -method .requestAVAsset(forVideo:,options:,resultHandler:), PHVideoRequestOptions -bject .version, .current. , .original, .

+2

Source: https://habr.com/ru/post/1679126/


All Articles