4

當使用AVCaptureVideoDataOutput並使用調度隊列(setSampleBufferDelegate:queue)定義樣本緩衝區委託時,我們在iOS 8上經歷了AVFoundation不會發布樣本緩衝區在指定的調度隊列上,而是總是使用「com.apple.avfoundation.videodataoutput.bufferqueue」。iOS 8上的AVCaptureVideoDataOutput不會在指定的調度隊列上發佈樣本緩衝區

這可以在iOS7上按預期工作。

有沒有其他人經歷過這個?

一個明顯的解決方法是手動調用dispatch_sync回調同步處理到定製調度隊列,但這種奇怪的是,導致死鎖...

產生這個問題

示例代碼:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    AVCaptureSession *session = [[AVCaptureSession alloc] init]; 
    session.sessionPreset = AVCaptureSessionPresetMedium; 

    AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session]; 
    captureVideoPreviewLayer.frame = self.view.bounds; 
    [self.view.layer addSublayer:captureVideoPreviewLayer]; 

    [session addInput:[AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil]]; 

    AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init]; 

    queue = dispatch_queue_create("our.dispatch.queue", DISPATCH_QUEUE_SERIAL); 

    [output setSampleBufferDelegate:self queue:queue]; 

    [session addOutput:output]; 

    [session startRunning]; 
} 

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { 
    NSLog(@"Running on queue %@, queue that was set is %@, this is %s", dispatch_get_current_queue(), 
     [captureOutput performSelector:@selector(sampleBufferCallbackQueue)], 
     queue == dispatch_get_current_queue() ? "our queue" : "not our queue!!!"); 
} 

回答

6

這裏可能發生的事情是,他們的隊列com.apple.avfoundation.videodataoutput.bufferqueue已被設置爲使用dispatch_set_target_queue來定位您的隊列。這在功能上等同於調度到您的隊列,但會解釋名稱,並且還會在您嘗試返回隊列時解釋死鎖。

換句話說,只是因爲隊列名稱不等於隊列的名稱並不意味着該塊沒有在您的隊列上執行。

+0

是的,這也是越過我們的頭腦,_but_整個問題最初被發現時,我們有一個問題/競爭條件多線程訪問只能從我們的處理隊列訪問的共享資源。堆棧跟蹤顯示一個線程在我們的處理隊列上運行作業,另一個線程運行「com.apple.avfoundation.videodataoutput.bufferqueue」。如果avfoundation隊列dispatch_sync到我們的隊列,這應該不會發生,因爲我們的隊列是串行的 – m1h4 2014-10-02 16:39:35

+2

你可以肯定,通過預先掛起你的隊列。然後,如果你最終在塊中,你可以肯定這是一個錯誤。 – ipmcc 2014-10-02 18:29:09

+1

暫停「我們的」隊列實際上停止了處理隊列,所以看起來你是正確的,「com.apple.avfoundation.videodataoutput.bufferqueue」正在使用我們的隊列作爲目標隊列。儘管如此,爲什麼我們有兩個同時運行的線程,它們應該在同一個串行隊列中排隊(其中一個從「com.apple.avfoundation.videodataoutput.bufferqueue」中註明,另一個從「our.dispatch.queue」 )對我們來說是一種神祕感。這不應該發生,否則唯一的解釋是在avfoundation的隊列處理中存在某種同步監督。 – m1h4 2014-10-03 14:46:05

0

爲了解決這個問題,我不得不改變我的-captureOutput:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 
    dispatch_queue_t queue = ((MyAppDelegate *)UIApplication.sharedApplication.delegate).videoDataOutputQueue; 
    CFRetain(sampleBuffer); 
    dispatch_async(queue, ^{ 

     for (id<AVCaptureVideoDataOutputSampleBufferDelegate> target in captureTargets.copy) 
      [target captureOutput:captureOutput didOutputSampleBuffer:sampleBuffer fromConnection:connection]; 
     CFRelease(sampleBuffer); 
    }); 
} 
+0

什麼是captureTarget.copy這裏。? – TheMall 2018-01-03 21:02:25

+1

我有許多來自相機的圖像的不同用戶。這些「用戶」存儲在數組captureTargets中。由於數組可以在另一個隊列中更改,因此我使用該數組的副本循環並將相機輸出發送給每個隊列。 – mahboudz 2018-01-19 07:53:40

+0

謝謝...... – TheMall 2018-01-19 08:20:10