L'ajout de sous-titres de text à la piste video (dans Swift) échoue avec le code d'erreur -11841

J'ai lutté avec l'ajout de sous-titres de text aux videos pendant un moment. J'ai ajouté quelques liens que j'ai mentionnés en détail, mais ils ne m'aident pas.

Dans le code ci-dessous, j'essaie d'append un sous-titre à une video. Le path du file de sortie est comme ci-dessous:

file:///var/mobile/Applications/03E49B29-1070-4541-B7CB-B1366732C179/Documents/output_movie.mov 

En outre, le file d'input a été enregistré avec un appel à UIPickerView dans la même application, sur le path temporaire ci-dessous:

 file:///private/var/mobile/Applications/03E49B29-1070-4541-B7CB-B1366732C179/tmp/capture/capturedvideo.MOV 

L'erreur que je reçois est la suivante,

 Error:- Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo=0x15ebcfb0 {NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The video could not be composed.} Description:- <AVAssetExportSession: 0x15d97c80, asset = <AVMutableComposition: 0x15d788d0 tracks = ("<AVMutableCompositionTrack: 0x15d86910 trackID = 1, mediaType = vide, editCount = 1>")>, presetName = AVAssetExportPresetHighestQuality, outputFileType = com.apple.quicktime-movie Completed merging the video with status code 4 

Le code que j'utilise est comme ci-dessous. Je l'utilise sur iOS 7.1.2 sur un iPhone 4s.

 class func mergeVideoWithTheme(outputUrl: NSURL, inputVideoUrl videoUrl: NSURL!, onComplete completionHandler: ((Int) -> ())!) -> Void { // 1. mergeComposition adds all the AVAssets var mergeComposition : AVMutableComposition = AVMutableComposition() var trackVideo : AVMutableCompositionTrack = mergeComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID()) //var trackAudio : AVMutableCompositionTrack = mergeComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID()) // 2. Add a bank for theme insertion later //trackVideo.insertTimeRange(range, ofTrack: VideoHelper.Static.blankTrack, atTime: kCMTimeZero, error: nil) // 3. Source tracks let sourceAsset = AVURLAsset(URL: videoUrl, options: nil) let sourceDuration = CMTimeRangeMake(kCMTimeZero, sourceAsset.duration) let vtrack: AVAssetTrack? = sourceAsset.tracksWithMediaType(AVMediaTypeVideo)[0] as? AVAssetTrack let atrack: AVAssetTrack? = sourceAsset.tracksWithMediaType(AVMediaTypeAudio)[0] as? AVAssetTrack if (vtrack == nil) { return } let renderWidth = vtrack?.naturalSize.width let renderHeight = vtrack?.naturalSize.height let insertTime = kCMTimeZero let endTime = sourceAsset.duration let range = sourceDuration // append tracks trackVideo.insertTimeRange(sourceDuration, ofTrack: vtrack, atTime: insertTime, error: nil) //if(atrack > 0){ // trackAudio.insertTimeRange(sourceDuration, ofTrack: atracks[0] as AVAssetTrack, atTime: insertTime, error: nil) //} // 4. Add subtitles (we call it theme) var themeVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition(propertiesOfAsset: sourceAsset) // 4.1 - Create AVMutableVideoCompositionInstruction let mainInstruction: AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction() mainInstruction.timeRange = range // 4.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation. let videolayerInstruction : AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction() videolayerInstruction.setTransform(trackVideo.preferredTransform, atTime: insertTime) videolayerInstruction.setOpacity(0.0, atTime: endTime) // 4.3 - Add instructions mainInstruction.layerInstructions = NSArray(array: [videolayerInstruction]) themeVideoComposition.renderScale = 1.0 themeVideoComposition.renderSize = CGSizeMake(renderWidth!, renderHeight!) themeVideoComposition.frameDuration = CMTimeMake(1, 30) themeVideoComposition.instructions = NSArray(array: [mainInstruction]) // add the theme // setup variables // add text let title = Ssortingng("Testing this subtitle") var titleLayer = CATextLayer() titleLayer.ssortingng = title titleLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) let fontName: CFSsortingngRef = "Helvetica-Bold" let fontSize = CGFloat(36) titleLayer.font = CTFontCreateWithName(fontName, fontSize, nil) titleLayer.alignmentMode = kCAAlignmentCenter titleLayer.foregroundColor = UIColor.whiteColor().CGColor var backgroundLayer = CALayer() backgroundLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) backgroundLayer.masksToBounds = true backgroundLayer.addSublayer(titleLayer) // 2. set parent layer and video layer var parentLayer = CALayer() var videoLayer = CALayer() parentLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) videoLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) parentLayer.addSublayer(backgroundLayer) parentLayer.addSublayer(videoLayer) // 3. make animation themeVideoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer) // Remove the file if it already exists (merger does not overwrite) let fileManager = NSFileManager.defaultManager() fileManager.removeItemAtURL(outputUrl, error: nil) // export to output url var exporter = AVAssetExportSession(asset: mergeComposition, presetName: AVAssetExportPresetHighestQuality) exporter.outputURL = outputUrl exporter.videoComposition = themeVideoComposition exporter.outputFileType = AVFileTypeQuickTimeMovie exporter.shouldOptimizeForNetworkUse = true exporter.exportAsynchronouslyWithCompletionHandler({ if (exporter.error != nil) { println("Error") println(exporter.error) println("Description") println(exporter.description) } completionHandler(exporter.status.rawValue) }) } 

J'apprécierais grandement votre aide. Je n'ai trouvé aucun exemple rapide d'ajout d'animations aux videos. Vous vous requestz si cela a fonctionné pour quelqu'un sur swift.

Références: (1) https://gist.github.com/SheffieldKevin/c01789ccff2b2a87f5ea (2) http://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos

Vous n'avez pas réussi à insert trackID lors de la création d'une instruction de couche. Essayez:

 let videolayerInstruction : AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction(vtrack) 

Quand j'ai essayé, le sous-titre n'apparaissait pas. Je l'ai réparé en échangeant l'ordre des sous-couches.

c'est à dire

parentLayer.addSublayer (videoLayer)

parentLayer.addSubLayer (backgroundLayer)

Je l'ai mis à jour pour travailler avec Swift 3 + en ajoutant le correctif suggéré par Deepak.

 func mergeVideoWithTheme(outputUrl: NSURL, inputVideoUrl videoUrl: NSURL!, onComplete completionHandler: ((Int) -> ())!) -> Void { do { // 1. mergeComposition adds all the AVAssets var mergeComposition : AVMutableComposition = AVMutableComposition() var trackVideo : AVMutableCompositionTrack = mergeComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID()) //var trackAudio : AVMutableCompositionTrack = mergeComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID()) // 2. Add a bank for theme insertion later //trackVideo.insertTimeRange(range, ofTrack: VideoHelper.Static.blankTrack, atTime: kCMTimeZero, error: nil) // 3. Source tracks let sourceAsset = AVURLAsset(url: videoUrl as URL, options: nil) let sourceDuration = CMTimeRangeMake(kCMTimeZero, sourceAsset.duration) let vtrack: AVAssetTrack? = sourceAsset.tracks(withMediaType: AVMediaTypeVideo)[0] as? AVAssetTrack let atrack: AVAssetTrack? = sourceAsset.tracks(withMediaType: AVMediaTypeAudio)[0] as? AVAssetTrack if (vtrack == nil) { return } let renderWidth = vtrack?.naturalSize.width let renderHeight = vtrack?.naturalSize.height let insertTime = kCMTimeZero let endTime = sourceAsset.duration let range = sourceDuration // append tracks try trackVideo.insertTimeRange(sourceDuration, of: vtrack!, at: insertTime) //if(atrack > 0){ // trackAudio.insertTimeRange(sourceDuration, ofTrack: atracks[0] as AVAssetTrack, atTime: insertTime, error: nil) //} // 4. Add subtitles (we call it theme) var themeVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition(propertiesOf: sourceAsset) // 4.1 - Create AVMutableVideoCompositionInstruction let mainInstruction: AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction() mainInstruction.timeRange = range // 4.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation. let videolayerInstruction : AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: vtrack!) videolayerInstruction.setTransform(trackVideo.preferredTransform, at: insertTime) videolayerInstruction.setOpacity(0.0, at: endTime) // 4.3 - Add instructions mainInstruction.layerInstructions = NSArray(array: [videolayerInstruction]) as! [AVVideoCompositionLayerInstruction] themeVideoComposition.renderScale = 1.0 themeVideoComposition.renderSize = CGSize(width: renderWidth!, height: renderHeight!) themeVideoComposition.frameDuration = CMTimeMake(1, 30) themeVideoComposition.instructions = NSArray(array: [mainInstruction]) as! [AVVideoCompositionInstructionProtocol] // add the theme // setup variables // add text let title = Ssortingng("Testing this subtitle") var titleLayer = CATextLayer() titleLayer.ssortingng = title titleLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) let fontName: CFSsortingng = "Helvetica-Bold" as CFSsortingng let fontSize = CGFloat(36) titleLayer.font = CTFontCreateWithName(fontName, fontSize, nil) titleLayer.alignmentMode = kCAAlignmentCenter titleLayer.foregroundColor = UIColor.white.cgColor var backgroundLayer = CALayer() backgroundLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) backgroundLayer.masksToBounds = true backgroundLayer.addSublayer(titleLayer) // 2. set parent layer and video layer var parentLayer = CALayer() var videoLayer = CALayer() parentLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) videoLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) parentLayer.addSublayer(backgroundLayer) parentLayer.addSublayer(videoLayer) // 3. make animation themeVideoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer) // Remove the file if it already exists (merger does not overwrite) let fileManager = FileManager.default try fileManager.removeItem(at: outputUrl as URL) // export to output url var exporter = AVAssetExportSession(asset: mergeComposition, presetName: AVAssetExportPresetHighestQuality) exporter?.outputURL = outputUrl as URL exporter?.videoComposition = themeVideoComposition exporter?.outputFileType = AVFileTypeQuickTimeMovie exporter?.shouldOptimizeForNetworkUse = true exporter?.exportAsynchronously(completionHandler: { if (exporter?.error != nil) { print("Error") print(exporter?.error) print("Description") print(exporter?.description) } completionHandler((exporter?.status.rawValue)!) }) } catch{ } }