问题描述
现在我正在该模块中开发一个模块,我需要从数组 CGImage 创建视频,在执行此操作时,我的应用程序在某些时候崩溃了,我无法找出崩溃背后的确切原因。
任何人都可以建议我是否朝着正确的方向前进,我应该将 [CGImage] 转换为视频还是需要选择其他方法。
我也尝试将 CGImage 转换为 UIImage 并尝试创建视频,但仍然面临同样的问题。
我在 [UInt8] 数据中获取图像数据,那么转换图像格式和创建视频的正确方法是什么?
为了从 [CGImage] 创建视频,请遵循以下方法。 我正在使用 CGDataProvider 将 [UInt8] 数据转换为 CGImage,并将 CGImage 转换为 UIImage。我有一系列图像并收集 UIImage,然后合并图像并创建视频。
这是我从数据转换 CGImage 的代码。
private(set) var data: [UInt8]
var cgImage: CGImage? {
let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let bitsPerPixel = channels * bitsPerComponent
let bytesPerRow = channels * width
let totalBytes = height * bytesPerRow
let bitmapInfo = CGBitmapInfo(rawValue: channels == 3 ? CGImageAlphaInfo.none.rawValue : CGImageAlphaInfo.last.rawValue)
let provider = CGDataProvider( dataInfo: nil,data: data,size: totalBytes,releaseData: {_,_,_ in })!
return CGImage(width: width,height: height,bitsPerComponent: bitsPerComponent,bitsPerPixel: bitsPerPixel,bytesPerRow: bytesPerRow,space: colorSpaceRef,bitmapInfo: bitmapInfo,provider: provider,decode: nil,shouldInterpolate: false,intent: CGColorRenderingIntent.perceptual)
}
当我开始频繁地将图像绘制到上下文时,我的应用程序在此功能中崩溃
(context!.draw(cgImage,in: CGRect(x: 0,y: 0,width: frameWidth,高度:frameHeight)))
如果我使用捆绑包中的图像数量并使用此代码创建视频,则其工作正常。当我使用从 [UInt8] 数据创建的 CGImage 时,它在写入 3-4 个图像后开始崩溃。
func newPixelBufferFrom(cgImage:CGImage) -> CVPixelBuffer?{
autoreleasepool {
let options:[String: Any] = [kCVPixelBufferCGImageCompatibilityKey as String: true,kCVPixelBufferCGBitmapContextCompatibilityKey as String: true]
var pxbuffer:CVPixelBuffer?
let frameWidth = self.videoSettings[AVVideoWidthKey] as! Int
let frameHeight = self.videoSettings[AVVideoHeightKey] as! Int
let status = CVPixelBufferCreate(kCFAllocatorDefault,frameWidth,frameHeight,kCVPixelFormatType_32ARGB,options as CFDictionary?,&pxbuffer)
assert(status == kCVReturnSuccess && pxbuffer != nil,"newPixelBuffer failed")
CVPixelBufferLockBaseAddress(pxbuffer!,CVPixelBufferLockFlags(rawValue: 0))
let pxdata = CVPixelBufferGetBaseAddress(pxbuffer!)
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGContext(data: pxdata,height: frameHeight,bitsPerComponent: 8,bytesPerRow: CVPixelBufferGetBytesPerRow(pxbuffer!),space: rgbColorSpace,bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
assert(context != nil,"context is nil")
context!.concatenate(CGAffineTransform.identity)
context!.draw(cgImage,height: frameHeight))
CVPixelBufferUnlockBaseAddress(pxbuffer!,CVPixelBufferLockFlags(rawValue: 0))
return pxbuffer
}
在这里,我使用下面的代码从图像数组创建视频。
typealias CXEMovieMakerCompletion = (URL) -> Void
typealias CXEMovieMakerUIImageExtractor = (AnyObject) -> UIImage?
public class CXEImagesToVideo: NSObject{
var assetWriter:AVAssetWriter!
var writeInput:AVAssetWriterInput!
var bufferAdapter:AVAssetWriterInputPixelBufferAdaptor!
var videoSettings:[String : Any]!
var frameTime:CMTime!
var fileURL:URL!
var completionBlock: CXEMovieMakerCompletion?
var movieMakerUIImageExtractor:CXEMovieMakerUIImageExtractor?
public class func videoSettings(codec:String,width:Int,height:Int) -> [String: Any]{
if(Int(width) % 16 != 0){
print("warning: video settings width must be divisible by 16")
}
let videoSettings:[String: Any] = [AVVideoCodecKey: AVVideoCodecType.h264,AVVideoWidthKey: width,AVVideoHeightKey: height]
return videoSettings
}
public init(videoSettings: [String: Any],frameTime: CMTime) {
super.init()
self.frameTime = frameTime
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,true)
let tempPath = paths[0] + "/exprotvideo1.mp4"
if(FileManager.default.fileExists(atPath: tempPath)){
guard (try? FileManager.default.removeItem(atPath: tempPath)) != nil else {
print("remove path failed")
return
}
}
self.fileURL = URL(fileURLWithPath: tempPath)
self.assetWriter = try! AVAssetWriter(url: self.fileURL,fileType: AVFileType.mp4)
self.videoSettings = videoSettings
self.writeInput = AVAssetWriterInput(mediaType: AVMediaType.video,outputSettings: videoSettings)
assert(self.assetWriter.canAdd(self.writeInput),"add failed")
self.assetWriter.add(self.writeInput)
let bufferAttributes:[String: Any] = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32ARGB)]
self.bufferAdapter = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: self.writeInput,sourcePixelBufferAttributes: bufferAttributes)
self.frameTime = CMTimeMake(value: 1,timescale: 10)
}
func createMovieFrom(urls: [URL],withCompletion: @escaping CXEMovieMakerCompletion){
self.createMovieFromSource(images: urls as [AnyObject],extractor:{(inputObject:AnyObject) ->UIImage? in
return UIImage(data: try! Data(contentsOf: inputObject as! URL))},withCompletion: withCompletion)
}
func createMovieFrom(images: [UIImage],withCompletion: @escaping CXEMovieMakerCompletion){
DispatchQueue.main.async {
self.createMovieFromSource(images: images,extractor: {(inputObject:AnyObject) -> UIImage? in
return inputObject as? UIImage},withCompletion: withCompletion)
}
}
func imageFromLayer(layer:CALayer) -> UIImage {
UIGraphicsBeginImageContextWithOptions(layer.frame.size,layer.isOpaque,0)
layer.render(in: UIGraphicsGetCurrentContext()!)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage!
}
func createMovieFromSource(images: [AnyObject],extractor: @escaping CXEMovieMakerUIImageExtractor,withCompletion: @escaping CXEMovieMakerCompletion){
self.completionBlock = withCompletion
self.assetWriter.startWriting()
self.assetWriter.startSession(atSourceTime: CMTime.zero)
let mediaInputQueue = DispatchQueue.init(label: "Main") // DispatchQueue(label: "mediaInputQueue")
var i = 0
let frameNumber = images.count
self.writeInput.requestMediaDataWhenReady(on: mediaInputQueue){
while(true){
if(i >= frameNumber){
break
}
if (self.writeInput.isReadyForMoreMediaData){
var sampleBuffer:CVPixelBuffer?
autoreleasepool{
let temp = images[i]
let img = extractor(temp)
if img == nil{
i += 1
print("Warning: counld not extract one of the frames")
//continue
}
sampleBuffer = self.newPixelBufferFrom(cgImage: temp.cgImage!)
}
if (sampleBuffer != nil){
if(i == 0){
self.bufferAdapter.append(sampleBuffer!,withPresentationTime: CMTime.zero)
}else{
let value = i - 1
let lastTime = CMTimeMake(value: Int64(value),timescale: self.frameTime.timescale)
let presentTime = CMTimeAdd(lastTime,self.frameTime)
self.bufferAdapter.append(sampleBuffer!,withPresentationTime: presentTime)
}
i = i + 1
}
}
}
self.writeInput.markAsFinished()
self.assetWriter.finishWriting {
DispatchQueue.main.sync {
self.completionBlock!(self.fileURL)
}
}
}
}
func newPixelBufferFrom(cgImage:CGImage) -> CVPixelBuffer?{
autoreleasepool {
let options:[String: Any] = [kCVPixelBufferCGImageCompatibilityKey as String: true,bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
// CGImageAlphaInfo.noneSkipFirst.rawValue
assert(context != nil,"context is nil")
// context?.clear(CGRect(x: 0,height: frameHeight))
context!.concatenate(CGAffineTransform.identity)
context!.draw(cgImage,CVPixelBufferLockFlags(rawValue: 0))
return pxbuffer
}
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)