无法在swift 3中加载带有文本/图像叠加的视频

时间:2017-03-20 12:53:05

标签: swift3 avfoundation

我正在使用 AVFoundation 在视频上制作文字叠加和水印。我面临一些困难。我正在使用Image/Text overlay in video swift问题的代码。但我修改了它。当我调用功能 loadVideo 时,视频无法加载。我想不明白。这是我的代码

@IBAction func loadVideo(_ sender: Any) {

    let path = Bundle.main.path(forResource: "SampleVideo", ofType:"mp4")
    let fileURL = URL(fileURLWithPath: path!)

    let composition = AVMutableComposition()
    let vidAsset = AVURLAsset(url: fileURL as URL, options: nil)

    // get video track
    let vtrack =  vidAsset.tracks(withMediaType: AVMediaTypeVideo)
    let videoTrack:AVAssetTrack = vtrack[0] 
    _ = videoTrack.timeRange.duration
    let vid_timerange = CMTimeRangeMake(kCMTimeZero, vidAsset.duration)


    let compositionvideoTrack:AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())

    do {
        _ = try compositionvideoTrack.insertTimeRange(vid_timerange, of: videoTrack, at: kCMTimeZero)
    } catch {
        print("error")
    }

    compositionvideoTrack.preferredTransform = videoTrack.preferredTransform

    // Watermark Effect
    let size = videoTrack.naturalSize

    let imglogo = UIImage(named: "iosIcon.png")
    let imglayer = CALayer()
    imglayer.contents = imglogo?.cgImage
    imglayer.frame = CGRect(x: 5, y: 5, width: 100, height: 100)
    imglayer.opacity = 0.6

    // create text Layer
    let titleLayer = CATextLayer()
    titleLayer.backgroundColor = UIColor.white.cgColor
    titleLayer.string = "Subtitle Overlay Text"
    titleLayer.font = UIFont(name: "Helvetica", size: 28)
    titleLayer.shadowOpacity = 0.5
    titleLayer.alignmentMode = kCAAlignmentCenter
    titleLayer.frame = CGRect(x: 0, y: 50, width: size.width, height: size.height / 6)

    let videolayer = CALayer()
    videolayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)

    let parentlayer = CALayer()
    parentlayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    parentlayer.addSublayer(videolayer)
    parentlayer.addSublayer(imglayer)
    parentlayer.addSublayer(titleLayer)

    let layercomposition = AVMutableVideoComposition()
    layercomposition.frameDuration = CMTimeMake(1, 30)
    layercomposition.renderSize = size
    layercomposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videolayer, in: parentlayer)

    // instruction for watermark
    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration)
    let videotrack = composition.tracks(withMediaType: AVMediaTypeVideo)[0] as AVAssetTrack
    let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)
    instruction.layerInstructions = NSArray(object: layerinstruction) as [AnyObject] as [AnyObject] as! [AVVideoCompositionLayerInstruction]
    layercomposition.instructions = NSArray(object: instruction) as [AnyObject] as [AnyObject] as! [AVVideoCompositionInstructionProtocol]



    //  create new file to receive data
    let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    let docsDir = dirPaths[0] as String
    let movieFilePath = docsDir.appending("result.mov")

    let movieDestinationUrl = URL(fileURLWithPath: movieFilePath)
    //remove existing file
    _ = try? FileManager().removeItem(at: movieDestinationUrl)


    // use AVAssetExportSession to export video
    guard let assetExport = AVAssetExportSession(asset: composition, presetName:AVAssetExportPresetHighestQuality) else {return}
    assetExport.videoComposition = layercomposition
    assetExport.outputFileType = AVFileTypeQuickTimeMovie
    assetExport.outputURL = movieDestinationUrl
    assetExport.exportAsynchronously(completionHandler: {
        switch assetExport.status{
        case  AVAssetExportSessionStatus.failed:
            print("failed \(assetExport.error)")
        case AVAssetExportSessionStatus.cancelled:
            print("cancelled \(assetExport.error)")
        case AVAssetExportSessionStatus.completed:
            print("Completed")
        default:
            print("unknown")
        }
    })

}

我做错了什么?将ExportAsset保存在文件目录中有什么问题吗?

2 个答案:

答案 0 :(得分:1)

最后我决定回答我自己的问题。上面的代码运行没有失败,但在模拟器中导出需要一些时间。所以我将presetName: AVAssetExportPresetHighestQuality 更改为 AVAssetExportPresetMediumQuality 。在文档目录中导出视频文件时也有修改。上面的代码不会删除文档目录中的现有视频文件。因此,当我导出另一个视频时,它无法覆盖现有视频。所以我删除了该文件。以下是代码:

{{1}}

答案 1 :(得分:1)

创建layerInstuctions后,请尝试使用此代码而不是上面的内容。对于其他任何有问题的人,就像我一样。您应该能够将预设保留在 AVAssetExportPresetHighestQuality

instruction.layerInstructions = [layerinstruction]
layercomposition.instructions = [instruction]

    let movieFilePath = NSTemporaryDirectory() + "result.mp4"
    let movieDestinationUrl = URL(fileURLWithPath: movieFilePath)


// must delete existing temporary file from file directory, also use try catch
do {
    try FileManager.default.removeItem(at: movieDestinationUrl as URL)
} catch _ as NSError {
    print("Error")
}