ios - CGAffineTransform -如何在屏幕中心对齐视频

标签 ios swift avfoundation cgaffinetransform avvideocomposition

我已经能够将 16:9 横向视频的中间居中,裁剪视频,然后创建视频的 9:16 纵向版本,类似于 Apple does it 的方式。在照片相册中。

enter image description here

唯一的问题是生成的纵向视频未居中于屏幕中间(如下图)。

如何在屏幕中央获得生成的肖像视频?

func createExportSession(for videoURL: URL) {

    let asset = AVURLAsset(url: videoURL)
    let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)!

    exporter.videoComposition = turnHorizontalVideoToPortraitVideo(asset: asset)

    exporter.outputURL = // ...
    exporter.outputFileType = AVFileType.mp4
    exporter.shouldOptimizeForNetworkUse = true

    exporter.exportAsynchronously { [weak self] in

        // ...

        // the exporter.url is eventually added to an AVURLAsset and played inside an AVPlayer
    }
}

func turnHorizontalVideoToPortraitVideo(asset: AVURLAsset) -> AVVideoComposition {

    let track = asset.tracks(withMediaType: AVMediaType.video)[0]

    let renderSize = CGSize(width: 720, height: 1280)

    var transform1 = track.preferredTransform
    transform1 = transform1.concatenating(CGAffineTransform(rotationAngle: CGFloat(90.0 * .pi / 180)))
    transform1 = transform1.concatenating(CGAffineTransform(translationX: track.naturalSize.width, y: 0))

    let transform2 = CGAffineTransform(translationX: track.naturalSize.height, y: (track.naturalSize.width - track.naturalSize.height) / 2)

    let transform3 = transform2.rotated(by: CGFloat(Double.pi/2)).concatenating(transform1)

    let translate = CGAffineTransform(translationX: renderSize.width, y: renderSize.height)
    let rotateFromUpsideDown = translate.rotated(by: CGFloat(Double.pi)) // without this the portrait video is always upside down 

    let finalTransform = transform3.concatenating(rotateFromUpsideDown)

    let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
    transformer.setTransform(finalTransform, at: .zero)

    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
    instruction.layerInstructions = [transformer]

    let videoComposition = AVMutableVideoComposition()
    videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
    videoComposition.renderSize = renderSize
    videoComposition.instructions = [instruction]
        
    return videoComposition
}

初始水平视频:

enter image description here

运行上述代码后生成的肖像视频。视频在屏幕上不正确居中:

enter image description here

这是它应该居中的方式:

enter image description here

最佳答案

如果有人有更好的答案,请发布,我会检查并接受

我不知道视频处于正确的位置,但负黑条空间导致视频看起来未对齐。更改 AVMutableVideoCompositionInstruction() .backgroundColor 显示黄色中的负黑条空间问题:

instruction.backgroundColor = UIColor.yellow.cgColor

enter image description here

为了修复 .landscapeRight 视频的问题,我将 finalTransform.ty 分成两半,并从翻译 y 值中减去它。对于 .landscapeLeft 视频,我添加了以下代码:

func turnHorizontalVideoToPortraitVideo(asset: AVURLAsset) -> AVVideoComposition {

    let track = asset.tracks(withMediaType: AVMediaType.video)[0]

    let renderSize = CGSize(width: 720, height: 1280)

    let t = track.preferredTransform

    if (t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0) {
        print("landscapeRight")
    }

    var isLandscapeLeft = false
    if (t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0) {
        print("landscapeLeft")
        isLandscapeLeft = true
    }

    var transform1 = t
    transform1 = transform1.concatenating(CGAffineTransform(rotationAngle: CGFloat(90.0 * .pi / 180)))
    transform1 = transform1.concatenating(CGAffineTransform(translationX: track.naturalSize.width, y: 0))

    let transform2 = CGAffineTransform(translationX: track.naturalSize.height, y: (track.naturalSize.width - track.naturalSize.height) / 2)

    var p = Double.pi/2
    if isLandscapeLeft {
        p = -Double.pi/2
    }
    let transform3 = transform2.rotated(by: CGFloat(p)).concatenating(transform1)

    let finalTransform = transform3

    let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: track)

    if isLandscapeLeft {
            
        let ty = finalTransform.ty
        let dividedNum = ty/2.5
            
        let translation = CGAffineTransform(translationX: 0, y: dividedNum)
        let new_finalTransform = finalTransform.concatenating(translation)
            
        transformer.setTransform(new_finalTransform, at: .zero)
    }

    if !isLandscapeLeft {
            
        let translate = CGAffineTransform(translationX: renderSize.width, y: renderSize.height)
        let rotateFromUpsideDown = translate.rotated(by: CGFloat(Double.pi))
        let transformRotated = finalTransform.concatenating(rotateFromUpsideDown)
            
        let ty = transformRotated.ty
            
        var dividedNum = ty/2
            
        if dividedNum < 0 {
            dividedNum = 0
        }
            
        let translation = CGAffineTransform(translationX: 0, y: -dividedNum)
        let new_finalTransform = transformRotated.concatenating(translation)
            
        transformer.setTransform(new_finalTransform, at: .zero)
    }

    let instruction = AVMutableVideoCompositionInstruction()
    //instruction.backgroundColor = UIColor.yellow.cgColor
    instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
    instruction.layerInstructions = [transformer]
        
    let videoComposition = AVMutableVideoComposition()
    videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
    videoComposition.renderSize = renderSize
    videoComposition.instructions = [instruction]
        
    return videoComposition
}

.landscapeRight 视频的结果:

enter image description here

.landscapeRight 视频的结果,负黑条空间为黄色,以显示它现在如何居中:

enter image description here

关于ios - CGAffineTransform -如何在屏幕中心对齐视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72074158/

相关文章:

删除后iOS导航栏 subview 重新出现

swift - iOS10 中的 PFImageView loadInBackground() 问题

objective-c - AVPlayerLooper 不会循环播放多个视频

swift - 创建 WAV 文件时生成错误字节

ios - 使用 CoreData 快速保存分数

php - Swift4 - 错误域=NSCocoaErrorDomain 代码=4865

ios - 如何获取UIScrollView中显示区域的中心?

ios - 键盘约束问题

iphone - Linea Pro 扫描条码问题

swift - AVFoundation:缩放视频改变颜色