GPUImage 裁剪为 CGRect 并旋转
GPUImage crop to CGRect and rotate
鉴于 CGRect
,我想使用 GPUImage 裁剪视频。例如,如果矩形是 (0, 0, 50, 50)
,则视频将在 (0,0)
处裁剪,每边长度为 50。
让我感到震惊的是 GPUImageCropFilter
不采用矩形,而是采用值范围为 0 到 1 的标准化裁剪区域。我的直觉是:
let assetSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, videoTrack.preferredTransform)
let cropRect = CGRect(x: frame.minX/assetSize.width,
y: frame.minY/assetSize.height,
width: frame.width/assetSize.width,
height: frame.height/assetSize.height)
根据传入资源的大小计算裁剪区域。那么:
// Filter
let cropFilter = GPUImageCropFilter(cropRegion: cropRect)
let url = NSURL(fileURLWithPath: "\(NSTemporaryDirectory())\(String.random()).mp4")
let movieWriter = GPUImageMovieWriter(movieURL: url, size: assetSize)
movieWriter.encodingLiveVideo = false
movieWriter.shouldPassthroughAudio = false
// add targets
movieFile.addTarget(cropFilter)
cropFilter.addTarget(movieWriter)
cropFilter.forceProcessingAtSize(frame.size)
cropFilter.setInputRotation(kGPUImageRotateRight, atIndex: 0)
电影作家的尺寸应该是多少?它不应该是我想要裁剪的框架的大小吗?我应该将 forceProcessingAtSize
与裁剪框的尺寸值一起使用吗?
如果有完整的代码示例就好了;我已经尝试了几个小时,但似乎无法获得我想要的视频部分。
决赛:
if let videoTrack = self.asset.tracks.first {
let movieFile = GPUImageMovie(asset: self.asset)
let transformedRegion = CGRectApplyAffineTransform(region, videoTrack.preferredTransform)
// Filters
let cropFilter = GPUImageCropFilter(cropRegion: transformedRegion)
let url = NSURL(fileURLWithPath: "\(NSTemporaryDirectory())\(String.random()).mp4")
let renderSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, CGAffineTransformMakeScale(transformedRegion.width, transformedRegion.height))
let movieWriter = GPUImageMovieWriter(movieURL: url, size: renderSize)
movieWriter.transform = videoTrack.preferredTransform
movieWriter.encodingLiveVideo = false
movieWriter.shouldPassthroughAudio = false
// add targets
//
movieFile.addTarget(cropFilter)
cropFilter.addTarget(movieWriter)
movieWriter.completionBlock = {
observer.sendNext(url)
observer.sendCompleted()
}
movieWriter.failureBlock = { _ in
observer.sendFailed(.VideoCropFailed)
}
disposable.addDisposable {
cropFilter.removeTarget(movieWriter)
movieWriter.finishRecording()
}
movieWriter.startRecording()
movieFile.startProcessing()
}
正如您所注意到的,GPUImageCropFilter 接受标准化坐标中的矩形。您走在正确的轨道上,因为您只需要将 X 分量(origin.x 和 size.width)除以图像宽度和 Y 分量,将以像素为单位的 CGRect 转换为归一化坐标按高度。
您不需要使用forceProcessingAtSize()
,因为裁剪会自动输出适当裁剪尺寸的图像。电影作家的尺寸应该与这个裁剪尺寸相匹配,你应该从你的原始 CGRect 中知道。
您介绍的一个复杂问题是旋转。如果除了裁剪之外还需要应用旋转,您可能需要检查并确保不需要为裁剪区域交换 X 和 Y。如果需要交换两者,这在输出中应该很明显。
不久前在裁剪的同时应用旋转有一些错误,我不记得我是否修复了所有这些错误。如果我没有,您可以在裁剪之前或之后插入一个虚拟滤镜(伽玛或亮度设置为默认值)并在该阶段应用旋转。
鉴于 CGRect
,我想使用 GPUImage 裁剪视频。例如,如果矩形是 (0, 0, 50, 50)
,则视频将在 (0,0)
处裁剪,每边长度为 50。
让我感到震惊的是 GPUImageCropFilter
不采用矩形,而是采用值范围为 0 到 1 的标准化裁剪区域。我的直觉是:
let assetSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, videoTrack.preferredTransform)
let cropRect = CGRect(x: frame.minX/assetSize.width,
y: frame.minY/assetSize.height,
width: frame.width/assetSize.width,
height: frame.height/assetSize.height)
根据传入资源的大小计算裁剪区域。那么:
// Filter
let cropFilter = GPUImageCropFilter(cropRegion: cropRect)
let url = NSURL(fileURLWithPath: "\(NSTemporaryDirectory())\(String.random()).mp4")
let movieWriter = GPUImageMovieWriter(movieURL: url, size: assetSize)
movieWriter.encodingLiveVideo = false
movieWriter.shouldPassthroughAudio = false
// add targets
movieFile.addTarget(cropFilter)
cropFilter.addTarget(movieWriter)
cropFilter.forceProcessingAtSize(frame.size)
cropFilter.setInputRotation(kGPUImageRotateRight, atIndex: 0)
电影作家的尺寸应该是多少?它不应该是我想要裁剪的框架的大小吗?我应该将 forceProcessingAtSize
与裁剪框的尺寸值一起使用吗?
如果有完整的代码示例就好了;我已经尝试了几个小时,但似乎无法获得我想要的视频部分。
决赛:
if let videoTrack = self.asset.tracks.first {
let movieFile = GPUImageMovie(asset: self.asset)
let transformedRegion = CGRectApplyAffineTransform(region, videoTrack.preferredTransform)
// Filters
let cropFilter = GPUImageCropFilter(cropRegion: transformedRegion)
let url = NSURL(fileURLWithPath: "\(NSTemporaryDirectory())\(String.random()).mp4")
let renderSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, CGAffineTransformMakeScale(transformedRegion.width, transformedRegion.height))
let movieWriter = GPUImageMovieWriter(movieURL: url, size: renderSize)
movieWriter.transform = videoTrack.preferredTransform
movieWriter.encodingLiveVideo = false
movieWriter.shouldPassthroughAudio = false
// add targets
//
movieFile.addTarget(cropFilter)
cropFilter.addTarget(movieWriter)
movieWriter.completionBlock = {
observer.sendNext(url)
observer.sendCompleted()
}
movieWriter.failureBlock = { _ in
observer.sendFailed(.VideoCropFailed)
}
disposable.addDisposable {
cropFilter.removeTarget(movieWriter)
movieWriter.finishRecording()
}
movieWriter.startRecording()
movieFile.startProcessing()
}
正如您所注意到的,GPUImageCropFilter 接受标准化坐标中的矩形。您走在正确的轨道上,因为您只需要将 X 分量(origin.x 和 size.width)除以图像宽度和 Y 分量,将以像素为单位的 CGRect 转换为归一化坐标按高度。
您不需要使用forceProcessingAtSize()
,因为裁剪会自动输出适当裁剪尺寸的图像。电影作家的尺寸应该与这个裁剪尺寸相匹配,你应该从你的原始 CGRect 中知道。
您介绍的一个复杂问题是旋转。如果除了裁剪之外还需要应用旋转,您可能需要检查并确保不需要为裁剪区域交换 X 和 Y。如果需要交换两者,这在输出中应该很明显。
不久前在裁剪的同时应用旋转有一些错误,我不记得我是否修复了所有这些错误。如果我没有,您可以在裁剪之前或之后插入一个虚拟滤镜(伽玛或亮度设置为默认值)并在该阶段应用旋转。