1

私はUIImagesの配列からビデオを作ります。私はそれを成功させた&すべての画像は、ビデオに表示されています。 AVAssetExportSessionを使用してビデオをエクスポートしていますが、AVAssetExportSessionを使用している場合を除いても動作しています。videoCompositionプロパティビデオは最初の画像のみを表示します。ここに私のコードは次のとおりです。AVAssetExportSession videoCompositionはビデオ内のすべてのフレームを表示していません

func mergeAudioVideoFiles(videoUrl:NSURL, audioUrl:NSURL)->NSURL 
{ 
    let mixComposition : AVMutableComposition = AVMutableComposition() 
    var mutableCompositionVideoTrack : [AVMutableCompositionTrack] = [] 
    var mutableCompositionAudioTrack : [AVMutableCompositionTrack] = [] 
    let totalVideoCompositionInstruction : AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction() 


    //start merge 

    let aVideoAsset : AVAsset = AVAsset(URL: videoUrl) 
    let aAudioAsset : AVAsset = AVAsset(URL: audioUrl) 

    mutableCompositionVideoTrack.append(mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)) 
    mutableCompositionAudioTrack.append(mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)) 

    let aVideoAssetTrack : AVAssetTrack = aVideoAsset.tracksWithMediaType(AVMediaTypeVideo)[0] 
    let aAudioAssetTrack : AVAssetTrack = aAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0] 
    do{ 
     try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aVideoAssetTrack, atTime: kCMTimeZero) 

     try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aAudioAssetTrack, atTime: kCMTimeZero)  
    }catch{ 

    } 
    print("\nslide duraition:\(CMTimeGetSeconds(aVideoAssetTrack.timeRange.duration))\n") 
    totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,aVideoAssetTrack.timeRange.duration) 

    let mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition(propertiesOfAsset: aVideoAsset) 
    mutableVideoComposition.frameDuration = aVideoAssetTrack.timeRange.duration 
    mutableVideoComposition.renderSize = CGSizeMake(1280,720) 

    //find your video on this URl 
    let savePathUrl : NSURL = NSURL(fileURLWithPath: documentsPath.stringByAppendingPathComponent("pandorarofinalist.mov")) 

    // 4. Add subtitles (we call it theme) 
    let insertTime = kCMTimeZero 
    //let endTime = aVideoAssetTrack.timeRange.duration 
    //let range = self.totalFrameDuration 
    //let themeVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition(propertiesOfAsset: aVideoAsset) 
    // 4.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation. 

    let videolayerInstruction : AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: aVideoAssetTrack) 
    totalVideoCompositionInstruction.layerInstructions = NSArray(array: [videolayerInstruction]) as! [AVVideoCompositionLayerInstruction] 
    mutableVideoComposition.instructions = NSArray(array: [totalVideoCompositionInstruction]) as! [AVVideoCompositionInstructionProtocol] 

    //mutableCompositionAudioTrack[0].preferredTransform 
    videolayerInstruction.setTransform(mutableCompositionVideoTrack[0].preferredTransform, atTime: insertTime) 
    //videolayerInstruction.setOpacity(0.0, atTime: endTime) 

    // 4.3 - Add instructions 


    // mutableVideoComposition.renderScale = 1.0 
    //themeVideoComposition.renderSize = CGSizeMake(aVideoAssetTrack.naturalSize.width, aVideoAssetTrack.naturalSize.height) 
    //themeVideoComposition.frameDuration = self.totalFrameDuration 

    // add text 

    let title = String("my video") 

    let titleLayer = CATextLayer() 
    titleLayer.string = title 
    titleLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: 100) 
    let fontName: CFStringRef = "Helvetica-Bold" 
    let fontSize = CGFloat(50) 
    titleLayer.font = CTFontCreateWithName(fontName, fontSize, nil) 
    titleLayer.alignmentMode = kCAAlignmentCenter 
    titleLayer.foregroundColor = UIColor.orangeColor().CGColor 

    let backgroundLayer = CALayer() 
    backgroundLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: aVideoAssetTrack.naturalSize.height) 
    backgroundLayer.masksToBounds = true 
    backgroundLayer.addSublayer(titleLayer) 

    // 2. set parent layer and video layer 

    let parentLayer = CALayer() 
    let videoLayer = CALayer() 
    parentLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: aVideoAssetTrack.naturalSize.height) 
    videoLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: aVideoAssetTrack.naturalSize.height) 
    parentLayer.addSublayer(videoLayer) 
    parentLayer.addSublayer(backgroundLayer) 

    //backgroundLayer.opacity = 1.0 

    // 3. make animation 

    mutableVideoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer) 

    // Remove the file if it already exists (merger does not overwrite) 

    do{ 
     let fileManager = NSFileManager.defaultManager() 
     try fileManager.removeItemAtURL(savePathUrl) 
    }catch{ 
    } 

    let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)! 
    assetExport.outputFileType = AVFileTypeMPEG4 
    assetExport.outputURL = savePathUrl 
    assetExport.shouldOptimizeForNetworkUse = true 
    assetExport.videoComposition = mutableVideoComposition 

    assetExport.exportAsynchronouslyWithCompletionHandler {() -> Void in 
     switch assetExport.status { 

     case AVAssetExportSessionStatus.Completed: 

      PHPhotoLibrary.sharedPhotoLibrary().performChanges({ 
       PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(savePathUrl) 
      }) { success, error in 
       if !success { 
        print("Error saving video: \(error)") 
       } 
      } 

      //Uncomment this if u want to store your video in asset 

      //let assetsLib = ALAssetsLibrary() 
      //assetsLib.writeVideoAtPathToSavedPhotosAlbum(savePathUrl, completionBlock: nil) 

      print("success") 
     case AVAssetExportSessionStatus.Failed: 
      print("failed \(assetExport.error)") 
     case AVAssetExportSessionStatus.Cancelled: 
      print("cancelled \(assetExport.error)") 
     default: 
      print("complete") 
     } 
    } 

    return savePathUrl 
} 

問題は、その行は、私はこの行を省略した場合、出力映像だけで結構ですassetExport.videoComposition = mutableVideoCompositionです。しかし、この行を追加すると、出力ビデオには、ビデオ用に追加した最初の画像しか表示されません。私はvideoCompositionを設定する必要があります。私はCALayerとして追加したビデオにタイトルテキストを追加しています。私は自分のプロジェクトにswift 2.2を使用しています。助けてください?前もって感謝します。

+0

解決策は見つかりましたか? – Sam

+0

これはAVVideoCompositionCoreAnimationToolのバグです。この投稿とすべての関連記事を確認してくださいhttp://stackoverflow.com/search?tab=newest&q=swift%20AVAssetWriter – Sam

+0

しかし、私は解決策を実装することができませんでした – Sam

答えて

2

私は問題はこのラインであると信じて:

mutableVideoComposition.frameDuration = aVideoAssetTrack.timeRange.duration

frameDurationは、ビデオでは、単一のフレームではなく、動画の合計時間の長さを表すことになっています。上の行は、ビデオの1フレームが元のビデオトラックの長さを持続するようにするため、静止画のように1つのフレームだけを表示します。 30fpsのビデオの場合

、あなたはこのように、第二の1/30にframeDurationを設定する必要があります。

mutableVideoComposition.frameDuration = CMTime(value: 1, timescale: 30)


警告:他のinitメソッドを使用しないように注意してくださいCMTime(seconds: 1.0, preferredTimescale: 30)これは、フレームの長さを1秒にします。

関連する問題