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 |