繁体   English   中英

AVAssetExportSession 导出失败并出现非确定性错误

[英]AVAssetExportSession export fails with non-deterministic error

我正在尝试使用 AVAssetExportSession 应用 CIFilter 导出视频,但有时它可以工作,有时它不能。 甚至不清楚如何重现该错误。

我注意到导出用 iPhone 录制的视频没有问题 但是,如果我尝试导出从 WhatsApp 下载的视频或之前已经导出的视频,我会收到以下错误:

Error Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo={NSLocalizedFailureReason=无法合成视频。, NSLocalizedDescription=Operation Stopped, NSUnderlyingError=0x2839eaf10 {Error Domain=NSOSStatusErrorDomain Code=-17390 "(null)"}}

这是我的代码:

var mutableComposition = AVMutableVideoComposition()
let exposureFilter = CIFilter.exposureAdjust()

func updateComposition() {
    mutableComposition = AVMutableVideoComposition(asset: player.currentItem!.asset, applyingCIFiltersWithHandler: { request in
        self.exposureFilter.inputImage = request.sourceImage.clampedToExtent()
        self.exposureFilter.ev = 5
        let output = self.exposureFilter.outputImage!.cropped(to: request.sourceImage.extent)
        request.finish(with: output, context: nil)
    })
    
    player.currentItem?.videoComposition = mutableComposition
}

func exportVideo() {
    let sourceAsset = AVURLAsset(url: videoURL)
    let composition = AVMutableComposition()

    let sourceVideoTrack = sourceAsset.tracks(withMediaType: .video)[0]
    let compositionVideoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
    try? compositionVideoTrack!.insertTimeRange(CMTimeRangeMake(start: .zero, duration: sourceAsset.duration), of: sourceVideoTrack, at: .zero)

    if sourceAsset.tracks(withMediaType: .audio).isEmpty == false {
        // Video has sound
        let sourceAudioTrack = sourceAsset.tracks(withMediaType: .audio)[0]
        let compositionAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
        try? compositionAudioTrack!.insertTimeRange(CMTimeRangeMake(start: .zero, duration: sourceAsset.duration), of: sourceAudioTrack, at: .zero)
    }

    guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        return
    }

    let videoID = UUID().uuidString
    let videofileName = "\(videoID).mov"

    let outputURL = documentsDirectory.appendingPathComponent(videofileName)

    if FileManager.default.fileExists(atPath: outputURL.path) {
        do {
            try FileManager.default.removeItem(at: outputURL)
        }
        catch {}
    }

    let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality)!
    exporter.outputFileType = .mov
    exporter.outputURL = outputURL
    exporter.videoComposition = mutableComposition

    exporter.exportAsynchronously(completionHandler: {
        switch exporter.status {
        case .failed:
            print("Export failed \(exporter.error!)")
        case .completed:
            UISaveVideoAtPathToSavedPhotosAlbum(outputURL.path, self, #selector(video(_:didFinishSavingWithError:contextInfo:)), nil)
        default:
            break
        }
    }
}

注释掉exporter.videoComposition = mutableComposition或将导出预设更改为 AVAssetExportPresetPassthrough 可修复错误,但当然不会对视频应用 CIFilter。

所以问题似乎在于 AVMutableVideoComposition。

我找到了一个适合我的解决方案。

替换:

let compositionVideoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)

let compositionAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)

和:

let compositionVideoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: sourceVideoTrack.trackID)
                            
let compositionAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: sourceAudioTrack.trackID)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM