| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 | 
							- //
 
- //  plugin-properties.m
 
- //  mac-avcapture
 
- //
 
- //  Created by Patrick Heyer on 2023-03-07.
 
- //
 
- #import "OBSAVCapture.h"
 
- #import "plugin-properties.h"
 
- #import "AVCaptureDeviceFormat+OBSListable.h"
 
- extern const char *av_capture_get_text(const char *text_id);
 
- void configure_property(obs_property_t *property, bool enable, bool visible, void *callback, OBSAVCapture *capture)
 
- {
 
-     if (property) {
 
-         obs_property_set_enabled(property, enable);
 
-         obs_property_set_visible(property, visible);
 
-         if (callback) {
 
-             obs_property_set_modified_callback2(property, callback, (__bridge void *) (capture));
 
-         }
 
-     }
 
- }
 
- bool properties_changed(OBSAVCapture *capture, obs_properties_t *properties, obs_property_t *property __unused,
 
-                         obs_data_t *settings)
 
- {
 
-     OBSAVCaptureInfo *captureInfo = capture.captureInfo;
 
-     obs_property_t *prop_use_preset = obs_properties_get(properties, "use_preset");
 
-     obs_property_t *prop_device = obs_properties_get(properties, "device");
 
-     obs_property_t *prop_presets = obs_properties_get(properties, "preset");
 
-     obs_property_set_enabled(prop_use_preset, !captureInfo->isFastPath);
 
-     if (captureInfo && settings) {
 
-         properties_update_device(capture, prop_device, settings);
 
-         bool use_preset = (settings ? obs_data_get_bool(settings, "use_preset") : true);
 
-         if (use_preset) {
 
-             properties_update_preset(capture, prop_presets, settings);
 
-         } else {
 
-             properties_update_config(capture, properties, settings);
 
-         }
 
-     }
 
-     return true;
 
- }
 
- bool properties_changed_preset(OBSAVCapture *capture, obs_properties_t *properties __unused, obs_property_t *property,
 
-                                obs_data_t *settings)
 
- {
 
-     bool use_preset = obs_data_get_bool(settings, "use_preset");
 
-     if (capture && settings && use_preset) {
 
-         NSArray *presetKeys =
 
-             [capture.presetList keysSortedByValueUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
 
-                 NSNumber *obj1Resolution;
 
-                 NSNumber *obj2Resolution;
 
-                 if ([obj1 isEqualToString:@"High"]) {
 
-                     obj1Resolution = @3;
 
-                 } else if ([obj1 isEqualToString:@"Medium"]) {
 
-                     obj1Resolution = @2;
 
-                 } else if ([obj1 isEqualToString:@"Low"]) {
 
-                     obj1Resolution = @1;
 
-                 } else {
 
-                     NSArray<NSString *> *obj1Dimensions = [obj1 componentsSeparatedByString:@"x"];
 
-                     obj1Resolution = [NSNumber numberWithInt:([[obj1Dimensions objectAtIndex:0] intValue] *
 
-                                                               [[obj1Dimensions objectAtIndex:1] intValue])];
 
-                 }
 
-                 if ([obj2 isEqualToString:@"High"]) {
 
-                     obj2Resolution = @3;
 
-                 } else if ([obj2 isEqualToString:@"Medium"]) {
 
-                     obj2Resolution = @2;
 
-                 } else if ([obj2 isEqualToString:@"Low"]) {
 
-                     obj2Resolution = @1;
 
-                 } else {
 
-                     NSArray<NSString *> *obj2Dimensions = [obj2 componentsSeparatedByString:@"x"];
 
-                     obj2Resolution = [NSNumber numberWithInt:([[obj2Dimensions objectAtIndex:0] intValue] *
 
-                                                               [[obj2Dimensions objectAtIndex:1] intValue])];
 
-                 }
 
-                 NSComparisonResult result = [obj1Resolution compare:obj2Resolution];
 
-                 if (result == NSOrderedAscending) {
 
-                     return (NSComparisonResult) NSOrderedDescending;
 
-                 } else if (result == NSOrderedDescending) {
 
-                     return (NSComparisonResult) NSOrderedAscending;
 
-                 } else {
 
-                     return (NSComparisonResult) NSOrderedSame;
 
-                 }
 
-             }];
 
-         NSString *UUID = [OBSAVCapture stringFromSettings:settings withSetting:@"device"];
 
-         AVCaptureDevice *device = [AVCaptureDevice deviceWithUniqueID:UUID];
 
-         NSString *currentPreset = [OBSAVCapture stringFromSettings:settings withSetting:@"preset"];
 
-         obs_property_list_clear(property);
 
-         if (device) {
 
-             for (NSString *presetName in presetKeys) {
 
-                 NSString *presetDescription = capture.presetList[presetName];
 
-                 if ([device supportsAVCaptureSessionPreset:presetName]) {
 
-                     obs_property_list_add_string(property, presetDescription.UTF8String, presetName.UTF8String);
 
-                 } else if ([currentPreset isEqualToString:presetName]) {
 
-                     size_t index =
 
-                         obs_property_list_add_string(property, presetDescription.UTF8String, presetName.UTF8String);
 
-                     obs_property_list_item_disable(property, index, true);
 
-                 }
 
-             };
 
-         } else if (UUID.length) {
 
-             size_t index = obs_property_list_add_string(property, capture.presetList[currentPreset].UTF8String,
 
-                                                         currentPreset.UTF8String);
 
-             obs_property_list_item_disable(property, index, true);
 
-         }
 
-         return YES;
 
-     } else {
 
-         return NO;
 
-     }
 
- }
 
- bool properties_changed_use_preset(OBSAVCapture *capture, obs_properties_t *properties,
 
-                                    obs_property_t *property __unused, obs_data_t *settings)
 
- {
 
-     bool use_preset = obs_data_get_bool(settings, "use_preset");
 
-     obs_property_t *preset_list = obs_properties_get(properties, "preset");
 
-     obs_property_set_visible(preset_list, use_preset);
 
-     if (use_preset) {
 
-         properties_changed_preset(capture, properties, preset_list, settings);
 
-     }
 
-     const char *update_properties[2] = {"frame_rate", "supported_format"};
 
-     size_t number_of_properties = sizeof(update_properties) / sizeof(update_properties[0]);
 
-     for (size_t i = 0; i < number_of_properties; i++) {
 
-         obs_property_t *update_property = obs_properties_get(properties, update_properties[i]);
 
-         if (update_property) {
 
-             obs_property_set_visible(update_property, !use_preset);
 
-             obs_property_set_enabled(update_property, !use_preset);
 
-         }
 
-     }
 
-     return true;
 
- }
 
- bool properties_update_preset(OBSAVCapture *capture, obs_property_t *property, obs_data_t *settings)
 
- {
 
-     NSArray *presetKeys =
 
-         [capture.presetList keysSortedByValueUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
 
-             NSNumber *obj1Resolution;
 
-             NSNumber *obj2Resolution;
 
-             if ([obj1 isEqualToString:@"High"]) {
 
-                 obj1Resolution = @3;
 
-             } else if ([obj1 isEqualToString:@"Medium"]) {
 
-                 obj1Resolution = @2;
 
-             } else if ([obj1 isEqualToString:@"Low"]) {
 
-                 obj1Resolution = @1;
 
-             } else {
 
-                 NSArray<NSString *> *obj1Dimensions = [obj1 componentsSeparatedByString:@"x"];
 
-                 obj1Resolution = [NSNumber numberWithInt:([[obj1Dimensions objectAtIndex:0] intValue] *
 
-                                                           [[obj1Dimensions objectAtIndex:1] intValue])];
 
-             }
 
-             if ([obj2 isEqualToString:@"High"]) {
 
-                 obj2Resolution = @3;
 
-             } else if ([obj2 isEqualToString:@"Medium"]) {
 
-                 obj2Resolution = @2;
 
-             } else if ([obj2 isEqualToString:@"Low"]) {
 
-                 obj2Resolution = @1;
 
-             } else {
 
-                 NSArray<NSString *> *obj2Dimensions = [obj2 componentsSeparatedByString:@"x"];
 
-                 obj2Resolution = [NSNumber numberWithInt:([[obj2Dimensions objectAtIndex:0] intValue] *
 
-                                                           [[obj2Dimensions objectAtIndex:1] intValue])];
 
-             }
 
-             NSComparisonResult result = [obj1Resolution compare:obj2Resolution];
 
-             if (result == NSOrderedAscending) {
 
-                 return (NSComparisonResult) NSOrderedDescending;
 
-             } else if (result == NSOrderedDescending) {
 
-                 return (NSComparisonResult) NSOrderedAscending;
 
-             } else {
 
-                 return (NSComparisonResult) NSOrderedSame;
 
-             }
 
-         }];
 
-     NSString *deviceUUID = [OBSAVCapture stringFromSettings:settings withSetting:@"device"];
 
-     AVCaptureDevice *device = [AVCaptureDevice deviceWithUniqueID:deviceUUID];
 
-     NSString *currentPreset = [OBSAVCapture stringFromSettings:settings withSetting:@"preset"];
 
-     obs_property_list_clear(property);
 
-     if (device) {
 
-         for (NSString *presetName in presetKeys) {
 
-             NSString *presetDescription = capture.presetList[presetName];
 
-             if ([device supportsAVCaptureSessionPreset:presetName]) {
 
-                 obs_property_list_add_string(property, presetDescription.UTF8String, presetName.UTF8String);
 
-             } else if ([currentPreset isEqualToString:presetName]) {
 
-                 size_t index =
 
-                     obs_property_list_add_string(property, presetDescription.UTF8String, presetName.UTF8String);
 
-                 obs_property_list_item_disable(property, index, true);
 
-             }
 
-         };
 
-     } else if (deviceUUID.length) {
 
-         size_t index = obs_property_list_add_string(property, capture.presetList[currentPreset].UTF8String,
 
-                                                     currentPreset.UTF8String);
 
-         obs_property_list_item_disable(property, index, true);
 
-     }
 
-     return true;
 
- }
 
- bool properties_update_device(OBSAVCapture *capture __unused, obs_property_t *property, obs_data_t *settings)
 
- {
 
-     obs_property_list_clear(property);
 
-     NSString *currentDeviceUUID = [OBSAVCapture stringFromSettings:settings withSetting:@"device"];
 
-     NSString *currentDeviceName = [OBSAVCapture stringFromSettings:settings withSetting:@"device_name"];
 
-     BOOL isDeviceFound = NO;
 
-     obs_property_list_add_string(property, "", "");
 
-     NSArray *deviceTypes;
 
-     if (@available(macOS 13, *)) {
 
-         deviceTypes = @[
 
-             AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeExternalUnknown,
 
-             AVCaptureDeviceTypeDeskViewCamera
 
-         ];
 
-     } else {
 
-         deviceTypes = @[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeExternalUnknown];
 
-     }
 
-     AVCaptureDeviceDiscoverySession *videoDiscoverySession =
 
-         [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo
 
-                                                                 position:AVCaptureDevicePositionUnspecified];
 
-     AVCaptureDeviceDiscoverySession *muxedDiscoverySession =
 
-         [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeMuxed
 
-                                                                 position:AVCaptureDevicePositionUnspecified];
 
-     for (AVCaptureDevice *device in [videoDiscoverySession devices]) {
 
-         obs_property_list_add_string(property, device.localizedName.UTF8String, device.uniqueID.UTF8String);
 
-         if (!isDeviceFound && [currentDeviceUUID isEqualToString:device.uniqueID]) {
 
-             isDeviceFound = YES;
 
-         }
 
-     }
 
-     for (AVCaptureDevice *device in [muxedDiscoverySession devices]) {
 
-         obs_property_list_add_string(property, device.localizedName.UTF8String, device.uniqueID.UTF8String);
 
-         if (!isDeviceFound && [currentDeviceUUID isEqualToString:device.uniqueID]) {
 
-             isDeviceFound = YES;
 
-         }
 
-     }
 
-     if (!isDeviceFound && currentDeviceUUID.length > 0) {
 
-         size_t index =
 
-             obs_property_list_add_string(property, currentDeviceName.UTF8String, currentDeviceUUID.UTF8String);
 
-         obs_property_list_item_disable(property, index, true);
 
-     }
 
-     return true;
 
- }
 
- bool properties_update_config(OBSAVCapture *capture, obs_properties_t *properties, obs_data_t *settings)
 
- {
 
-     AVCaptureDevice *device = [AVCaptureDevice deviceWithUniqueID:[OBSAVCapture stringFromSettings:settings
 
-                                                                                        withSetting:@"device"]];
 
-     obs_property_t *prop_framerate = obs_properties_get(properties, "frame_rate");
 
-     obs_property_t *prop_format = obs_properties_get(properties, "supported_format");
 
-     obs_property_t *prop_effects_warning = obs_properties_get(properties, "effects_warning");
 
-     obs_property_frame_rate_clear(prop_framerate);
 
-     obs_property_list_clear(prop_format);
 
-     obs_property_list_clear(prop_effects_warning);
 
-     struct media_frames_per_second fps;
 
-     if (!obs_data_get_frames_per_second(settings, "frame_rate", &fps, NULL)) {
 
-         [capture AVCaptureLog:LOG_DEBUG withFormat:@"No valid framerate found in settings"];
 
-     }
 
-     const char *selectedFormatData = obs_data_get_string(settings, "supported_format");
 
-     NSString *selectedFormatString = [NSString stringWithCString:selectedFormatData encoding:NSUTF8StringEncoding];
 
-     NSMutableArray *frameRates = [[NSMutableArray alloc] init];
 
-     if (device) {
 
-         NSSortDescriptor *aspectSort = [[NSSortDescriptor alloc] initWithKey:@"aspectRatioComparisonValue"
 
-                                                                    ascending:false];
 
-         NSSortDescriptor *pixelBandwidthSort = [[NSSortDescriptor alloc] initWithKey:@"pixelBandwidthComparisonValue"
 
-                                                                            ascending:false];
 
-         NSSortDescriptor *bppSort = [[NSSortDescriptor alloc] initWithKey:@"bitsPerPixel" ascending:true];
 
-         NSArray<NSSortDescriptor *> *sortArray =
 
-             [NSArray arrayWithObjects:aspectSort, pixelBandwidthSort, bppSort, nil];
 
-         for (AVCaptureDeviceFormat *format in [device.formats sortedArrayUsingDescriptors:sortArray]) {
 
-             NSString *enumeratedFormatString = format.obsPropertyListDescription;
 
-             NSString *internalRepresentation = format.obsPropertyListInternalRepresentation;
 
-             obs_property_list_add_string(prop_format, enumeratedFormatString.UTF8String,
 
-                                          internalRepresentation.UTF8String);
 
-             if ([selectedFormatString isEqualToString:internalRepresentation]) {
 
-                 for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) {
 
-                     struct media_frames_per_second min_fps = {
 
-                         .numerator = (uint32_t) clamp_Uint(range.maxFrameDuration.timescale, 0, UINT32_MAX),
 
-                         .denominator = (uint32_t) clamp_Uint(range.maxFrameDuration.value, 0, UINT32_MAX)};
 
-                     struct media_frames_per_second max_fps = {
 
-                         .numerator = (uint32_t) clamp_Uint(range.minFrameDuration.timescale, 0, UINT32_MAX),
 
-                         .denominator = (uint32_t) clamp_Uint(range.minFrameDuration.value, 0, UINT32_MAX)};
 
-                     if (![frameRates containsObject:range]) {
 
-                         obs_property_frame_rate_fps_range_add(prop_framerate, min_fps, max_fps);
 
-                         [frameRates addObject:range];
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-     }
 
-     return true;
 
- }
 
 
  |