我已经能够将 16:9 横向视频的中间居中,裁剪视频,然后创建视频的 9:16 纵向版本,类似于 Apple does it 的方式。在照片相册中。
唯一的问题是生成的纵向视频未居中于屏幕中间(如下图)。
如何在屏幕中央获得生成的肖像视频?
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
}
初始水平视频:
运行上述代码后生成的肖像视频。视频在屏幕上不正确居中:
这是它应该居中的方式:
最佳答案
如果有人有更好的答案,请发布,我会检查并接受。
我不知道视频处于正确的位置,但负黑条空间导致视频看起来未对齐。更改 AVMutableVideoCompositionInstruction()
.backgroundColor
显示黄色中的负黑条空间问题:
instruction.backgroundColor = UIColor.yellow.cgColor
为了修复 .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
视频的结果:
.landscapeRight
视频的结果,负黑条空间为黄色,以显示它现在如何居中:
关于ios - CGAffineTransform -如何在屏幕中心对齐视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72074158/