J'enregistre une vidéo filtrée via une caméra iPhone, et l'utilisation du processeur augmente considérablement lors de la conversion d'une CIImage en UIImage en temps réel pendant l'enregistrement. Ma fonction de tampon pour créer un CVPixelBuffer utilise une UIImage, qui jusqu'à présent m'oblige à effectuer cette conversion. Je voudrais plutôt créer une fonction de tampon qui prend une CIImage si possible afin que je puisse ignorer la conversion d'UIImage en CIImage. Je pense que cela me donnera un énorme coup de pouce en termes de performances lors de l'enregistrement vidéo, car il n'y aura pas de transfert entre le CPU et le GPU.
C'est ce que j'ai en ce moment. Dans ma fonction captureOutput, je crée une UIImage à partir de CIImage, qui est l'image filtrée. Je crée un CVPixelBuffer à partir de la fonction buffer à l'aide de UIImage, et je l'ajoute au pixelBufferInput de assetWriter:
func buffer(from image: UIImage) -> CVPixelBuffer? { let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary var pixelBuffer : CVPixelBuffer? let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(image.size.width), Int(image.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer) guard (status == kCVReturnSuccess) else { return nil } CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!) let videoRecContext = CGContext(data: pixelData, width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: 8, bytesPerRow: videoRecBytesPerRow, space: (MTLCaptureView?.colorSpace)!, // It's getting the current colorspace from a MTKView bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) videoRecContext?.translateBy(x: 0, y: image.size.height) videoRecContext?.scaleBy(x: 1.0, y: -1.0) UIGraphicsPushContext(videoRecContext!) image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)) UIGraphicsPopContext() CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) return pixelBuffer }
Ma fonction buffer qui utilise une UIImage:
let imageUI = UIImage(ciImage: ciImage) let filteredBuffer:CVPixelBuffer? = buffer(from: imageUI) let success = self.assetWriterPixelBufferInput?.append(filteredBuffer!, withPresentationTime: self.currentSampleTime!)
3 Réponses :
Créez un CIContext
et utilisez-le pour afficher la CIImage
directement sur votre CVPixelBuffer
en utilisant CIContext.render (_: CIImage, pour tamponner: CVPixelBuffer)
.
Je ne sais pas exactement comment initialiser le CVPixelBuffer, mais un copier-coller de la fonction de tampon que j'avais auparavant, en remplaçant le paramètre UIImage par CIImage, en échangeant la taille avec l'extension et en supprimant le code UIIGraphicsContext a fait l'affaire. Je vais voir ce que je peux supprimer d'autre là-dedans, ou peut-être pourriez-vous le montrer dans votre réponse. J'ai déjà essayé d'utiliser CIIContext.render, sans trop de chance pour écrire l'appel de fonction ou créer un CVPixelBuffer.
Il a été réduit en supprimant tout jusqu'à l'instruction guard (status == kCVReturnSuccess) et a renvoyé pixelBuffer. J'obtiens une amélioration assez significative sur le processeur. Merci beaucoup.
Est-ce considéré comme une méthode rapide?
Notez que la fonction buffer passe une ciImage. J'ai formaté ma fonction de tampon pour passer la CIImage, et j'ai pu me débarrasser d'une grande partie de ce qui se trouvait à l'intérieur:
func buffer(from image: CIImage) -> CVPixelBuffer? { let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary var pixelBuffer : CVPixelBuffer? let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(image.extent.width), Int(image.extent.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer) guard (status == kCVReturnSuccess) else { return nil } return pixelBuffer }
rob mayoff résume la situation, mais il y a une chose TRÈS TRÈS TRÈS importante à garder à l'esprit:
Core Image reporte le rendu jusqu'à ce que le client demande l'accès au frame buffer, c'est-à-dire
CVPixelBufferLockBaseAddress
.
J'ai appris cela en parlant avec l'ingénieur du support technique d'Apple et je n'ai trouvé cela dans aucun des documents. Je l'ai utilisé uniquement avec macOS, mais imaginez que ce ne serait pas différent sur iOS.
Gardez à l'esprit que si vous verrouillez la mémoire tampon avant le rendu, il fonctionnera toujours mais exécutera une image derrière et le premier rendu sera vide.
Enfin, il est mentionné plus d'une fois sur SO et même dans ce fil: évitez de créer un nouveau CVPixelBuffer
pour chaque rendu car chaque tampon prend une tonne de ressources système. C'est pourquoi nous avons CVPixelBufferPool
- Apple l'utilise dans leurs frameworks, alors pouvez-vous faire encore mieux performance! ✌️
Hé Ian! Pouvez-vous montrer un exemple d'utilisation de CVPixelBufferPool s'il vous plaît?