Adding text subtitles to video track (in Swift) fails with error code -11841

后端 未结 3 1149
天涯浪人
天涯浪人 2021-02-04 22:23

I have been struggling with adding text subtitles to videos for a while. I have added some links that I referred in detail, but they are not helping.

In below code, I a

相关标签:
3条回答
  • 2021-02-04 23:14

    You failed to insert trackID when creating layer instruction. Try :

    let videolayerInstruction : AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction(vtrack)
    
    0 讨论(0)
  • 2021-02-04 23:14

    I updated it to work with Swift 3 + adding the fix suggested by 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{
    
            }
    
        }
    
    0 讨论(0)
  • 2021-02-04 23:16

    When I tried this the subtitle did not appear. I fixed it by swapping the order of the sublayers.

    i.e

    parentLayer.addSublayer(videoLayer)

    parentLayer.addSubLayer(backgroundLayer)

    0 讨论(0)
提交回复
热议问题