OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "media/video/capture/mac/video_capture_device_qtkit_mac.h" | 5 #import "media/video/capture/mac/video_capture_device_qtkit_mac.h" |
6 | 6 |
7 #import <QTKit/QTKit.h> | 7 #import <QTKit/QTKit.h> |
8 | 8 |
9 #include "base/debug/crash_logging.h" | 9 #include "base/debug/crash_logging.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 return YES; | 139 return YES; |
140 } else { | 140 } else { |
141 // Remove the previously set capture device. | 141 // Remove the previously set capture device. |
142 if (!captureDeviceInput_) { | 142 if (!captureDeviceInput_) { |
143 // Being here means stopping a device that never started OK in the first | 143 // Being here means stopping a device that never started OK in the first |
144 // place, log it. | 144 // place, log it. |
145 [self sendLogString:[NSString | 145 [self sendLogString:[NSString |
146 stringWithUTF8String:"No video capture device set, on removal."]]; | 146 stringWithUTF8String:"No video capture device set, on removal."]]; |
147 return YES; | 147 return YES; |
148 } | 148 } |
149 if ([[captureSession_ inputs] count] > 0) { | 149 // Tear down input and output, stop the capture and deregister observers. |
150 // The device is still running. | 150 [self stopCapture]; |
151 [self stopCapture]; | |
152 } | |
153 if ([[captureSession_ outputs] count] > 0) { | |
154 // Only one output is set for |captureSession_|. | |
155 DCHECK_EQ([[captureSession_ outputs] count], 1u); | |
156 id output = [[captureSession_ outputs] objectAtIndex:0]; | |
157 [output setDelegate:nil]; | |
158 | |
159 // TODO(shess): QTKit achieves thread safety by posting messages to the | |
160 // main thread. As part of -addOutput:, it posts a message to the main | |
161 // thread which in turn posts a notification which will run in a future | |
162 // spin after the original method returns. -removeOutput: can post a | |
163 // main-thread message in between while holding a lock which the | |
164 // notification handler will need. Posting either -addOutput: or | |
165 // -removeOutput: to the main thread should fix it, remove is likely | |
166 // safer. http://crbug.com/152757 | |
167 [captureSession_ performSelectorOnMainThread:@selector(removeOutput:) | |
168 withObject:output | |
169 waitUntilDone:YES]; | |
170 } | |
171 [captureSession_ release]; | 151 [captureSession_ release]; |
172 captureSession_ = nil; | 152 captureSession_ = nil; |
173 [captureDeviceInput_ release]; | 153 [captureDeviceInput_ release]; |
174 captureDeviceInput_ = nil; | 154 captureDeviceInput_ = nil; |
175 return YES; | 155 return YES; |
176 } | 156 } |
177 } | 157 } |
178 | 158 |
179 - (BOOL)setCaptureHeight:(int)height | 159 - (BOOL)setCaptureHeight:(int)height |
180 width:(int)width | 160 width:(int)width |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 [notificationCenter addObserver:self | 215 [notificationCenter addObserver:self |
236 selector:@selector(handleNotification:) | 216 selector:@selector(handleNotification:) |
237 name:QTCaptureSessionRuntimeErrorNotification | 217 name:QTCaptureSessionRuntimeErrorNotification |
238 object:captureSession_]; | 218 object:captureSession_]; |
239 [captureSession_ startRunning]; | 219 [captureSession_ startRunning]; |
240 } | 220 } |
241 return YES; | 221 return YES; |
242 } | 222 } |
243 | 223 |
244 - (void)stopCapture { | 224 - (void)stopCapture { |
245 if ([[captureSession_ inputs] count] == 1) { | 225 // QTKit achieves thread safety and asynchronous execution by posting messages |
246 [captureSession_ removeInput:captureDeviceInput_]; | 226 // to the main thread, e.g. -addOutput:. Both -removeOutput: and -removeInput: |
247 [captureSession_ stopRunning]; | 227 // post a message to the main thread while holding a lock that the |
248 } | 228 // notification handler might need. To avoid a deadlock, we perform those |
249 | 229 // tasks in the main thread. See bugs http://crbug.com/152757 and |
| 230 // http://crbug.com/399792. |
| 231 [self performSelectorOnMainThread:@selector(stopCaptureOnUIThread:) |
| 232 withObject:nil |
| 233 waitUntilDone:YES]; |
250 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 234 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
251 } | 235 } |
252 | 236 |
| 237 - (void)stopCaptureOnUIThread:(id)dummy { |
| 238 if ([[captureSession_ inputs] count] > 0) { |
| 239 [captureSession_ removeInput:captureDeviceInput_]; |
| 240 DCHECK_EQ([[captureSession_ inputs] count], 1u); |
| 241 [captureSession_ stopRunning]; |
| 242 } |
| 243 if ([[captureSession_ outputs] count] > 0) { |
| 244 DCHECK_EQ([[captureSession_ outputs] count], 1u); |
| 245 id output = [[captureSession_ outputs] objectAtIndex:0]; |
| 246 [output setDelegate:nil]; |
| 247 [captureSession_ removeOutput:output]; |
| 248 } |
| 249 } |
| 250 |
253 // |captureOutput| is called by the capture device to deliver a new frame. | 251 // |captureOutput| is called by the capture device to deliver a new frame. |
254 - (void)captureOutput:(QTCaptureOutput*)captureOutput | 252 - (void)captureOutput:(QTCaptureOutput*)captureOutput |
255 didOutputVideoFrame:(CVImageBufferRef)videoFrame | 253 didOutputVideoFrame:(CVImageBufferRef)videoFrame |
256 withSampleBuffer:(QTSampleBuffer*)sampleBuffer | 254 withSampleBuffer:(QTSampleBuffer*)sampleBuffer |
257 fromConnection:(QTCaptureConnection*)connection { | 255 fromConnection:(QTCaptureConnection*)connection { |
258 [lock_ lock]; | 256 [lock_ lock]; |
259 if(!frameReceiver_) { | 257 if(!frameReceiver_) { |
260 [lock_ unlock]; | 258 [lock_ unlock]; |
261 return; | 259 return; |
262 } | 260 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 | 347 |
350 - (void)sendLogString:(NSString*)message { | 348 - (void)sendLogString:(NSString*)message { |
351 DVLOG(1) << [message UTF8String]; | 349 DVLOG(1) << [message UTF8String]; |
352 [lock_ lock]; | 350 [lock_ lock]; |
353 if (frameReceiver_) | 351 if (frameReceiver_) |
354 frameReceiver_->LogMessage([message UTF8String]); | 352 frameReceiver_->LogMessage([message UTF8String]); |
355 [lock_ unlock]; | 353 [lock_ unlock]; |
356 } | 354 } |
357 | 355 |
358 @end | 356 @end |
OLD | NEW |