FreeRDP
Loading...
Searching...
No Matches
modes.m
1
18#include "modes.h"
19#include "capture_policy.h"
20#include "frame_rate.h"
21
22@interface FreeRDPCameraAVFoundationMode : NSObject
23@property(nonatomic) CAM_MEDIA_TYPE_DESCRIPTION mediaType;
24@property(nonatomic, retain) AVCaptureDeviceFormat *format;
25@property(nonatomic) CMTime frameDuration;
26@end
27
28@implementation FreeRDPCameraAVFoundationMode
29- (void)dealloc
30{
31 [_format release];
32 [super dealloc];
33}
34@end
35
36/* Do not hash the C struct's padding. Flags describe the shared encoder's output,
37 * so they do not participate in selecting the native NV12 capture mode. */
38static NSString *cam_avfoundation_mode_key(const CAM_MEDIA_TYPE_DESCRIPTION *type)
39{
40 WINPR_ASSERT(type);
41 return [NSString stringWithFormat:@"%u:%u:%u:%u:%u:%u:%u", type->Format, type->Width,
42 type->Height, type->FrameRateNumerator,
43 type->FrameRateDenominator, type->PixelAspectRatioNumerator,
44 type->PixelAspectRatioDenominator];
45}
46
48{
49 /* Preserve enumeration order independently of the descriptor hash table. */
50 NSArray<FreeRDPCameraAVFoundationMode *> *_entries;
51 NSDictionary<NSString *, FreeRDPCameraAVFoundationMode *> *_lookup;
52}
53
54- (instancetype)initWithFormats:(NSArray<AVCaptureDeviceFormat *> *)formats
55{
56 self = [super init];
57 if (!self)
58 return nil;
59 NSMutableArray<FreeRDPCameraAVFoundationMode *> *entries = [NSMutableArray array];
60 NSMutableDictionary<NSString *, FreeRDPCameraAVFoundationMode *> *lookup =
61 [NSMutableDictionary dictionary];
62 for (AVCaptureDeviceFormat *format in formats)
63 {
64 const CMVideoDimensions size =
65 CMVideoFormatDescriptionGetDimensions(format.formatDescription);
66 if ((size.width < CAM_AVFOUNDATION_MIN_WIDTH) ||
67 (size.height < CAM_AVFOUNDATION_MIN_HEIGHT) ||
68 (size.width > CAM_AVFOUNDATION_MAX_WIDTH) ||
69 (size.height > CAM_AVFOUNDATION_MAX_HEIGHT) || (size.width % 2) || (size.height % 2))
70 continue;
71 const UINT32 rates[] = CAM_AVFOUNDATION_FRAME_RATES;
72 for (size_t r = 0; r < ARRAYSIZE(rates); r++)
73 {
74 CMTime duration = kCMTimeInvalid;
75 for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges)
76 {
77 if (cam_avfoundation_frame_duration(rates[r], 1, range.minFrameDuration,
78 range.maxFrameDuration, &duration))
79 break;
80 }
82 CAM_MEDIA_FORMAT_NV12, (UINT32)size.width, (UINT32)size.height, 0, 0, 1, 1, 0
83 };
84 if (!cam_avfoundation_frame_rate(duration, &type.FrameRateNumerator,
85 &type.FrameRateDenominator))
86 continue;
87 NSString *key = cam_avfoundation_mode_key(&type);
88 if (lookup[key] || (entries.count >= ECAM_MAX_MEDIA_TYPE_DESCRIPTORS))
89 continue;
90 FreeRDPCameraAVFoundationMode *entry = [[FreeRDPCameraAVFoundationMode alloc] init];
91 if (!entry)
92 {
93 [self release];
94 return nil;
95 }
96 entry.mediaType = type;
97 entry.format = format;
98 /* Keep the native clock representation, not a duration rebuilt from the wire rate. */
99 entry.frameDuration = duration;
100 [entries addObject:entry];
101 lookup[key] = entry;
102 [entry release];
103 }
104 }
105 _entries = [entries copy];
106 _lookup = [lookup copy];
107 if (!_entries || !_lookup)
108 {
109 [self release];
110 return nil;
111 }
112 return self;
113}
114
115- (size_t)copyMediaTypes:(CAM_MEDIA_TYPE_DESCRIPTION *)mediaTypes capacity:(size_t)capacity
116{
117 WINPR_ASSERT(mediaTypes);
118 size_t count = 0;
119 for (FreeRDPCameraAVFoundationMode *entry in _entries)
120 {
121 if (count >= capacity)
122 break;
123 mediaTypes[count++] = entry.mediaType;
124 }
125 return count;
126}
127
128- (AVCaptureDeviceFormat *)formatForMediaType:(const CAM_MEDIA_TYPE_DESCRIPTION *)mediaType
129 frameDuration:(CMTime *)frameDuration
130{
131 WINPR_ASSERT(frameDuration);
132 FreeRDPCameraAVFoundationMode *entry = _lookup[cam_avfoundation_mode_key(mediaType)];
133 *frameDuration = entry ? entry.frameDuration : kCMTimeInvalid;
134 return entry.format;
135}
136
137- (void)dealloc
138{
139 [_entries release];
140 [_lookup release];
141 [super dealloc];
142}
143@end