OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 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 |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include "avfoundationformatmapper.h" |
| 12 |
| 13 #import "WebRTC/RTCLogging.h" |
| 14 |
| 15 // TODO(denicija): add support for higher frame rates. |
| 16 // See http://crbug/webrtc/6355 for more info. |
| 17 static const int kFramesPerSecond = 30; |
| 18 |
| 19 static inline BOOL IsMediaSubTypeSupported(FourCharCode mediaSubType) { |
| 20 return (mediaSubType == kCVPixelFormatType_420YpCbCr8PlanarFullRange || |
| 21 mediaSubType == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange); |
| 22 } |
| 23 |
| 24 static inline BOOL IsFrameRateWithinRange(int fps, AVFrameRateRange* range) { |
| 25 return range.minFrameRate <= fps && range.maxFrameRate >= fps; |
| 26 } |
| 27 |
| 28 // Returns filtered array of device formats based on predefined constraints our |
| 29 // stack imposes. |
| 30 static NSArray<AVCaptureDeviceFormat*>* GetEligibleDeviceFormats( |
| 31 const AVCaptureDevice* device, |
| 32 int supportedFps) { |
| 33 NSMutableArray<AVCaptureDeviceFormat*>* eligibleDeviceFormats = |
| 34 [NSMutableArray array]; |
| 35 |
| 36 for (AVCaptureDeviceFormat* format in device.formats) { |
| 37 // Filter out subTypes that we currently don't support in the stack |
| 38 FourCharCode mediaSubType = |
| 39 CMFormatDescriptionGetMediaSubType(format.formatDescription); |
| 40 if (!IsMediaSubTypeSupported(mediaSubType)) { |
| 41 continue; |
| 42 } |
| 43 |
| 44 // Filter out frame rate ranges that we currently don't support in the stack |
| 45 for (AVFrameRateRange* frameRateRange in format.videoSupportedFrameRateRange
s) { |
| 46 if (IsFrameRateWithinRange(supportedFps, frameRateRange)) { |
| 47 [eligibleDeviceFormats addObject:format]; |
| 48 break; |
| 49 } |
| 50 } |
| 51 } |
| 52 |
| 53 return [eligibleDeviceFormats copy]; |
| 54 } |
| 55 |
| 56 // Mapping from cricket::VideoFormat to AVCaptureDeviceFormat. |
| 57 static AVCaptureDeviceFormat* GetDeviceFormatForVideoFormat( |
| 58 const AVCaptureDevice* device, |
| 59 const cricket::VideoFormat& videoFormat) { |
| 60 AVCaptureDeviceFormat* desiredDeviceFormat = nil; |
| 61 NSArray<AVCaptureDeviceFormat*>* eligibleFormats = |
| 62 GetEligibleDeviceFormats(device, videoFormat.framerate()); |
| 63 |
| 64 for (AVCaptureDeviceFormat* deviceFormat in eligibleFormats) { |
| 65 CMVideoDimensions dimension = |
| 66 CMVideoFormatDescriptionGetDimensions(deviceFormat.formatDescription); |
| 67 FourCharCode mediaSubType = |
| 68 CMFormatDescriptionGetMediaSubType(deviceFormat.formatDescription); |
| 69 |
| 70 if (videoFormat.width == dimension.width && |
| 71 videoFormat.height == dimension.height) { |
| 72 if (mediaSubType == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { |
| 73 // This is the preferred format so no need to wait for better option. |
| 74 return deviceFormat; |
| 75 } else { |
| 76 // This is good candidate, but let's wait for something better. |
| 77 desiredDeviceFormat = deviceFormat; |
| 78 } |
| 79 } |
| 80 } |
| 81 |
| 82 return desiredDeviceFormat; |
| 83 } |
| 84 namespace webrtc { |
| 85 std::set<cricket::VideoFormat> GetSupportedVideoFormatsForDevice( |
| 86 AVCaptureDevice* device) { |
| 87 std::set<cricket::VideoFormat> supportedFormats; |
| 88 |
| 89 NSArray<AVCaptureDeviceFormat*>* eligibleFormats = |
| 90 GetEligibleDeviceFormats(device, kFramesPerSecond); |
| 91 |
| 92 for (AVCaptureDeviceFormat* deviceFormat in eligibleFormats) { |
| 93 CMVideoDimensions dimension = |
| 94 CMVideoFormatDescriptionGetDimensions(deviceFormat.formatDescription); |
| 95 cricket::VideoFormat format = cricket::VideoFormat( |
| 96 dimension.width, dimension.height, |
| 97 cricket::VideoFormat::FpsToInterval(kFramesPerSecond), |
| 98 cricket::FOURCC_NV12); |
| 99 supportedFormats.insert(format); |
| 100 } |
| 101 |
| 102 return supportedFormats; |
| 103 } |
| 104 |
| 105 bool SetFormatForCaptureDevice(AVCaptureDevice* device, |
| 106 AVCaptureSession* session, |
| 107 const cricket::VideoFormat& format) { |
| 108 AVCaptureDeviceFormat* deviceFormat = |
| 109 GetDeviceFormatForVideoFormat(device, format); |
| 110 const int fps = cricket::VideoFormat::IntervalToFps(format.interval); |
| 111 |
| 112 NSError* error = nil; |
| 113 bool success = true; |
| 114 [session beginConfiguration]; |
| 115 if ([device lockForConfiguration:&error]) { |
| 116 @try { |
| 117 device.activeFormat = deviceFormat; |
| 118 device.activeVideoMinFrameDuration = CMTimeMake(1, fps); |
| 119 } @catch (NSException* exception) { |
| 120 RTCLogError(@"Failed to set active format!\n User info:%@", |
| 121 exception.userInfo); |
| 122 success = false; |
| 123 } |
| 124 |
| 125 [device unlockForConfiguration]; |
| 126 } else { |
| 127 RTCLogError(@"Failed to lock device %@. Error: %@", device, error.userInfo); |
| 128 success = false; |
| 129 } |
| 130 [session commitConfiguration]; |
| 131 |
| 132 return success; |
| 133 } |
| 134 |
| 135 } // namespace webrtc |
OLD | NEW |