如何解决同时使用AVComposition和AVVideoComposition时转换错误
我正在创建一个AVMutableComposition
。我需要将资产水平翻转,因此我要像这样设置合成轨道的变换:
compositionTrack.preferredTransform = assetTrack.preferredTransform.scaledBy(x: -1,y: 1)
如果我导出此文件(我使用AVAssetPreset960x640
作为预设),则可以正常工作。
但是,我还需要添加一个AVMutableVideoComposition
叠加层才能使用此copmosition进行渲染。此叠加层不应水平翻转。我这样指定:
// Create video composition
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = videoSize
videoComposition.frameDuration = CMTime(value: 1,timescale: 30)
videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(
postProcessingAsVideoLayer: videoLayer,in: outputLayer
)
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRange(
start: .zero,duration: composition.duration
)
let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compositionTrack)
layerInstruction.setTransform(assetTrack.preferredTransform,at: .zero)
instruction.layerInstructions = [layerInstruction]
videoComposition.instructions = [instruction]
当我以此导出视频时,它不会水平翻转。它将停止执行应用于合成的PreferredTransform。大概是这条线导致了这一点:
layerInstruction.setTransform(assetTrack.preferredTransform,at: .zero)
如果将图层变换设置为assetTrack.preferredTransform.scaledBy(x: -1,y: 1)
或compositionTrack.preferredTransform
,则导出时会出现黑屏。
Apple有these docs解释了AVVideoComposition上的转换。如果我理解正确,他们会说我应该设置图层指令的转换。如果我这样做-对图层指令而不是对合成应用转换-我仍然会看到黑屏。
这是为什么,我该如何解决?
解决方法
编辑:有效的转换是
CGAffineTransform(a: -1.0,b: 0.0,c: 0.0,d: 1.0,tx: videoSize.width,ty: 0.0)
因此,在RayWenderlich tutorial之后,我又遇到了这个问题(您的代码看起来也非常熟悉!)。问题是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,d: -1,tx: assetSize.width,ty: assetSize.height)
case .left:
transform = CGAffineTransform(a: 0,b: -1,c: 1,d: 0,ty: assetSize.width)
case .right:
transform = CGAffineTransform(a: 0,b: 1,c: -1,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...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。