2016-08-16 14 views
2

AVAsset-arrayVideosを1つのビデオにマージして、カメラロールに保存します。 Raywenderlich.comにはtutorialがあり、2つのビデオが1つに統合されています。次のコードを作成しましたが、カメラロールに書き出した後に取得するビデオには、配列の最初と最後のビデオのみが含まれます(残りのビデオはarrayVideosの中間には含まれません)。私はここに何かを逃していますかスウィフトマージAVasset-ビデオアレイ

var arrayVideos = [AVAsset]() //Videos Array  
var atTimeM: CMTime = CMTimeMake(0, 0) 
var lastAsset: AVAsset! 
var layerInstructionsArray = [AVVideoCompositionLayerInstruction]() 
var completeTrackDuration: CMTime = CMTimeMake(0, 1) 
var videoSize: CGSize = CGSize(width: 0.0, height: 0.0) 

func mergeVideoArray(){ 

    let mixComposition = AVMutableComposition() 
    for videoAsset in arrayVideos{ 
     let videoTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) 
     do { 
      if videoAsset == arrayVideos.first{ 
       atTimeM = kCMTimeZero 
      } else{ 
       atTimeM = lastAsset!.duration 
      } 
      try videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), of: videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0], at: atTimeM) 
      videoSize = videoTrack.naturalSize 
     } catch let error as NSError { 
      print("error: \(error)") 
     } 
     completeTrackDuration = CMTimeAdd(completeTrackDuration, videoAsset.duration) 
     let videoInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack) 
     if videoAsset != arrayVideos.last{ 
      videoInstruction.setOpacity(0.0, at: videoAsset.duration) 
     } 
     layerInstructionsArray.append(videoInstruction) 
     lastAsset = videoAsset    
    } 

    let mainInstruction = AVMutableVideoCompositionInstruction() 
    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, completeTrackDuration) 
    mainInstruction.layerInstructions = layerInstructionsArray   

    let mainComposition = AVMutableVideoComposition() 
    mainComposition.instructions = [mainInstruction] 
    mainComposition.frameDuration = CMTimeMake(1, 30) 
    mainComposition.renderSize = CGSize(width: videoSize.width, height: videoSize.height) 

    let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] 
    let dateFormatter = DateFormatter() 
    dateFormatter.dateStyle = .long 
    dateFormatter.timeStyle = .short 
    let date = dateFormatter.string(from: NSDate() as Date) 
    let savePath = (documentDirectory as NSString).appendingPathComponent("mergeVideo-\(date).mov") 
    let url = NSURL(fileURLWithPath: savePath) 

    let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) 
    exporter!.outputURL = url as URL 
    exporter!.outputFileType = AVFileTypeQuickTimeMovie 
    exporter!.shouldOptimizeForNetworkUse = true 
    exporter!.videoComposition = mainComposition 
    exporter!.exportAsynchronously { 

     PHPhotoLibrary.shared().performChanges({ 
      PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: exporter!.outputURL!) 
     }) { saved, error in 
      if saved { 
       let alertController = UIAlertController(title: "Your video was successfully saved", message: nil, preferredStyle: .alert) 
       let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil) 
       alertController.addAction(defaultAction) 
       self.present(alertController, animated: true, completion: nil) 
      } else{ 
       print("video erro: \(error)") 

      } 
     } 
    } 
} 

答えて

3

すべてのアセットの合計時間をトラッキングし、各ビデオについて更新する必要があります。

あなたの質問のコードは、atTimeMを現在のビデオで書き換えていました。だから、最初と最後だけが含まれています。

それはこのようになります:

... 
var totalTime : CMTime = CMTimeMake(0, 0) 

func mergeVideoArray() { 

    let mixComposition = AVMutableComposition() 
    for videoAsset in arrayVideos { 
     let videoTrack = 
      mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, 
              preferredTrackID: Int32(kCMPersistentTrackID_Invalid))   
     do { 
      if videoAsset == arrayVideos.first { 
       atTimeM = kCMTimeZero 
      } else { 
       atTimeM = totalTime // <-- Use the total time for all the videos seen so far. 
      } 
      try videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), 
              of: videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0], 
              at: atTimeM) 
      videoSize = videoTrack.naturalSize 
     } catch let error as NSError { 
      print("error: \(error)") 
     } 
     totalTime += videoAsset.duration // <-- Update the total time for all videos. 
... 

あなたはlastAssetの使用を削除することができます。

+0

乾杯ダニエルと

if videoAsset == arrayVideos.first{ atTimeM = kCMTimeZero } else{ atTimeM = lastAsset!.duration } try videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), of: videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0], at: atTimeM) 

を交換してください。 ! videoAsset = arrayVideos.lastの場合:追加のコードを追加するための{(0.0で、completeTrackDuration) videoInstruction.setOpacity: } – Marcelo

+0

感謝をちょうどあなたの答えを補完するために、我々は次のコードでも、合計時間を追加する必要があります。 – Daniel

+0

合計時間を+ =で増やすことはできません。CMTimeAddを使用する必要があります。 – user3288724

0

atTimeMはまったく必要ありません。単純にcompleteTrackDurationを次のピースを追加する場所に追加するだけです。だから、

try videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), of: videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0], at: completeTrackDuration) 
関連する問題