2015-11-22 3 views
3

Je suis nouveau à AVFoundation, et j'essaye d'ajouter une image à une vidéo. Cependant, je continue à recevoir une erreur: failed Optional(Error Domain=AVFoundationErrorDomain Code=-11823 "Cannot Save" UserInfo={NSLocalizedDescription=Cannot Save, NSLocalizedRecoverySuggestion=Try saving again.}) . Qu'est-ce que je fais mal. Voici mon code:Ajouter une image de filigrane à une vidéo

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) 
      }) 
     } 
    }) 

} 
+1

Cela peut ne pas aider, mais j'ai deux suggestions: (1) Votre utilisation mixte de chemins de fichiers de chaîne et URL de fichier NSURL est dangereuse et susceptible d'erreur. Utilisez NSURL partout. (De plus, votre utilisation de AnyObject montre que vous ne savez pas ce que vous faites, même avec les chemins de fichiers de chaînes, vous essayez clairement de contourner quelque chose qui vous mystifie, mais en fait il y a une explication simple.) (2) Assurez-vous le fichier de votre URL cible n'existe pas avant d'essayer de l'enregistrer. – matt

+0

Probablement que je ne suis pas tout à fait dans l'AVFoundation et les informations sur Internet sont limitées et s'il y a quelque chose, c'est «obj-c», donc j'apprécierais que vous ayez une réponse concrète. Merci d'avance –

Répondre

1

Comme Matt a commenté, vous avez oublié de supprimer le fichier de sortie (AVFoundation refuse d'écraser des fichiers pour une raison quelconque). Alors que faire:

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

qui corrige l'erreur, mais vous ne serez pas encore voir votre filigrane parce que vous n'êtes pas régler le l » videoCompositionAVAssetExportSession:

assetExport?.videoComposition = layercomposition // important! 

assetExport!.exportAsynchronouslyWithCompletionHandler({...}) 
+0

J'ai ajouté 'assetExport? .videoComposition = layercomposition' mais il n'ajoute pas le filigrane. –

+0

Je ne sais pas si ça a quelque chose à voir avec ça mais même si c'est filmé en portrait il le sort en paysage –

0

Salut je l'ai fait en ObjectivC suit est mon code ...

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]; 
+1

La question est taguée "swift". Votre réponse devrait utiliser Swift. – Moritz

+1

Bien que ce code puisse répondre à la question, il vaudrait mieux expliquer comment il résout le problème sans en présenter d'autres et pourquoi l'utiliser. Les réponses au code uniquement ne sont pas utiles à long terme. – JAL