我有一个源视频,我想通过获取源视频的每一帧的一个区域来从中生成一个新视频。例如,如果我有一个分辨率为A
x B
、内容大小为X
xY
且输出分辨率为C
xD
的视频,那么我想创建一个分辨率为C
x的视频,D
其内容将是原始视频中每帧的前X
x 个像素。Y
为了实现这一点,我使用一个AVAssetReader
用于阅读源视频和一个AVAssetWriter
用于编写新视频。为了仅提取源视频的区域X
x Y
,我使用一个AVAssetReaderVideoCompositionOutput
对象作为资产读取器的输出。设置代码类似于:
let output = AVAssetReaderVideoCompositionOutput(...)
output.videoComposition = AVMutableVideoComposition(
asset: asset,
videoTrack: videoTrack,
contentRect: contentRect,
renderSize: renderSize
)
然后裁剪视频内容的逻辑发生在以下自定义初始化程序中:
extension AVMutableVideoComposition {
convenience init(asset: AVAsset, videoTrack: AVAssetTrack, contentRect: CGRect, renderSize: CGSize) {
// Compute transform for rendering the video content at `contentRect` with a size equal to `renderSize`.
let trackFrame = CGRect(origin: .zero, size: videoTrack.naturalSize)
let transformedFrame = trackFrame.applying(videoTrack.preferredTransform)
let moveToOriginTransform = CGAffineTransform(translationX: -transformedFrame.minX, y: -transformedFrame.minY)
let moveToContentRectTransform = CGAffineTransform(translationX: -contentRect.minX, y: -contentRect.minY)
let scaleTransform = CGAffineTransform(scaleX: renderSize.width / contentRect.width, y: renderSize.height / contentRect.height)
let transform = videoTrack.preferredTransform.concatenating(moveToOriginTransform).concatenating(moveToContentRectTransform).concatenating(scaleTransform)
let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
layerInstruction.setTransform(transform, at: .zero)
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
instruction.layerInstructions = [layerInstruction]
self.init(propertiesOf: asset)
instructions = [instruction]
self.renderSize = renderSize
}
}
此代码在某些情况下可以正常工作,例如,对于 content size (origin = (x = 0, y = 0), size = (width = 1416, height = 1920))
。但是,如果我将宽度更改为 1417,则它不起作用,并且我收到错误消息:
Error Domain=AVFoundationErrorDomain Code=-11858“源帧格式不支持” UserInfo={NSUnderlyingError=0x283e689c0 {Error Domain=NSOSStatusErrorDomain Code=-12502“(null)”},NSLocalizedFailureReason=视频无法合成,NSDebugDescription=源帧不支持的格式,NSLocalizedDescription=操作停止}
这是一个带有测试视频的示例项目的链接,我得到了错误。这种失败的情况对我来说是随机的,因为它适用于宽度 1416、1421、1422、1423、1429 并且对于 1416 和 1429 之间的所有其他宽度值都失败。这里有什么问题,我该如何解决这个问题?
为什么我使用这种方法?
我使用 anAVAssetReaderVideoCompositionOutput
而不是使用 anAVAssetReaderTrackOutput
然后手动进行裁剪的原因是因为使用前者可以减少应用程序的内存占用,因为在我的用例中,输出渲染大小将比视频原始大小小得多尺寸。当我同时处理多个视频时,这很重要。