AVMutableComposition以某种方式将纵向视频导出为横向

时间:2017-06-27 21:44:01

标签: ios swift3 avfoundation avmutablecomposition

当源视频为纵向时,此功能将合并的合成导出为横向。我将原始视频以纵向方式保存到我的文档目录中,然后将其保存到相机胶卷并正常工作。然后,我将已保存的视频网址传递给此功能,并且当它不应该以某种方式将其旋转到横向。我该如何解决这个问题?

func makeVideoOverlay (url : URL) {

    print("documents directory url: \(url)")

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

    // get video track

    let vtrack =  vidAsset.tracks(withMediaType: AVMediaTypeVideo)
    let videoTrack:AVAssetTrack = vtrack[0]
    let vid_duration = videoTrack.timeRange.duration
    let vid_timerange = CMTimeRangeMake(kCMTimeZero, vidAsset.duration)

    //var error: NSError?

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

    do {
        try compositionvideoTrack.insertTimeRange(vid_timerange, of: videoTrack, at: kCMTimeZero)
    } catch {
        // handle error

        print("comp video track error: \(error.localizedDescription)")
    }

    compositionvideoTrack.preferredTransform = videoTrack.preferredTransform

    let size = videoTrack.naturalSize

    //this prints out to 1920x1080 landscape dimension. i don't know how

    print("asset size: \(size)")

    // Watermark Effect

    let imglogo = UIImage(named: "logo-image")
    let imglayer = CALayer()
    imglayer.contents = imglogo?.cgImage
    imglayer.frame = CGRect.init(x: 5, y: size.height-160, width: 150, height: 150)
    imglayer.opacity = 1.0

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

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

    parentlayer.addSublayer(videolayer)
    parentlayer.addSublayer(imglayer)

    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: String = dirPaths[0] as String


    let movieFilePath = docsDir.appending("/result.mov") as String

    movieDestinationUrl = URL(fileURLWithPath: movieFilePath)

    print("overlay destination url: \(movieDestinationUrl)")

    // use AVAssetExportSession to export video

    let assetExport = AVAssetExportSession(asset: composition, presetName:AVAssetExportPresetHighestQuality)

    assetExport?.outputFileType = AVFileTypeQuickTimeMovie
    assetExport?.outputURL = movieDestinationUrl as URL

    assetExport?.videoComposition = layercomposition

    assetExport?.exportAsynchronously(completionHandler: {

        if assetExport?.status == AVAssetExportSessionStatus.failed
        {
            print("failed: \(assetExport?.error)")
        }
        else if assetExport?.status == AVAssetExportSessionStatus.cancelled
        {
            print("cancelled: \(assetExport?.error)")
        }
        else
        {
            print("Movie complete")

            OperationQueue.main.addOperation({ () -> Void in

                //saves in landscape
                self.saveAsset(url: self.movieDestinationUrl)                    
            })
        }
    })
}

1 个答案:

答案 0 :(得分:-2)

AVMutableVideoCompositionLayerInstruction有一个方法setTransform(_:at:)

正如documentation所说

  

设置固定变换以从指定时间应用到下一个   设置转换的时间。 [...]。在第一个指定的时间之前   设置变换后,仿射变换保持不变   身份;在最后一次设置变换之后,   仿射变换在最后一个值处保持不变。

您应该将videoTrack' preferredTransform设置为layerInstruction

修改

您需要使用新创建的合成曲目创建layerinstruction

let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compositionvideoTrack) // NOT videoTrack. layerinstruction.setTransform(videoTrack.preferredTransform, at: kCMTimeZero)