AVCaptureSession部分用法


原文鏈接

AVCaptureSession阻塞主線程問題

前陣子程序中出現了一個奇怪的 bug,在 iOS 系統上,頁面彈出的時候會卡很久,相機始終黑屏,大概6-7秒鍾,跟蹤具體每個步驟花費時間的時候發現在viewWillDisappear:中開銷最大,這其中只調用了一個相機關閉的代碼:

if ([[self.avCameraManager session] isRunning]) {
            [[self.avCameraManager session] stopRunning];
}

仔細看了文檔之后,發現問題出在stopRunning這里,

蘋果文檔描述如下:

Clients invoke -stopRunning to stop the flow of data from inputs to outputs connected to
the AVCaptureSession instance. This call blocks until the session object has completely
stopped.

重點是這個函數在 session 完全停止下來之前會始終阻塞線程, 同樣的,在startRunning中:

Clients invoke -startRunning to start the flow of data from inputs to outputs connected to
the AVCaptureSession instance. This call blocks until the session object has completely
started up or failed. A failure to start running is reported through the AVCaptureSessionRuntimeErrorNotification
mechanism.

因此這里必須放在后台線程中處理,否則,就會導致界面不響應,iOS8之后應該在這里做了優化,即使放在主線程做也沒有很卡頓的現象,但 iOS7中,尤其是測試設備為4s,界面卡死問題很嚴重。

開啟和關閉相機部分代碼改為:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        DDLogDebug(@"Function: %s,line : %d 開啟相機",__FUNCTION__,__LINE__);
        [[self.avCameraManager session] startRunning];
    });
    
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        DDLogDebug(@"Function: %s,line : %d 關閉相機",__FUNCTION__,__LINE__);
        if ([[self.avCameraManager session] isRunning]) {
            [[self.avCameraManager session] stopRunning];
        }
    });

這里除了使用系統提供的隊列以外還可以自己創建 FIFO 類型后台線程進行管理,包括切換前后攝像頭、改變閃光燈模式、切換拍照和錄像等,都可以放入子線程操作。

相機前后台切換問題

另一個問題與前后台切花相關,項目中在程序進入后台時有這么一段代碼:

[self performSelector:@selector(startRunningSession) withObject:nil afterDelay:0.5];

當時我很奇怪,這里為什么要加延時呢?進入到前台時不是應該直接開啟相機嗎?於是我直接把這里改成了:

[self startRunningSession];

沒過多久,問題出現了,多次切換前后台之后發現,相機始終黑屏,這時,進入后台再回來,問題解決了,仔細加了 log 之后發現,出現黑屏的時候,確實也正確調用了啟動 session,但是並沒有收到系統相機啟動成功的消息,反而收到了兩次相機關閉的通知。

那么之前代碼中加了0.5秒延時的原因也就清楚了,是為了等待系統關閉相機之后,再調用開啟相機,以免相機啟動失敗,但這種方式真的合理嗎?其實並沒有解決本質問題,如果0.5秒鍾的時間並沒有完全關閉系統相機呢?這里仍然會出現黑屏問題。

於是繼續查看系統文檔,發現系統的 sampleCode AVCam-iOS中並沒有專門用於前后台處理的邏輯,原來這里並不需要我們自己手動管理相機,系統會自動根據程序狀態來判斷是否需要關閉或者開啟相機,如果按 home 進入UIApplicationStateBackground 狀態,那么系統自動關閉相機並在進入UIApplicationStateActive狀態時開啟相機;如果是進入UIApplicationStateInactive狀態,例如,雙擊 home 調出任務管理器,這時,相機並沒有被關閉,仍然能夠看到 preview 畫面。

我們在程序切換前后台時,僅需要捕獲相繼開啟或者關閉的通知來刷新界面即可,否則可能會由於快速開啟切換前后台導致系統相機執行命令錯亂,無法正確啟動相機。

總結

  • AVCaptureSession 中絕大部分操作需要在后台線程完成,最好使用一個 FIFO 的隊列來進行操作
  • 前后台切換時,無需手動管理 CaptureSession


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM