我已经成功从视频中提取了所有帧,并且它适用于较小的视频,但是当我尝试从视频中提取超过60秒的帧时,应用程序在设备上崩溃。
我从视频中每秒提取30帧。
以下是我写的代码: -
var videoSec = Float64(0)
func startImageConversion(){
let filePath = NSURL.fileURLWithPath(self.savedVideoURL)
videoSec = self.getVideoTime(filePath)
videoImagesArray = self.getImagesArrayFromVideo(filePath)
print("Images Count \(videoImagesArray.count)")
}
// MARK: - 视频编辑器功能
func getImagesArrayFromVideo(filePath:NSURL) -> NSMutableArray
{
let imageArray = NSMutableArray()
print("Video Sec is ",videoSec)
let vidSec = Float64(videoSec)
let theOpts = [
AVURLAssetPreferPreciseDurationAndTimingKey : true,
AVURLAssetReferenceRestrictionsKey : 0 // AVAssetReferenceRestrictions.RestrictionForbidNone
]
let asset = AVURLAsset(URL: filePath, options: theOpts)
let generator = AVAssetImageGenerator(asset: asset)
generator.maximumSize = CGSize(width: Double(self.view.frame.size.width),
height: Double(self.view.frame.size.height))
generator.appliesPreferredTrackTransform = false
generator.requestedTimeToleranceBefore = kCMTimeZero
generator.requestedTimeToleranceAfter = kCMTimeZero
let vid_length:CMTime = asset.duration
let fps = vid_length.timescale
print("Video Lenght :- \(vid_length) FPS is :- \(fps)")
let mainValue = Float64(vid_length.value)
let divide = vidSec*30
let byVal = mainValue/divide
for i in 0.stride(through: Float64(vid_length.value), by: byVal)
{
var image:CGImage!//UIImage()
let divident = Float64(i)
// let mileSec = Float64(divident / 1000)
// print(Sec)
image = self.generateVideoThumbs(filePath, second: divident,
thumbWidth: Double(self.view.frame.size.width),
generator : generator,
fps : fps
)
if image != nil {
imageArray.addObject(image)
}
}
print("value of Array is ",imageArray.count)
return imageArray
}
private func getVideoTime(url: NSURL) -> Float64
{
let videoTime = AVURLAsset(URL: url, options: nil)
print("videoTime.preferredRate = \(videoTime.preferredRate)")
return CMTimeGetSeconds(videoTime.duration)
}
private func generateVideoThumbs(url: NSURL, second: Float64, thumbWidth: Double, generator:AVAssetImageGenerator, fps: CMTimeScale) -> CGImage! {
let thumbTime = CMTimeMake(Int64(second), fps)
var actualTime : CMTime = CMTimeMake(0, 0)
print("thumbTime - \(thumbTime)")
do {
let ref = try generator.copyCGImageAtTime(thumbTime, actualTime: &actualTime)
print("actualTime - \(actualTime)")
return ref//UIImage(CGImage: ref)
}catch {
print(error)
return nil
}
}
如果视频小于60秒左右,一切正常。 它也可以在模拟器上正常工作,但在没有任何警告或错误的情况下断开设备。 任何帮助将不胜感激,谢谢
答案 0 :(得分:2)
autoreleasepool{
if image != nil {
var newImage:UIImage = UIImage(CGImage: cgImage)
imageArray.addObject(image)
}
}
如上面的答案潜水中提到的那样是记忆问题。 只需使用此代码。我测试了它,它工作正常。
答案 1 :(得分:1)
Core Graphics不支持Objective C中的自动释放池,但是Swift ARC可以处理CF类型,无论如何,在某些情况下你仍然会遇到CGImage
发布的问题,也许就是这种情况,你显然有问题使用imageArray
的大小,我确定您的设备因out of memory
SIGTERM而断开连接。 iOS模拟器在现代15英寸开发MacBook上使用共享内存,因此,一切都将在那里工作。
我建议您重写generateVideoThumbs(...)
函数并使用UIImage
作为返回值(您已经尝试过,因为我可以看到,只需使用UIImage
返回您的解决方案):< / p>
private func generateVideoThumbs(url: NSURL, second: Float64, thumbWidth: Double, generator:AVAssetImageGenerator, fps: CMTimeScale) -> UIImage! {
let thumbTime = CMTimeMake(Int64(second), fps)
var actualTime : CMTime = CMTimeMake(0, 0)
print("thumbTime - \(thumbTime)")
do {
let ref = try generator.copyCGImageAtTime(thumbTime, actualTime: &actualTime)
let resultImage = UIImage.init(ref)
print("actualTime - \(actualTime)")
return resultImage
}catch {
print(error)
return nil
}
}
其次,我建议您将图像保存到磁盘,并仅存储imageArray
中的链接。像这样:
if image != nil {
let data = UIImagePNGRepresentation(image)
let filename = NSTemporaryDirectory().appendingPathComponent("\(i).png")
try? data.write(to: filename)
imageArray.addObject(filename)
}
然后,您可以从网址中提取图片,并执行您计划使用的任何内容。它允许您以任何您想要的方式避免内存压力并使用您的阵列(复制,转发到另一个类等)。
P.S。我编写的代码没有编译,但我认为这个想法很清楚。
答案 2 :(得分:1)
这是一个记忆问题。 copeCGImageAtTime
在主线程中是同步的,如果你将它放入for循环就会出现问题。
使用- (void)generateCGImagesAsynchronouslyForTimes:(NSArray<NSValue *> *)requestedTimes completionHandler:(AVAssetImageGeneratorCompletionHandler)handler;
而不是- (nullable CGImageRef)copyCGImageAtTime:(CMTime)requestedTime actualTime:(nullable CMTime *)actualTime error:(NSError * _Nullable * _Nullable)outError CF_RETURNS_RETAINED;
。
再试一次。
度过愉快的一天。