当源视频为纵向时,此功能将合并的构图导出为横向。我将原始视频以纵向方向保存到我的文档目录中,然后将其保存到相机胶卷中并且工作正常。然后,我将保存的视频的url传递给此函数,并在不应该的情况下以某种方式将其旋转为横向。我该如何解决?

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

最佳答案

AVMutableVideoCompositionLayerInstruction具有方法setTransform(_:at:)
正如documentation所说

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

您应该将videoTrackpreferredTransform设置为layerInstruction

编辑

您需要改为使用新创建的合成音轨创建layerinstruction
let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compositionvideoTrack) // NOT videoTrack.layerinstruction.setTransform(videoTrack.preferredTransform, at: kCMTimeZero)

08-17 16:51