Почему у iPhone XS ухудшается производительность процессора при использовании камеры в прямом эфире, чем у iPhone 6S Plus? - PullRequest
0 голосов
/ 30 января 2019

Я использую вывод с камеры в реальном времени для обновления CIImage на MTKView.Моя главная проблема заключается в том, что у меня большая отрицательная разница в производительности, когда у старого iPhone производительность процессора выше, чем у нового, несмотря на то, что все их настройки, с которыми я сталкивался, одинаковы.

Это длинное сообщение, но я решил включить эти детали, поскольку они могут быть важны для причины этой проблемы.Пожалуйста, дайте мне знать, что еще я могу включить.

Ниже у меня есть функция captureOutput с двумя отладочными булами, которые я могу включать и выключать во время работы.Я использовал это, чтобы попытаться определить причину моей проблемы.

applyLiveFilter - bool, манипулировать CIImage с помощью CIFilter или нет.

updateMetalView - bool, обновлять или нет CIImage MTKView.

// 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
        }
    }

}

Ниже приведена таблица результатов для обоих телефонов, переключающих различные комбинации bools, обсужденных выше:

bool chart results for both iPhones

Даже без обновления CIIMage в Metal view и без применения фильтров процессор iPhone XS на 2% больше, чем у iPhone 6S Plus, что не является существенной нагрузкой, но заставляет меня подозревать, чтокаким-то образом способы захвата камеры различаются между устройствами.

  • Предустановка моего AVCaptureSession установлена ​​одинаково для обоих телефонов (AVCaptureSession.Preset.hd1280x720)

  • CIImage, созданный из captureOutput, имеет одинаковый размер (экстент) для обоих телефонов.

Есть ли какие-либо настройки, которые мне нужно установить вручную?Есть ли между этими двумя телефонами настройки 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 основан на коде, написанном Саймоном Гладманом, с некоторыми правками для повышения производительности и масштабирования рендера до его масштабирования доширина экрана с использованием Core Animation, предложенной Apple.

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 Ответ

0 голосов
/ 13 февраля 2019

На мой взгляд, вы не сравниваете груши с грушами, даже если вы работаете с 2,49 ГГц A12 против 1,85 ГГц A9, различия между камерами также огромны, даже если вы используете их сПо тем же параметрам есть несколько функций камеры XS, которые требуют больше ресурсов ЦП (двойная камера, стабилизация, умный HDR и т. д.).

Извините за источники, я попытался найти показатели стоимости ЦП этих функцийНо я не смог найти, к сожалению, для ваших нужд, что информация не имеет отношения к маркетингу, когда они продают ее как лучшую камеру для смартфона.

Они также продают его как лучший процессор, мы не знаем, что случится с камерой XS с процессором A9, она, вероятно, вылетит, мы никогда не узнаем ...

PS .... Ваши показатели для всего процессора или для используемого ядра?Для всего процессора также необходимо учитывать другие задачи, которые могут выполнять устройства, для одного ядра - 21% от 200% против 39% от 600%

...