为什么使用相机实时拍摄时,iPhone XS 的CPU性能比 iPhone 6S Plus 更差?

8
我正在使用实时摄像头输出来更新MTKView上的CIImage。我的主要问题是,尽管我遇到的所有设置都相同,但旧版iPhone比新版iPhone具有更好的CPU性能,出现了明显的性能差异。
这是一个冗长的帖子,但我决定包括这些细节,因为它们可能对这个问题的原因很重要。请让我知道我还可以添加什么。
下面是我的captureOutput函数,其中包含两个debug bools,我可以在运行时打开和关闭它们。我使用这个函数来试图确定我的问题的原因。
applyLiveFilter-bool是否使用CIFilter操作CIImage。 updateMetalView-bool是否更新MTKView的CIImage。
// live output from camera
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection){

    /*              
     Create CIImage from camera.
     Here I save a few percent of CPU by using a function 
     to convert a sampleBuffer to a Metal texture, but
     whether I use this or the commented out code 
     (without captureOutputMTLOptions) does not have 
     significant impact. 
    */

    guard let texture:MTLTexture = convertToMTLTexture(sampleBuffer: sampleBuffer) else{
        return
    }

    var cameraImage:CIImage = CIImage(mtlTexture: texture, options: captureOutputMTLOptions)!

    var transform: CGAffineTransform = .identity

    transform = transform.scaledBy(x: 1, y: -1)

    transform = transform.translatedBy(x: 0, y: -cameraImage.extent.height)

    cameraImage = cameraImage.transformed(by: transform)

    /*
    // old non-Metal way of getting the ciimage from the cvPixelBuffer
    guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else
    {
        return
    }

    var cameraImage:CIImage = CIImage(cvPixelBuffer: pixelBuffer)
    */

    var orientation = UIImage.Orientation.right

    if(isFrontCamera){
        orientation = UIImage.Orientation.leftMirrored
    }

    // apply filter to camera image
    if debug_applyLiveFilter {
        cameraImage = self.applyFilterAndReturnImage(ciImage: cameraImage, orientation: orientation, currentCameraRes:currentCameraRes!)
    }

    DispatchQueue.main.async(){
        if debug_updateMetalView {
            self.MTLCaptureView!.image = cameraImage
        }
    }

}

以下是两部手机在不同的布尔值组合下的结果图表: bool chart results for both iPhones 即使没有使用Metal视图的CIIMage更新和未应用任何过滤器,iPhone XS的CPU比iPhone 6S Plus高2%,这并不是一个显著的开销,但这让我怀疑相机在捕捉图像时在设备之间存在某些差异。
我的AVCaptureSession预设在两部手机之间设置为相同 (AVCaptureSession.Preset.hd1280x720)。 从captureOutput创建的CIImage在两部手机之间大小(范围)相同。
是否有任何设置需要在这两个手机的AVCaptureDevice设置中手动设置,包括activeFormat属性,以使它们在设备之间相同?
我现在拥有的设置是:
if let captureDevice = AVCaptureDevice.default(for:AVMediaType.video) {
    do {
        try captureDevice.lockForConfiguration()
            captureDevice.isSubjectAreaChangeMonitoringEnabled = true
            captureDevice.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
            captureDevice.exposureMode = AVCaptureDevice.ExposureMode.continuousAutoExposure
        captureDevice.unlockForConfiguration()

    } catch {
        // Handle errors here
        print("There was an error focusing the device's camera")
    }
}

我的MTKView基于Simon Gladman编写的代码,为了提高性能并在使用苹果建议的核心动画将渲染缩放到屏幕宽度之前进行缩放而进行了一些编辑。

class MetalImageView: MTKView
{
    let colorSpace = CGColorSpaceCreateDeviceRGB()

    var textureCache: CVMetalTextureCache?

    var sourceTexture: MTLTexture!

    lazy var commandQueue: MTLCommandQueue =
        {
            [unowned self] in

            return self.device!.makeCommandQueue()
            }()!

    lazy var ciContext: CIContext =
        {
            [unowned self] in

            return CIContext(mtlDevice: self.device!)
            }()


    override init(frame frameRect: CGRect, device: MTLDevice?)
    {
        super.init(frame: frameRect,
                   device: device ?? MTLCreateSystemDefaultDevice())



        if super.device == nil
        {
            fatalError("Device doesn't support Metal")
        }

        CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, self.device!, nil, &textureCache)

        framebufferOnly = false

        enableSetNeedsDisplay = true

        isPaused = true

        preferredFramesPerSecond = 30
    }

    required init(coder: NSCoder)
    {
        fatalError("init(coder:) has not been implemented")
    }

    // The image to display
    var image: CIImage?
    {
        didSet
        {
            setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect)
    {
        guard var
            image = image,
            let targetTexture:MTLTexture = currentDrawable?.texture else
        {
            return
        }

        let commandBuffer = commandQueue.makeCommandBuffer()

        let customDrawableSize:CGSize = drawableSize

        let bounds = CGRect(origin: CGPoint.zero, size: customDrawableSize)

        let originX = image.extent.origin.x
        let originY = image.extent.origin.y

        let scaleX = customDrawableSize.width / image.extent.width
        let scaleY = customDrawableSize.height / image.extent.height

        let scale = min(scaleX*IVScaleFactor, scaleY*IVScaleFactor)
        image = image
            .transformed(by: CGAffineTransform(translationX: -originX, y: -originY))
            .transformed(by: CGAffineTransform(scaleX: scale, y: scale))


        ciContext.render(image,
                         to: targetTexture,
                         commandBuffer: commandBuffer,
                         bounds: bounds,
                         colorSpace: colorSpace)


        commandBuffer?.present(currentDrawable!)

        commandBuffer?.commit()

    }

}

下面是我的AVCaptureSession(captureSession)和AVCaptureVideoDataOutput(videoOutput)设置:

func setupCameraAndMic(){
    let backCamera = AVCaptureDevice.default(for:AVMediaType.video)

    var error: NSError?
    var videoInput: AVCaptureDeviceInput!
    do {
        videoInput = try AVCaptureDeviceInput(device: backCamera!)
    } catch let error1 as NSError {
        error = error1
        videoInput = nil
        print(error!.localizedDescription)
    }

    if error == nil &&
        captureSession!.canAddInput(videoInput) {

        guard CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, MetalDevice, nil, &textureCache) == kCVReturnSuccess else {
            print("Error: could not create a texture cache")
            return
        }

        captureSession!.addInput(videoInput)            

        setDeviceFrameRateForCurrentFilter(device:backCamera)

        stillImageOutput = AVCapturePhotoOutput()

        if captureSession!.canAddOutput(stillImageOutput!) {
            captureSession!.addOutput(stillImageOutput!)

            let q = DispatchQueue(label: "sample buffer delegate", qos: .default)
            videoOutput.setSampleBufferDelegate(self, queue: q)
            videoOutput.videoSettings = [
                kCVPixelBufferPixelFormatTypeKey as AnyHashable as! String: NSNumber(value: kCVPixelFormatType_32BGRA),
                kCVPixelBufferMetalCompatibilityKey as String: true
            ]
            videoOutput.alwaysDiscardsLateVideoFrames = true

            if captureSession!.canAddOutput(videoOutput){
                captureSession!.addOutput(videoOutput)
            }

            captureSession!.startRunning()

        }

    }

    setDefaultFocusAndExposure()
}

视频和麦克风分别记录在两个不同的流中。由于我专注于直播摄像头输出的性能,因此麦克风和录制视频的详细信息被省略了。
更新 - 我在GitHub上有一个简化的测试项目,可以更轻松地测试我遇到的问题:https://github.com/PunchyBass/Live-Filter-test-project
1个回答

1
从我记忆中来看,即使您使用A12的2.49 GHz与A9的1.85 GHz进行比较,摄像头之间的差异也很大,即使您将它们与相同的参数一起使用,XS相机中有几个功能需要更多的CPU资源(双摄像头、稳定性、智能HDR等)。抱歉,我试图找到这些功能的CPU成本指标,但我找不到,很遗憾,对于您的需求来说,那些信息并不重要,因为他们正在将其作为智能手机上最好的相机出售。
他们也将其作为最好的处理器出售,我们不知道使用A9处理器的XS相机会发生什么情况,它可能会崩溃,我们永远不会知道...
PS... 您的度量标准是针对整个处理器还是已用核心?对于整个处理器,您还需要考虑设备可能执行的其他任务,对于单个核心,它是200%的21%对600%的39%。

它正在高度利用XS上的所有核心。我将链接一个简化的示例项目供任何人测试。对我来说,没有理由让iPhone XS的相机设置可以近似于旧手机上的设置,并且能够同时更轻松地处理这些信息。 - Chewie The Chorkie
我刚刚发现在iPhone XS上,MTKView的drawableSize在视图大小改变时从未改变,但在其他手机上却可以正常工作。我认为这是性能问题的重要原因。我刚刚在苹果的开发者论坛上发布了这个问题。希望有工作人员能回复我并确认这是一个bug。 - Chewie The Chorkie
我也禁用了HDR,但没有性能变化。我还认为可能是深度数据的问题,但如果是这种情况,我不知道如何禁用捕获深度数据。 - Chewie The Chorkie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接