1

我需要選擇性地(和可靠地)關閉captureOutput:didOutputSampleBuffer:fromConnection:方法中的sampleBuffers處理。正如你所知道的,它是從GCD隊列中調用的,而不是在主線程中調用的......但是我從UIButton中獲取用戶輸入(當然是在主線程中),並通過設置BOOL標誌來告訴我的相機對象停止所有處理。iOS:有選擇地禁用處理captureOutput:didOutputSampleBuffer:fromConnection:來自AVFoundation中的主線程

但是,有時我會在處理被認爲停止之後看到1個額外的框架滑落。有沒有什麼方法可以絕對確保在按下按鈕後不會處理任何內容?現在我做一個簡單的測試:

// in ViewController: 
- (IBAction)tappedStop:(id)sender { 
    NSLog("stop processing!"); 
    _camera.capturing = NO; 
} 

// in my camera obj: 
- (void)captureOutput:(AVCaptureOutput *)captureOutput did... { 
    if (!capturing) { 
     return; 
    } 
    NSLog(@"processing!"); 
} 

我使用@synchronized,靜態BOOL嘗試,並使用信號量,但是沒有用......有時額外的框架還在偷偷的任何人。有和想法?可能有一些GCD方法可以做我想做的,但我不知道如何去做。

這裏是如何的結果(有時)在我的調試控制檯看(縮短,使其更具可讀性):

2012-09-29 23:29:01.869 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:01.910 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:01.953 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:01.994 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.047 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.078 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.121 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.166 -[ViewController tappedButton:] [Line 913] stop processing! 
2012-09-29 23:29:02.161 __33-_block_invoke_0 [Line 322] processing! 
... 

但通常(約4出5次)我的控制檯看起來像:

2012-09-29 23:29:01.869 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:01.910 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:01.953 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:01.994 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.047 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.078 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.121 __33-_block_invoke_0 [Line 322] processing! 
2012-09-29 23:29:02.166 -[ViewController tappedButton:] [Line 913] stop processing! 

我也許應該提一下,我沒有訪問原始隊列的captureOutput:didOutput...,因爲它位於我無法控制的框架的超類中。

+0

除了那個日誌你還有什麼測量?因爲它是在您設置標誌之前放置的。也許這只是一個錯字,但不管你做了多少同步測量技術,有時還會顯示你正在生成的日誌。另外,當這個標誌被設置時,你的要求是處理保釋的一部分嗎? –

+0

嘿,是否可以刪除「gcd」標籤,因爲我們已經有了「大中央調度」,並添加了「比賽條件」? –

+0

我唯一使用的測量是顯示/隱藏視圖以查看幀是否實際上仍在輸出。我知道這是一種誤導,因爲調試輸出中「額外幀」的時間戳發生在我的「停止處理」行('2012-09-29 23:29:02.161')之前。回覆:標籤,當然如果你認爲這有助於更多,那就去吧。 – taber

回答

1

我不知道爲什麼我沒有早點想到這一點,但是如果我在與主線程的異步調用中包裝我的整個captureOutput:didOutput ...方法,即使它看起來有點不理想,請關閉sampleBuffer處理按預期工作。我想這是有道理的;我的觸摸事件總是來自主線程,由於我沒有處理在哪個線程被用在我的緩衝區輸出隊列中,唯一可以檢查的方法是(可以看到)isRecording是從main線程也是。

- (void)captureOutput:(AVCaptureOutput *)captureOutput did... { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     if (!isRecording) { 
      return; 
     } 

     NSLog(@"processing!"); 

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 
      // do actual processing 
     }); 
    }); 
} 

如果任何人有任何其他建議,但我很樂意聽到他們。謝謝!

+0

這是我最後的結果,但非常感謝這些建議,我很感激。 – taber

0

我會做這個

// in ViewController: 
- (IBAction)tappedStop:(id)sender { 
    NSLog("stop processing!"); 
    dispatch_async(capture_dispatch_queue, ^{_camera.capturing = NO;}); 
} 

這將導致該塊被插入到串行調度隊列。它將在任何更多的圖像處理塊得到處理之前執行。就像現在你在_camera.capturing變量上有一個競爭條件。這將通過相對於捕獲回調串行地執行該變量來解決競態條件。

編輯:

也許我應該還提到,我沒有訪問到的呼喚captureOutput的 原來隊列:didOutput ......因爲它是在 框架的超我能」控制。

我錯過了那部分。這很難。您在技術上可以通過Objective-C運行時訪問它。但是,如果那個iVar改變了名字,你的代碼就會崩潰。也許在你的情況下,你設計的解決方案是最好的。不過我會考慮的。很好的問題。

0

您可以使用本地到您的相機類的串行調度隊列作爲一種互斥體。其基本思想是,所有需要同步的工作都將被分派到該隊列中 - 捕獲變量的設置(可能取得)以及回調中完成的工作。這要求我將所有的同步工作都移到相機本身。我將日誌保存爲同步工作的一部分,以便您可以準確地檢測代碼是否按順序執行。它似乎工作正常,每秒運行60次以模擬60 fps的視頻捕捉。

Camera.h:

@interface Camera : NSObject 

@property (nonatomic,getter = isCapturing) BOOL capturing; 

@end 

Camera.m

#define CALLBACK_INTERVAL (1.0/60.0) 

@implementation Camera { 
    dispatch_queue_t _sync_queue; 
    BOOL _capturing; 
} 

- (id)init 
{ 
    if (self = [super init]) 
    { 
     _capturing = YES; 
     _sync_queue = dispatch_queue_create("com.mycompany.whatever", NULL); 
     [self performSelector:@selector(triggerCallback) withObject:nil afterDelay:CALLBACK_INTERVAL]; 
    } 

    return self; 
} 


- (void)setCapturing:(BOOL)capturing 
{ 
    dispatch_async(_sync_queue, ^{ 
     _capturing = capturing; 
     if (!_capturing) 
      NSLog(@"STOP"); 
    }); 
} 

- (void)repeatingCallback 
{ 
    dispatch_async(_sync_queue, ^{ 
     if (!_capturing) 
      return; 
     NSLog(@"WORKING"); 
    }); 
} 

- (void)triggerCallback 
{ 
    [NSObject cancelPreviousPerformRequestsWithTarget:self]; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [self repeatingCallback]; 
    }); 
    [self performSelector:@selector(triggerCallback) withObject:nil afterDelay:CALLBACK_INTERVAL]; 
} 

@end 

並在視圖控制器:

- (IBAction)stopCapturing:(id)sender 
{ 
    self.camera.capturing = NO; 
} 

希望這有助於讓我知道,如果你有任何問題。需要考慮的一件事情是,與回調的頻率相比,處理工作需要多長時間。如果花費相當長的時間在隊列上建立大量工作,那麼_capturing敲擊後可能需要一些時間才能進行更改,這聽起來可能是不可接受的,但仍然應該停止當時不在隊列中的任何處理它被挖掘。

相關問題