编辑:有效的转换是
CGAffineTransform(a: -1.0, b: 0.0, c: 0.0, d: 1.0, tx: videoSize.width, ty: 0.0)
所以我不久前遇到了这个问题,遵循这个 RayWenderlich教程(你的代码看起来也非常熟悉!)。问题是这assetTrack.preferredTransform
不可靠,在某些视频上它可以工作,而在其他视频上它会是黑屏。
代替
let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compositionTrack)
layerInstruction.setTransform(assetTrack.preferredTransform, at: .zero)
试试这个:
func compositionLayerInstruction(for track: AVCompositionTrack, assetTrack: AVAssetTrack, orientation: UIImage.Orientation) -> AVMutableVideoCompositionLayerInstruction {
let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
var transform = CGAffineTransform.identity
let assetSize = assetTrack.naturalSize
/// you should be able to play with these values to make a horizontal flip (try changing `a` and `d`)
switch orientation {
case .up:
transform = CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0)
case .down:
transform = CGAffineTransform(a: -1, b: 0, c: 0, d: -1, tx: assetSize.width, ty: assetSize.height)
case .left:
transform = CGAffineTransform(a: 0, b: -1, c: 1, d: 0, tx: 0, ty: assetSize.width)
case .right:
transform = CGAffineTransform(a: 0, b: 1, c: -1, d: 0, tx: assetSize.height, ty: 0)
default:
print("Unsupported orientation")
}
instruction.setTransform(transform, at: .zero)
return instruction
}
let layerInstruction = compositionLayerInstruction(
for: compositionTrack, assetTrack: assetTrack, orientation: videoInfo.orientation)
/// assetTrack is the original video
我将此基于SO的另一个答案,但不记得在哪里。
这是一个辅助函数,用于获取orientation
/// adjust the video orientation is the source has a different orientation
private func orientation(from transform: CGAffineTransform) -> (orientation: UIImage.Orientation, isPortrait: Bool) {
var assetOrientation = UIImage.Orientation.up
var isPortrait = false
if transform.a == 0 && transform.b == 1.0 && transform.c == -1.0 && transform.d == 0 {
assetOrientation = .right
isPortrait = true
} else if transform.a == 0 && transform.b == -1.0 && transform.c == 1.0 && transform.d == 0 {
assetOrientation = .left
isPortrait = true
} else if transform.a == 1.0 && transform.b == 0 && transform.c == 0 && transform.d == 1.0 {
assetOrientation = .up
} else if transform.a == -1.0 && transform.b == 0 && transform.c == 0 && transform.d == -1.0 {
assetOrientation = .down
}
return (assetOrientation, isPortrait)
}
完整用法:
/// get adjusted orientation of the video
let videoInfo = orientation(from: assetTrack.preferredTransform)
let videoSize: CGSize
if videoInfo.isPortrait {
videoSize = CGSize(
width: assetTrack.naturalSize.height,
height: assetTrack.naturalSize.width)
} else {
videoSize = assetTrack.naturalSize
}
/// the video
let videoLayer = CALayer()
videoLayer.frame = CGRect(origin: .zero, size: videoSize)
/// overlay where you add graphics and other stuff
let overlayLayer = CALayer()
overlayLayer.frame = CGRect(origin: .zero, size: videoSize)
let outputLayer = CALayer()
outputLayer.frame = CGRect(origin: .zero, size: videoSize)
outputLayer.addSublayer(videoLayer)
outputLayer.addSublayer(overlayLayer)
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = videoSize
videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(
postProcessingAsVideoLayer: videoLayer,
in: outputLayer)
// MARK: - previous `let layerInstruction` code goes here...
instruction.layerInstructions = [layerInstruction]
/// export session code here...