AVAssetExportSession导出非确定性地失败并出现错误:“Operation Stopped,NSLocalizedFailureReason =视频无法合成。” [英] AVAssetExportSession export fails non-deterministically with error: "Operation Stopped, NSLocalizedFailureReason=The video could not be composed."
问题描述
我们为用户录制的视频添加字幕,但我们的AVAssetExportSession对象的导出无法确定性地失败:有时它会起作用,有时它不起作用。目前还不清楚如何重现错误。
We add subtitles to a video recorded by the user, but the export by our AVAssetExportSession object fails non-deterministically: sometimes it works, and sometimes it doesn't. It's unclear even how to reproduce the error.
我们注意到出口期间资产轨迹似乎丢失了。
We noticed the asset tracks seem to get lost during export.
在导出之前,有两个轨道(一个用于音频,一个用于视频),如预期的那样。但是,在 exportDidFinish
中检查同一文件URL的曲目数量会显示0个曲目。因此导出过程似乎出现了问题。
Before exporting, there are two tracks (one for audio, one for video) as expected. But checking the number of tracks for the same file URL in exportDidFinish
shows 0 tracks. So something seems wrong with the export process.
更新:注释掉 exporter.videoComposition = mutableComposition
修复错误,但当然没有变换应用于视频。所以问题似乎在于创建 AVMutableVideoComposition
,这会在导出期间导致下游问题。关于 AVMutableVideoComposition
的文档和教程很少,所以即使你没有解决方案但可以推荐Apple以外的参考资料,这会有所帮助。
Update: Commenting out exporter.videoComposition = mutableComposition
fixes the error, but of course no transforms are applied to the video. So the problem seems to lie in creating AVMutableVideoComposition
, which causes problems downstream during export. Documentation and tutorials on AVMutableVideoComposition
are sparse, so even if you don't have a solution but could recommend sources for reference beyond Apple, that would be helpful.
错误:
错误域= AVFoundationErrorDomain代码= -11841操作已停止
UserInfo = 0x170676e80 {NSLocalizedDescription =操作已停止,
NSLocalizedFailureReason =视频无法合成。}
Error Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo=0x170676e80 {NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The video could not be composed.}
代码:
let videoAsset = AVURLAsset(URL: fileUrl, options: nil)
let mixComposition = AVMutableComposition()
let videoTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
let audioTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
let sourceVideoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0] as! AVAssetTrack
let sourceAudioTrack = videoAsset.tracksWithMediaType(AVMediaTypeAudio)[0] as! AVAssetTrack
videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), ofTrack: sourceVideoTrack, atTime: kCMTimeZero, error: nil)
audioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), ofTrack: sourceAudioTrack, atTime: kCMTimeZero, error: nil)
// Create something mutable???
// -- Create instruction
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
let videoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: sourceVideoTrack)
instruction.layerInstructions = [videoLayerInstruction]
let mutableComposition = AVMutableVideoComposition()
//mutableComposition.renderSize = videoTrack.naturalSize
mutableComposition.renderSize = CGSize(width: 320, height: 320)
mutableComposition.frameDuration = CMTimeMake(1, 60)
mutableComposition.instructions = [instruction]
// Animate
mutableComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer)
// -- Get path
let fileName = "/editedVideo-\(arc4random() % 10000).mp4"
let allPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docsPath = allPaths[0] as! NSString
let exportPath = docsPath.stringByAppendingFormat(fileName)
let exportUrl = NSURL.fileURLWithPath(exportPath as String)!
println("Tracks before export: \(mixComposition.tracks.count). File URL: \(exportUrl)")
// -- Remove old video?
if NSFileManager.defaultManager().fileExistsAtPath(exportPath as String) {
println("Deleting existing file\n")
NSFileManager.defaultManager().removeItemAtPath(exportPath as String, error: nil)
}
// -- Create exporter
let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
exporter.videoComposition = mutableComposition
exporter.outputFileType = AVFileTypeMPEG4
exporter.outputURL = exportUrl
exporter.shouldOptimizeForNetworkUse = true
// -- Export video
exporter.exportAsynchronouslyWithCompletionHandler({
self.exportDidFinish(exporter)
})
func exportDidFinish(exporter: AVAssetExportSession) {
println("Exported video with status: \(getExportStatus(exporter))")
// Save video to photo album
let assetLibrary = ALAssetsLibrary()
assetLibrary.writeVideoAtPathToSavedPhotosAlbum(exporter.outputURL, completionBlock: {(url: NSURL!, error: NSError!) in
println("Saved video to album \(exporter.outputURL)")
if (error != nil) {
println("Error saving video")
}
})
// Check asset tracks
let asset = AVAsset.assetWithURL(exporter.outputURL) as? AVAsset
println("Tracks after export: \(asset!.tracks.count). File URL: \(exporter.outputURL)")
}
问题:
1)导致问题的原因是什么,解决方案是什么?
1) What's causing the problem, and what's the solution?
2)关于如何一致地重现错误的建议,希望有助于调试问题?
2) Suggestions on how to reproduce the error consistently, which hopefully helps debug the problem?
推荐答案
似乎可以解决的问题是确保 AVMutableVideoCompositionLayerInstruction
中的 assetTrack
参数不是来自 AVURLAsset
对象,但来自 addMutableTrackWithMediaType
返回的视频对象。
What seems to be the cure is making sure the assetTrack
parameter in AVMutableVideoCompositionLayerInstruction
is not from the AVURLAsset
object, but from the video object returned by addMutableTrackWithMediaType
.
换句话说,这一行:
let videoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: sourceVideoTrack)
应该是:
let videoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
Argh。几个小时的无尽沮丧,因为有时第一行有效,有时它没有。
Argh. Hours of endless frustration because sometimes the first line worked, and sometimes it didn't.
仍然想将赏金奖给某人。
Still would like to award the bounty to someone.
如果您可以解释为什么第一行不确定地失败,而不是每次都失败,或者为AVMutableComposition及其相关类提供更深入的教程 - 为了向用户记录添加文本叠加视频 - 赏金全是你的。 :)
If you can explain why the first line failed non-deterministically, instead of every time, or provide a deeper tutorial into AVMutableComposition and its related classes -- for the purposes of adding text overlays to user-recorded videos -- the bounty is all yours. :)
这篇关于AVAssetExportSession导出非确定性地失败并出现错误:“Operation Stopped,NSLocalizedFailureReason =视频无法合成。”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!