1

카메라의 프레임을 캡처하고 다른 스레드가 업데이트 한 이미지를 혼합하는 앱을 개발 중입니다. 내 문제는 매 500ms마다 호출되는 이미지 작성 스레드가 다른 스레드에 영향을 미치는 피크 컴퓨팅 성능을 소모한다는 것입니다. 여기GCD 설정 예약/스레드 간의 우선 순위

설명에 대한 일부 로그 :

captureOutput(): used time: 0.027741014957428 , frame rate: 36.0477077545513 
captureOutput(): used time: 0.0285720229148865 , frame rate: 34.9992719444091 
captureOutput(): used time: 0.0310209989547729 , frame rate: 32.2362281581567 
captureOutput(): used time: 0.0268059968948364 , frame rate: 37.3050852733863 
captureOutput(): used time: 0.0263729691505432 , frame rate: 37.9176115624965 
motionCallback(): starting drawing: 
captureOutput(): used time: 0.0376390218734741 , frame rate: 26.5681718127947 
motionCallback(): elapesed time: 0.0835540294647217 
captureOutput(): used time: 0.0581380128860474 , frame rate: 17.2004502795793 
captureOutput(): used time: 0.0364410281181335 , frame rate: 27.4415967836645 
captureOutput(): used time: 0.0278580188751221 , frame rate: 35.8963070734734 
captureOutput(): used time: 0.0283130407333374 , frame rate: 35.3194137435949 
captureOutput(): used time: 0.0271909832954407 , frame rate: 36.7768972947616 
captureOutput(): used time: 0.0268760323524475 , frame rate: 37.2078730552999 

당신이 captureOutput은 30 fps의 프레임 속도를 가지고 볼 수 있듯이. motionCallback이 이미지를 생성하자마자 프레임 속도가 떨어지고 다시 올라갑니다. motionCallback()은 매 15 번째 캡처 프레임마다 호출되므로 평균 컴퓨팅 성능이 충분해야합니다.

captureOutput()이 같이 생성 된 큐에서 실행되고 :

required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    self.m_captureSessionQueue = DispatchQueue(label: "CaptureSessionOutputQueue", attributes: DispatchQueueAttributes.serial) 
} 

나중에 나는 설정 AVCapture에서이 같은 :

videoDataOutput.setSampleBufferDelegate(self, queue: self.m_captureSessionQueue) 

motionCallback()는 다음과 같이 설정 :

let interval = 0.4 
if m_manager.isDeviceMotionAvailable { 
    m_manager.showsDeviceMovementDisplay = true 
    m_manager.deviceMotionUpdateInterval = interval 
    // XArbitraryCorrectedZVertical 
    m_manager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xArbitraryCorrectedZVertical , to: OperationQueue.main, withHandler: motionCallback) 
    print("viewDidLoad(): CM initialized !") 
} 

이상 :

이 같은
func motionCallback(_ motion: CMDeviceMotion?, error: NSError?) -> Void { 
    guard let mot = motion else {return} 
    print("motionCallback(): starting drawing: ") 

    let start = NSDate() // <<<<<<<<<< Start time 
    self.m_instrview?.update(attitude: mot.attitude) 
    self.m_overlayImage = CIImage(image: self.m_instrview!.generateImage()!) 

    let end = NSDate() // <<<<<<<<<< end time 
    let timeInterval: Double = end.timeIntervalSince(start as Date) 
    print("motionCallback(): elapesed time: ", timeInterval) 
} 

및 generateImage() :

func generateImage() -> UIImage { 
    UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main().scale) 
    drawHierarchy(in: self.bounds, afterScreenUpdates: true) 
    let image = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
    return image! 
} 

아이디어는 CoreMotion 시스템은 내게 새로운 이미지를 생성합니다 업데이 트를 얻을 때마다 만드는 것입니다.

제 질문은 어떻게 프레임 속도가 떨어지는 피크 CPU 전력을 소모하지 않도록 motionCallback()의 ​​계산 시간을 평균 할 수 있습니까? 그래서 나는 그것을 10 배 더 길게 실행하지만 그 시간 동안 CPU의 1/10만을 소모한다고 받아 들일 것입니다.

어떻게 통제 할 수 있었는지 아이디어가 있으십니까?

감사 크리스

+0

모션 콜백은 메인 큐에 있으며, 이는 CPU 집약적 인 함수 인'generateImage' 호출을 포함합니다.이것을 백그라운드 대기열로 보내면 기본 대기열에서 UI 업데이트를 수행해야합니다. – Paulw11

+0

예, 정확하게 문제입니다. CPU 집약 기능은 반드시 메인 스레드에서 호출되어야합니다. 따라서 motionCallBack의 우선 순위를 낮출 수 없다면 캡쳐 스레드의 우선 순위를 정해야합니다. 어떻게해야합니까? – Chris

+0

메인 스레드에서 CPU 집중 기능을 호출해야하는 이유는 무엇입니까? generateImage는 CPU 집중이지만 백그라운드 스레드에서 실행할 수 있습니다. 완료되면 주 스레드에 CIImage 할당을 전달하십시오. 코어 모션 이벤트 처리를 위해 우선 순위가 낮은 스레드 사용 – Paulw11

답변

1

은 프레임 캡처를 수행하는 것보다 낮은 우선 순위로 비동기 큐 (사용 dispatch_queue_create)를 만듭니다. 이 우선 순위가 낮은 대기열에서 motionCallback을 실행하십시오.

메인 스레드에서 작업을 실행하는 메인 대기열에서 motionCapture 메소드를 실행했습니다. 그러지 마.

이 줄은 잘못된 것입니다 :

m_manager.startDeviceMotionUpdates(
    using: CMAttitudeReferenceFrame.xArbitraryCorrectedZVertical , 
    to: OperationQueue.main, 
    withHandler: motionCallback) 

변경에 : 매개 변수입니다.

작성한 CaptureSessionOutputQueue보다 낮은 우선 순위로 실행되는 새 직렬 대기열을 작성하고 위의 to : 매개 변수에 전달해야합니다.

스위프트 3을 배우기 시작 했으므로 아직 디스패치 대기열을 생성하는 새로운 코드 구문은 없습니다.

+0

내가 수행 한 코드는 해당 코드를 넣는 것입니다 DispatchQueue.global (특성 : .qosBackground) .async {...}, 그러나 이것은 GUI의 동결에 이릅니다. drawHierarchy를 주 스레드에서 호출해야 할 수 있습니까? – Chris

+2

질문을 편집하여 대기열 설정의 세부 정보와 두 대기열이 실행중인 코드의 관련 부분을 포함하십시오. –

+0

이에 따라 업데이트되는 질문 – Chris