OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "avfoundationvideocapturer.h" | 11 #include "avfoundationvideocapturer.h" |
12 | 12 |
13 #import <AVFoundation/AVFoundation.h> | 13 #import <AVFoundation/AVFoundation.h> |
14 #import <Foundation/Foundation.h> | 14 #import <Foundation/Foundation.h> |
15 #if TARGET_OS_IPHONE | |
15 #import <UIKit/UIKit.h> | 16 #import <UIKit/UIKit.h> |
17 #endif | |
16 | 18 |
17 #import "RTCDispatcher+Private.h" | 19 #import "RTCDispatcher+Private.h" |
18 #import "WebRTC/RTCLogging.h" | 20 #import "WebRTC/RTCLogging.h" |
19 | 21 |
20 #include "webrtc/base/bind.h" | 22 #include "webrtc/base/bind.h" |
21 #include "webrtc/base/checks.h" | 23 #include "webrtc/base/checks.h" |
22 #include "webrtc/base/thread.h" | 24 #include "webrtc/base/thread.h" |
23 | 25 |
24 // TODO(tkchin): support other formats. | 26 // TODO(tkchin): support other formats. |
25 static NSString *const kDefaultPreset = AVCaptureSessionPreset640x480; | 27 static NSString *const kDefaultPreset = AVCaptureSessionPreset640x480; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
81 if (self = [super init]) { | 83 if (self = [super init]) { |
82 _capturer = capturer; | 84 _capturer = capturer; |
83 // Create the capture session and all relevant inputs and outputs. We need | 85 // Create the capture session and all relevant inputs and outputs. We need |
84 // to do this in init because the application may want the capture session | 86 // to do this in init because the application may want the capture session |
85 // before we start the capturer for e.g. AVCapturePreviewLayer. All objects | 87 // before we start the capturer for e.g. AVCapturePreviewLayer. All objects |
86 // created here are retained until dealloc and never recreated. | 88 // created here are retained until dealloc and never recreated. |
87 if (![self setupCaptureSession]) { | 89 if (![self setupCaptureSession]) { |
88 return nil; | 90 return nil; |
89 } | 91 } |
90 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; | 92 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; |
93 #if TARGET_OS_IPHONE | |
91 [center addObserver:self | 94 [center addObserver:self |
92 selector:@selector(deviceOrientationDidChange:) | 95 selector:@selector(deviceOrientationDidChange:) |
93 name:UIDeviceOrientationDidChangeNotification | 96 name:UIDeviceOrientationDidChangeNotification |
94 object:nil]; | 97 object:nil]; |
95 [center addObserver:self | 98 [center addObserver:self |
96 selector:@selector(handleCaptureSessionInterruption:) | 99 selector:@selector(handleCaptureSessionInterruption:) |
97 name:AVCaptureSessionWasInterruptedNotification | 100 name:AVCaptureSessionWasInterruptedNotification |
98 object:_captureSession]; | 101 object:_captureSession]; |
99 [center addObserver:self | 102 [center addObserver:self |
100 selector:@selector(handleCaptureSessionInterruptionEnded:) | 103 selector:@selector(handleCaptureSessionInterruptionEnded:) |
101 name:AVCaptureSessionInterruptionEndedNotification | 104 name:AVCaptureSessionInterruptionEndedNotification |
102 object:_captureSession]; | 105 object:_captureSession]; |
106 #endif | |
103 [center addObserver:self | 107 [center addObserver:self |
104 selector:@selector(handleCaptureSessionRuntimeError:) | 108 selector:@selector(handleCaptureSessionRuntimeError:) |
105 name:AVCaptureSessionRuntimeErrorNotification | 109 name:AVCaptureSessionRuntimeErrorNotification |
106 object:_captureSession]; | 110 object:_captureSession]; |
107 [center addObserver:self | 111 [center addObserver:self |
108 selector:@selector(handleCaptureSessionDidStartRunning:) | 112 selector:@selector(handleCaptureSessionDidStartRunning:) |
109 name:AVCaptureSessionDidStartRunningNotification | 113 name:AVCaptureSessionDidStartRunningNotification |
110 object:_captureSession]; | 114 object:_captureSession]; |
111 [center addObserver:self | 115 [center addObserver:self |
112 selector:@selector(handleCaptureSessionDidStopRunning:) | 116 selector:@selector(handleCaptureSessionDidStopRunning:) |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 // Called from WebRTC thread. | 185 // Called from WebRTC thread. |
182 - (void)start { | 186 - (void)start { |
183 if (self.hasStarted) { | 187 if (self.hasStarted) { |
184 return; | 188 return; |
185 } | 189 } |
186 self.hasStarted = YES; | 190 self.hasStarted = YES; |
187 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession | 191 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession |
188 block:^{ | 192 block:^{ |
189 _orientationHasChanged = NO; | 193 _orientationHasChanged = NO; |
190 [self updateOrientation]; | 194 [self updateOrientation]; |
195 #if TARGET_OS_IPHONE | |
191 [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; | 196 [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; |
197 #endif | |
192 AVCaptureSession *captureSession = self.captureSession; | 198 AVCaptureSession *captureSession = self.captureSession; |
193 [captureSession startRunning]; | 199 [captureSession startRunning]; |
194 }]; | 200 }]; |
195 } | 201 } |
196 | 202 |
197 // Called from same thread as start. | 203 // Called from same thread as start. |
198 - (void)stop { | 204 - (void)stop { |
199 if (!self.hasStarted) { | 205 if (!self.hasStarted) { |
200 return; | 206 return; |
201 } | 207 } |
202 self.hasStarted = NO; | 208 self.hasStarted = NO; |
203 // Due to this async block, it's possible that the ObjC object outlives the | 209 // Due to this async block, it's possible that the ObjC object outlives the |
204 // C++ one. In order to not invoke functions on the C++ object, we set | 210 // C++ one. In order to not invoke functions on the C++ object, we set |
205 // hasStarted immediately instead of dispatching it async. | 211 // hasStarted immediately instead of dispatching it async. |
206 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession | 212 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession |
207 block:^{ | 213 block:^{ |
208 [_videoDataOutput setSampleBufferDelegate:nil queue:nullptr]; | 214 [_videoDataOutput setSampleBufferDelegate:nil queue:nullptr]; |
209 [_captureSession stopRunning]; | 215 [_captureSession stopRunning]; |
216 #if TARGET_OS_IPHONE | |
210 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; | 217 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; |
218 #endif | |
211 }]; | 219 }]; |
212 } | 220 } |
213 | 221 |
214 #pragma mark iOS notifications | 222 #pragma mark iOS notifications |
215 | 223 |
224 #if TARGET_OS_IPHONE | |
216 - (void)deviceOrientationDidChange:(NSNotification *)notification { | 225 - (void)deviceOrientationDidChange:(NSNotification *)notification { |
217 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession | 226 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession |
218 block:^{ | 227 block:^{ |
219 _orientationHasChanged = YES; | 228 _orientationHasChanged = YES; |
220 [self updateOrientation]; | 229 [self updateOrientation]; |
221 }]; | 230 }]; |
222 } | 231 } |
232 #endif | |
223 | 233 |
224 #pragma mark AVCaptureVideoDataOutputSampleBufferDelegate | 234 #pragma mark AVCaptureVideoDataOutputSampleBufferDelegate |
225 | 235 |
226 - (void)captureOutput:(AVCaptureOutput *)captureOutput | 236 - (void)captureOutput:(AVCaptureOutput *)captureOutput |
227 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer | 237 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer |
228 fromConnection:(AVCaptureConnection *)connection { | 238 fromConnection:(AVCaptureConnection *)connection { |
229 NSParameterAssert(captureOutput == _videoDataOutput); | 239 NSParameterAssert(captureOutput == _videoDataOutput); |
230 if (!self.hasStarted) { | 240 if (!self.hasStarted) { |
231 return; | 241 return; |
232 } | 242 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
266 RTCLog(@"Capture session interrupted: %@", reasonString); | 276 RTCLog(@"Capture session interrupted: %@", reasonString); |
267 // TODO(tkchin): Handle this case. | 277 // TODO(tkchin): Handle this case. |
268 } | 278 } |
269 | 279 |
270 - (void)handleCaptureSessionInterruptionEnded:(NSNotification *)notification { | 280 - (void)handleCaptureSessionInterruptionEnded:(NSNotification *)notification { |
271 RTCLog(@"Capture session interruption ended."); | 281 RTCLog(@"Capture session interruption ended."); |
272 // TODO(tkchin): Handle this case. | 282 // TODO(tkchin): Handle this case. |
273 } | 283 } |
274 | 284 |
275 - (void)handleCaptureSessionRuntimeError:(NSNotification *)notification { | 285 - (void)handleCaptureSessionRuntimeError:(NSNotification *)notification { |
276 NSError *error = notification.userInfo[AVCaptureSessionErrorKey]; | 286 NSError *error = |
287 [notification.userInfo objectForKey:AVCaptureSessionErrorKey]; | |
277 RTCLogError(@"Capture session runtime error: %@", error.localizedDescription); | 288 RTCLogError(@"Capture session runtime error: %@", error.localizedDescription); |
278 | 289 |
279 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession | 290 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession |
280 block:^{ | 291 block:^{ |
292 #if TARGET_OS_IPHONE | |
281 if (error.code == AVErrorMediaServicesWereReset) { | 293 if (error.code == AVErrorMediaServicesWereReset) { |
282 [self handleNonFatalError]; | 294 [self handleNonFatalError]; |
283 } else { | 295 } else { |
284 [self handleFatalError]; | 296 [self handleFatalError]; |
285 } | 297 } |
298 #else | |
299 [self handleFatalError]; | |
300 #endif | |
286 }]; | 301 }]; |
287 } | 302 } |
288 | 303 |
289 - (void)handleCaptureSessionDidStartRunning:(NSNotification *)notification { | 304 - (void)handleCaptureSessionDidStartRunning:(NSNotification *)notification { |
290 RTCLog(@"Capture session started."); | 305 RTCLog(@"Capture session started."); |
291 self.isRunning = YES; | 306 self.isRunning = YES; |
292 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession | 307 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession |
293 block:^{ | 308 block:^{ |
294 // If we successfully restarted after an unknown error, allow future | 309 // If we successfully restarted after an unknown error, allow future |
295 // retries on fatal errors. | 310 // retries on fatal errors. |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { | 410 [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { |
396 if (captureDevice.position == position) { | 411 if (captureDevice.position == position) { |
397 return captureDevice; | 412 return captureDevice; |
398 } | 413 } |
399 } | 414 } |
400 return nil; | 415 return nil; |
401 } | 416 } |
402 | 417 |
403 - (AVCaptureDeviceInput *)frontCameraInput { | 418 - (AVCaptureDeviceInput *)frontCameraInput { |
404 if (!_frontCameraInput) { | 419 if (!_frontCameraInput) { |
420 #if TARGET_OS_IPHONE | |
405 AVCaptureDevice *frontCameraDevice = | 421 AVCaptureDevice *frontCameraDevice = |
406 [self videoCaptureDeviceForPosition:AVCaptureDevicePositionFront]; | 422 [self videoCaptureDeviceForPosition:AVCaptureDevicePositionFront]; |
423 #else | |
424 AVCaptureDevice *frontCameraDevice = | |
425 [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];; | |
tkchin_webrtc
2016/06/08 22:17:24
last one I promise :)
no space after :
| |
426 #endif | |
407 if (!frontCameraDevice) { | 427 if (!frontCameraDevice) { |
408 RTCLogWarning(@"Failed to find front capture device."); | 428 RTCLogWarning(@"Failed to find front capture device."); |
409 return nil; | 429 return nil; |
410 } | 430 } |
411 NSError *error = nil; | 431 NSError *error = nil; |
412 AVCaptureDeviceInput *frontCameraInput = | 432 AVCaptureDeviceInput *frontCameraInput = |
413 [AVCaptureDeviceInput deviceInputWithDevice:frontCameraDevice | 433 [AVCaptureDeviceInput deviceInputWithDevice:frontCameraDevice |
414 error:&error]; | 434 error:&error]; |
415 if (!frontCameraInput) { | 435 if (!frontCameraInput) { |
416 RTCLogError(@"Failed to create front camera input: %@", | 436 RTCLogError(@"Failed to create front camera input: %@", |
(...skipping 28 matching lines...) Expand all Loading... | |
445 } | 465 } |
446 | 466 |
447 // Called from capture session queue. | 467 // Called from capture session queue. |
448 - (void)updateOrientation { | 468 - (void)updateOrientation { |
449 AVCaptureConnection *connection = | 469 AVCaptureConnection *connection = |
450 [_videoDataOutput connectionWithMediaType:AVMediaTypeVideo]; | 470 [_videoDataOutput connectionWithMediaType:AVMediaTypeVideo]; |
451 if (!connection.supportsVideoOrientation) { | 471 if (!connection.supportsVideoOrientation) { |
452 // TODO(tkchin): set rotation bit on frames. | 472 // TODO(tkchin): set rotation bit on frames. |
453 return; | 473 return; |
454 } | 474 } |
475 #if TARGET_OS_IPHONE | |
455 AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationPortrait; | 476 AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationPortrait; |
456 switch ([UIDevice currentDevice].orientation) { | 477 switch ([UIDevice currentDevice].orientation) { |
457 case UIDeviceOrientationPortrait: | 478 case UIDeviceOrientationPortrait: |
458 orientation = AVCaptureVideoOrientationPortrait; | 479 orientation = AVCaptureVideoOrientationPortrait; |
459 break; | 480 break; |
460 case UIDeviceOrientationPortraitUpsideDown: | 481 case UIDeviceOrientationPortraitUpsideDown: |
461 orientation = AVCaptureVideoOrientationPortraitUpsideDown; | 482 orientation = AVCaptureVideoOrientationPortraitUpsideDown; |
462 break; | 483 break; |
463 case UIDeviceOrientationLandscapeLeft: | 484 case UIDeviceOrientationLandscapeLeft: |
464 orientation = AVCaptureVideoOrientationLandscapeRight; | 485 orientation = AVCaptureVideoOrientationLandscapeRight; |
465 break; | 486 break; |
466 case UIDeviceOrientationLandscapeRight: | 487 case UIDeviceOrientationLandscapeRight: |
467 orientation = AVCaptureVideoOrientationLandscapeLeft; | 488 orientation = AVCaptureVideoOrientationLandscapeLeft; |
468 break; | 489 break; |
469 case UIDeviceOrientationFaceUp: | 490 case UIDeviceOrientationFaceUp: |
470 case UIDeviceOrientationFaceDown: | 491 case UIDeviceOrientationFaceDown: |
471 case UIDeviceOrientationUnknown: | 492 case UIDeviceOrientationUnknown: |
472 if (!_orientationHasChanged) { | 493 if (!_orientationHasChanged) { |
473 connection.videoOrientation = orientation; | 494 connection.videoOrientation = orientation; |
474 } | 495 } |
475 return; | 496 return; |
476 } | 497 } |
477 connection.videoOrientation = orientation; | 498 connection.videoOrientation = orientation; |
499 #endif | |
478 } | 500 } |
479 | 501 |
480 // Update the current session input to match what's stored in _useBackCamera. | 502 // Update the current session input to match what's stored in _useBackCamera. |
481 - (void)updateSessionInputForUseBackCamera:(BOOL)useBackCamera { | 503 - (void)updateSessionInputForUseBackCamera:(BOOL)useBackCamera { |
482 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession | 504 [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession |
483 block:^{ | 505 block:^{ |
484 [_captureSession beginConfiguration]; | 506 [_captureSession beginConfiguration]; |
485 AVCaptureDeviceInput *oldInput = _backCameraInput; | 507 AVCaptureDeviceInput *oldInput = _backCameraInput; |
486 AVCaptureDeviceInput *newInput = _frontCameraInput; | 508 AVCaptureDeviceInput *newInput = _frontCameraInput; |
487 if (useBackCamera) { | 509 if (useBackCamera) { |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
668 | 690 |
669 // This will call a superclass method that will perform the frame conversion | 691 // This will call a superclass method that will perform the frame conversion |
670 // to I420. | 692 // to I420. |
671 SignalFrameCaptured(this, &frame); | 693 SignalFrameCaptured(this, &frame); |
672 | 694 |
673 CVPixelBufferUnlockBaseAddress(image_buffer, lock_flags); | 695 CVPixelBufferUnlockBaseAddress(image_buffer, lock_flags); |
674 CVBufferRelease(image_buffer); | 696 CVBufferRelease(image_buffer); |
675 } | 697 } |
676 | 698 |
677 } // namespace webrtc | 699 } // namespace webrtc |
OLD | NEW |