2015-07-10 16 views
2

我一直在添加文本字幕視頻一會兒掙扎。我已經添加了一些我詳細提到的鏈接,但他們沒有幫助。添加文本字幕,視頻軌(斯威夫特)失敗,錯誤代碼-11841

在下面的代碼,我想字幕添加到視頻。輸出文件路徑如下:

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

此外,輸入文件記錄了與在同一應用程序到UIPickerView一個電話,在下面的臨時路徑:

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

的錯誤我得到如下,

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 

我使用的代碼如下。我在iPhone 4s上的iOS 7.1.2上運行它。

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 = String("Testing this subtitle") 

    var titleLayer = CATextLayer() 
    titleLayer.string = title 
    titleLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) 
    let fontName: CFStringRef = "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) 
    }) 
} 

我將不勝感激您的幫助。我沒有發現任何爲視頻添加動畫的快速示例。想知道如果它快速爲任何人工作。

參考文獻:(1)https://gist.github.com/SheffieldKevin/c01789ccff2b2a87f5ea(2)http://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos

回答

1

你失敗創建層指令時插入的TrackID。嘗試:

let videolayerInstruction : AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction(vtrack) 
+0

感謝迪帕克。這解決了這個問題。 – flipflopapp

0

當我嘗試這個字幕沒有出現。我通過交換子層的順序來修復它。

parentLayer.addSublayer(videoLayer)

parentLayer.addSubLayer(backgroundLayer)

0

我更新它與夫特3 +添加人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 = String("Testing this subtitle") 

     var titleLayer = CATextLayer() 
     titleLayer.string = title 
     titleLayer.frame = CGRect(x: 0, y: 0, width: renderWidth!, height: renderHeight!) 
     let fontName: CFString = "Helvetica-Bold" as CFString 
     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{ 

     } 

    }