3

我是 AVFoundation 的新手,我正在尝试将图像添加到视频中。但是我不断收到错误消息:failed Optional(Error Domain=AVFoundationErrorDomain Code=-11823 "Cannot Save" UserInfo={NSLocalizedDescription=Cannot Save, NSLocalizedRecoverySuggestion=Try saving again.}) 。我究竟做错了什么。这是我的代码:

func createVideo() {

    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString

    let fileURL = NSURL(fileURLWithPath: "\(documentsPath)/\(self.randomVideoFileName).mov")

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

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


    do {
        let compositionvideoTrack:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
        try compositionvideoTrack.insertTimeRange(vid_timerange, ofTrack: videoTrack, atTime: kCMTimeZero)

        compositionvideoTrack.preferredTransform = videoTrack.preferredTransform
    } catch {
        print(error)
    }

    //Get the video
    let fullSizeImage = videoTrack

    let newOverLayHeight = fullSizeImage.naturalSize.width / self.containerView!.frame.width * self.containerView!.frame.height

    UIGraphicsBeginImageContext(CGSizeMake(fullSizeImage.naturalSize.width, newOverLayHeight));
    self.containerView!.drawViewHierarchyInRect(CGRectMake(0, 0, fullSizeImage.naturalSize.width, newOverLayHeight), afterScreenUpdates: true)
    let overlayImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    let imglogo = UIImage(named: "image.png")
    let imglayer = CALayer()
    imglayer.contents = imglogo?.CGImage
    imglayer.frame = CGRectMake(0,fullSizeImage.naturalSize.height - newOverLayHeight, overlayImage.size.width, overlayImage.size.height)

    let videolayer = CALayer()
    videolayer.frame = CGRectMake(0, 0, fullSizeImage.naturalSize.width, fullSizeImage.naturalSize.height)

    let parentlayer = CALayer()
    parentlayer.frame = CGRectMake(0, 0, fullSizeImage.naturalSize.width, fullSizeImage.naturalSize.height)
    parentlayer.addSublayer(imglayer)

    let layercomposition = AVMutableVideoComposition()
    layercomposition.frameDuration = CMTimeMake(1, 30)
    layercomposition.renderSize = fullSizeImage.naturalSize
    layercomposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videolayer, inLayer: parentlayer)

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


    //  create new file to receive data
    let docsDir: AnyObject = documentsPath
    let movieFilePath = docsDir.stringByAppendingPathComponent("result.mov")
    let movieDestinationUrl = NSURL(fileURLWithPath: movieFilePath)

    // use AVAssetExportSession to export video
    let assetExport = AVAssetExportSession(asset: composition, presetName:AVAssetExportPresetHighestQuality)
    assetExport!.outputFileType = AVFileTypeQuickTimeMovie
    assetExport!.outputURL = movieDestinationUrl
    assetExport!.exportAsynchronouslyWithCompletionHandler({
        switch assetExport!.status{
        case  AVAssetExportSessionStatus.Failed:
            print("failed \(assetExport!.error)")
        case AVAssetExportSessionStatus.Cancelled:
            print("cancelled \(assetExport!.error)")
        default:
            print("Movie complete")


            // save to photoalbum
            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                UISaveVideoAtPathToSavedPhotosAlbum(movieDestinationUrl.absoluteString,  self, "image:didFinishSavingWithError:contextInfo:", nil)
            })
        }
    })

}
4

2 回答 2

1

正如马特评论的那样,您忘记删除输出文件(AVFoundation 出于某种原因拒绝覆盖文件)。这样做:

let movieDestinationUrl = NSURL(fileURLWithPath: movieFilePath)
_ = try? NSFileManager().removeItemAtURL(movieDestinationUrl)

这修复了错误,但您还看不到水印,因为您没有设置AVAssetExportSession's videoComposition

assetExport?.videoComposition = layercomposition  // important!

assetExport!.exportAsynchronouslyWithCompletionHandler({...})
于 2015-11-23T03:08:44.633 回答
0

嗨,我在 ObjectivC 中完成了此操作,以下是我的代码...

AVMutableVideoComposition* videoComp = [AVMutableVideoComposition videoComposition] ;

    CGSize videoSize = CGSizeApplyAffineTransform(a_compositionVideoTrack.naturalSize, a_compositionVideoTrack.preferredTransform);

        CATextLayer *titleLayer = [CATextLayer layer];
        titleLayer.string = @"lippieapp.com";
        titleLayer.font = (__bridge CFTypeRef)(@"Helvetica-Bold");
        titleLayer.fontSize = 32.0;
        //titleLayer.alignmentMode = kCAAlignmentCenter;
        titleLayer.frame = CGRectMake(30, 0, 250, 60); //You may need to adjust this for proper display

    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
    videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
    [parentLayer addSublayer:videoLayer];
于 2015-11-23T06:06:50.253 回答