ios - AVExportSession | 在视频上添加带有 GIF 和绘图的 UIView
问题描述
Objective :
我有一个视频,我有一个 UIView,其中包含动画 GIF(不是本地存储,而是使用 giphy api)、文本或手绘图。我想将其与图像一起导出到单个视频中。
What I did :
我创建了一个动画所在的 UIView。然后将其转换为 CALayer 并使用 AVMutableVideoCompotion 添加到视频中。
Problem :
带有动画的 UIView 被转换为图像而不是视频。我该如何解决这个问题。以下是我的导出会话的程序。任何指针都会非常有帮助。
func convertVideoAndSaveTophotoLibrary(videoURL: URL) {
let file = FileManager.shared.getDocumentDirectory(path: currentFilename)
FileManager.shared.clearPreviousFiles(withPath: file.path)
// File to composit
let asset = AVURLAsset(url: videoURL as URL)
let composition = AVMutableComposition.init()
composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)
let clipVideoTrack = asset.tracks(withMediaType: AVMediaType.video)[0]
// Rotate to potrait
let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: clipVideoTrack)
let videoTransform:CGAffineTransform = clipVideoTrack.preferredTransform
//fix orientation
var videoAssetOrientation_ = UIImage.Orientation.up
var isVideoAssetPortrait_ = false
if videoTransform.a == 0 && videoTransform.b == 1.0 && videoTransform.c == -1.0 && videoTransform.d == 0 {
videoAssetOrientation_ = UIImage.Orientation.right
isVideoAssetPortrait_ = true
}
if videoTransform.a == 0 && videoTransform.b == -1.0 && videoTransform.c == 1.0 && videoTransform.d == 0 {
videoAssetOrientation_ = UIImage.Orientation.left
isVideoAssetPortrait_ = true
}
if videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0 {
videoAssetOrientation_ = UIImage.Orientation.up
}
if videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0 {
videoAssetOrientation_ = UIImage.Orientation.down;
}
transformer.setTransform(clipVideoTrack.preferredTransform, at: CMTime.zero)
transformer.setOpacity(0.0, at: asset.duration)
//adjust the render size if neccessary
var naturalSize: CGSize
if(isVideoAssetPortrait_){
naturalSize = CGSize(width: clipVideoTrack.naturalSize.height, height: clipVideoTrack.naturalSize.width)
} else {
naturalSize = clipVideoTrack.naturalSize;
}
var renderWidth: CGFloat!
var renderHeight: CGFloat!
renderWidth = naturalSize.width
renderHeight = naturalSize.height
let parentlayer = CALayer()
let videoLayer = CALayer()
let watermarkLayer = CALayer()
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = CGSize(width: renderWidth, height: renderHeight)
videoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
videoComposition.renderScale = 1.0
//---------------------->>>>>> converting uiview to uiimage
watermarkLayer.contents = canvasView.asImage().cgImage
parentlayer.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: naturalSize)
videoLayer.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: naturalSize)
watermarkLayer.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: naturalSize)
parentlayer.addSublayer(videoLayer)
parentlayer.addSublayer(watermarkLayer)
//---------------------->>>>>> Add view to video
videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayers: [videoLayer], in: parentlayer)
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: CMTimeMakeWithSeconds(60, preferredTimescale: 30))
instruction.layerInstructions = [transformer]
videoComposition.instructions = [instruction]
let exporter = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetHighestQuality)
exporter?.outputFileType = AVFileType.mp4
exporter?.outputURL = file
exporter?.videoComposition = videoComposition
exporter?.shouldOptimizeForNetworkUse = true
exporter!.exportAsynchronously(completionHandler: {() -> Void in
if exporter?.status == .completed {
let outputURL: URL? = exporter?.outputURL
self.saveToPhotoLibrary(url: outputURL!)
}
})
}
将 UIView 转换为 UIimage
extension UIView {
func asImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
Code for Adding the GIF
(我这里使用的是 Giphy API),所以下载了 gif 然后添加
func didSelectMedia(giphyViewController: GiphyViewController, media: GPHMedia) {
addMedia(media: media)
giphyViewController.dismiss(animated: true) { [weak self] in
self?.giphy = nil
}
}
// GPHMediaView is a subclass of UIImageView
func addMedia(media: GPHMedia) {
let mediaView = GPHMediaView()
mediaView.media = media
mediaView.contentMode = .scaleAspectFill
mediaView.frame.size = CGSize(width: 150, height: 150)
mediaView.center = canvasView.center
canvasView.addSubview(mediaView)
print(mediaView.frame)
self.addGesturesTo(mediaView)
}
我得到了什么:视频上的猫是一个 gif。但可悲的是,我得到的只是一帧。现在我知道这是因为我正在将视图转换为图像。但这是我需要知道的解决方案。如何将 gif 合并到视频中。
解决方案
推荐阅读
- javascript - 为什么javascript在控制台中显示“Uncaught SyntaxError: Identifier 'Common' has already been declared after making javascript class object”?
- r - 如何使日期成为第一列?
- laravel - 试图获取非对象 Laravel 5.8 的属性“dept_name”
- python - CBV:如何使用 Django FormView 进行下拉数据库查询
- javascript - 你如何在 vanilla javascript 中创建 xmlhttprequest
- java - 在不更改变量类型的情况下将浮点数格式化为小数点后 2 位
- testing - 如何完成像mocha这样的testcafe测试结构
- python - 创建显示上一期间百分比 +/- 的列
- python - 如何将html格式的json有效负载解析为django中的api并执行计算
- django - Django taggit 相关帖子未显示在模板上