MTKView以低于AVCaptureVideoPreviewLayer的分辨率显示摄像头提要 [英] MTKView displaying camera feed with lower resolution than AVCaptureVideoPreviewLayer

查看:108
本文介绍了MTKView以低于AVCaptureVideoPreviewLayer的分辨率显示摄像头提要的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将相机供稿流式传输到MTKView中,以将某些CI过滤器应用于实时流.初始化捕获会话并布局MTKView之后,以下是我设置金属(metalView是MTKview)的方法:

I'm trying to stream the camera feed into a MTKView for applying some CI filter to the live stream. After initializing the capture session and having layout the MTKView, here is how I set metal (metalView is the MTKview):

func setupMetal(){
    
    metalDevice = MTLCreateSystemDefaultDevice()
    metalView.device = metalDevice
    // Write when asked
    metalView.isPaused = true
    metalView.enableSetNeedsDisplay = false
    // Command queue for the GPU
    metalCommandQueue = metalDevice.makeCommandQueue()
    // Assign the delegate
    metalView.delegate = self
    // ???
    metalView.framebufferOnly = false
}

然后我从SampleBufferDelegate抓取帧并获得CIImage

I then grab frames from the SampleBufferDelegate and get a CIImage

extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate {

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    //try and get a CVImageBuffer out of the sample buffer
    guard let cvBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
        return
    }
    
    //get a CIImage out of the CVImageBuffer
    let ciImage = CIImage(cvImageBuffer: cvBuffer)
    
    self.currentCIImage = ciImage
    
    // We draw to the metal view everytime we receive a frame
    metalView.draw()
            
}}

然后我使用currentCIImage通过其委托方法绘制MTKView:

I then use the currentCIImage to draw in the MTKView using its delegate methods:

extension ViewController : MTKViewDelegate {

func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
    //tells us the drawable's size has changed
}

func draw(in view: MTKView) {
    //create command buffer for ciContext to use to encode it's rendering instructions to the GPU
    guard let commandBuffer = metalCommandQueue.makeCommandBuffer() else {
        return
    }
    
    //make sure we actually have a ciImage to work with
    guard let ciImage = currentCIImage else {
        return
    }
    
    //make sure the current drawable object for this metal view is available (it's not in use by the previous draw cycle)
    guard let currentDrawable = view.currentDrawable else {
        return
    }
    
    //render into the metal texture
    // Check here if we find a more elegant solution for the bounds
    self.ciContext.render(ciImage,
                          to: currentDrawable.texture,
                          commandBuffer: commandBuffer,
                          bounds: CGRect(origin: .zero, size: view.drawableSize),
                          colorSpace: CGColorSpaceCreateDeviceRGB())
    
    //register where to draw the instructions in the command buffer once it executes
    commandBuffer.present(currentDrawable)
    //commit the command to the queue so it executes
    commandBuffer.commit()
}
}

它工作正常,我能够从MTKView中渲染的相机获取帧.但是,我注意到我没有获得完整的分辨率,因此无法在MTKview中缩放图像.我知道这与我如何设置捕获会话无关,因为当我使用标准AVCapturePreviewLayer时,一切都很好.关于我在做什么错的任何想法吗?

It works fine and I'm able to get frames from the camera rendered in the MTKView. However, I noticed that I'm not getting the full resolution, somehow the image is zoomed in the MTKview. I know it is not an issue related to how I set the capture session because when I use the standard AVCapturePreviewLayer it is all fine. Any ideas on what I'm doing wrong?

非常感谢!

PS该代码主要基于该出色的教程: https://betterprogramming.pub/using-cifilters-metal-to-make-a-custom-camera-in-ios-c76134993316 ,但对于我来说似乎不起作用

P.S This code is mainly based on this excellent tutorial: https://betterprogramming.pub/using-cifilters-metal-to-make-a-custom-camera-in-ios-c76134993316 but somehow it doesn't seem to work for me.

推荐答案

根据捕获会话的设置,摄像机帧的大小将与您的 MTKView 的大小不同.这意味着您需要缩放和转换它们,然后再渲染以匹配 currentDrawable 的大小.为此,我使用以下代码(在 render 调用之前的 draw 内部):

Depending on the setup of the capture session, the camera frames will not have the same size as your MTKView. That means you need to scale and translate them before rendering to match the size of the currentDrawable. I use the following code for that (inside draw, just before the render call):

    // scale to fit into view
    let drawableSize = self.drawableSize
    let scaleX = drawableSize.width / input.extent.width
    let scaleY = drawableSize.height / input.extent.height
    let scale = min(scaleX, scaleY)
    let scaledImage = input.transformed(by: CGAffineTransform(scaleX: scale, y: scale))

    // center in the view
    let originX = max(drawableSize.width - scaledImage.extent.size.width, 0) / 2
    let originY = max(drawableSize.height - scaledImage.extent.size.height, 0) / 2
    let centeredImage = scaledImage.transformed(by: CGAffineTransform(translationX: originX, y: originY))

这篇关于MTKView以低于AVCaptureVideoPreviewLayer的分辨率显示摄像头提要的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆