Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
- Cleaned up Rust documentation.
- Added support for dragging BRAW Toolbox clips.
- Set minimum deployment target to 12.6 to match Gyroflow.
- Added Settings button.
- General tidy-up.
  • Loading branch information
latenitefilms committed Aug 3, 2023
1 parent f1c1d73 commit eca0171
Show file tree
Hide file tree
Showing 10 changed files with 1,808 additions and 1,228 deletions.
8 changes: 8 additions & 0 deletions Source/Frameworks/gyroflow/inc/gyroflow.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,11 @@ const char* loadLensProfile(
const char* gyroflow_project_data,
const char* lens_profile_path
);

//---------------------------------------------------------
// Load a Preset into a Gyroflow Project:
//---------------------------------------------------------
const char* loadPreset(
const char* gyroflow_project_data,
const char* lens_profile_path
);
128 changes: 122 additions & 6 deletions Source/Frameworks/gyroflow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,22 @@ use std::sync::Arc; // Adds Atomic Reference Count suppo
use std::sync::atomic::AtomicBool; // The AtomicBool type is a type of atomic variable that can be used in concurrent (multi-threaded) contexts.
use std::sync::Mutex; // A mutual exclusion primitive useful for protecting shared data

//---------------------------------------------------------
// We only want to setup the Gyroflow Manager once for
// each pixel format:
//---------------------------------------------------------
// This code block defines a lazy static variable called `MANAGER_CACHE` that is a `Mutex`-protected LRU cache of `StabilizationManager` instances.
//
// The `lazy_static!` macro is used to ensure that the variable is initialized only once, and only when it is first accessed.
//
// The `Mutex` is used to ensure that the cache can be safely accessed from multiple threads.
//
// The `LruCache` is used to limit the size of the cache to 8 items.
//
// # Example
//
// ```rust
// use gyroflow::MANAGER_CACHE;
//
// let cache = MANAGER_CACHE.lock().unwrap();
// let manager = cache.get("my_pixel_format").unwrap();
// ```
lazy_static! {
static ref MANAGER_CACHE: Mutex<LruCache<String, Arc<StabilizationManager>>> = Mutex::new(LruCache::new(std::num::NonZeroUsize::new(8).unwrap()));
}
Expand Down Expand Up @@ -416,7 +428,7 @@ pub extern "C" fn hasAccurateTimestamps(
}
}

/// Load a Lens Profile to a supplied Gyroflow Project.
/// Load a Lens Profile from a JSON to a supplied Gyroflow Project.
///
/// # Arguments
///
Expand Down Expand Up @@ -518,6 +530,107 @@ pub extern "C" fn loadLensProfile(
}
}

/// Load a Gyroflow Preset to a supplied Gyroflow Project.
///
/// # Arguments
///
/// * `gyroflow_project_data` - A pointer to a C-style string representing the Gyroflow Project data.
/// * `preset_path` - A pointer to a C-style string representing the Profile data.
///
/// # Returns
///
/// A new Gyroflow Project or "FAIL".
#[no_mangle]
pub extern "C" fn loadPreset(
gyroflow_project_data: *const c_char,
preset_path: *const c_char,
) -> *const c_char {
//---------------------------------------------------------
// Convert the Gyroflow Project data to a `&str`:
//---------------------------------------------------------
let gyroflow_project_data_pointer = unsafe { CStr::from_ptr(gyroflow_project_data) };
let gyroflow_project_data_string = gyroflow_project_data_pointer.to_string_lossy();

//---------------------------------------------------------
// Convert the Lens Profile data to a `&str`:
//---------------------------------------------------------
let preset_path_pointer = unsafe { CStr::from_ptr(preset_path) };
let preset_path_string = preset_path_pointer.to_string_lossy();

let mut stab = StabilizationManager::default();
{
//---------------------------------------------------------
// Find first lens profile database with loaded profiles:
//---------------------------------------------------------
let lock = MANAGER_CACHE.lock().unwrap();
for (_, v) in lock.iter() {
if v.lens_profile_db.read().loaded {
stab.lens_profile_db = v.lens_profile_db.clone();
break;
}
}
}

//---------------------------------------------------------
// Import the `gyroflow_project_data_string`:
//---------------------------------------------------------
let blocking = true;
let path = Some(std::path::PathBuf::from(&*gyroflow_project_data_string));
let cancel_flag = Arc::new(AtomicBool::new(false));
let mut is_preset = false;
match stab.import_gyroflow_data(
gyroflow_project_data_string.as_bytes(),
blocking,
path,
|_|(),
cancel_flag,
&mut is_preset
) {
Ok(_) => {
//---------------------------------------------------------
// Load Preset:
//---------------------------------------------------------
let mut is_preset = false;
if let Err(e) = stab.import_gyroflow_data(preset_path_string.as_bytes(), true, None, |_|(), Arc::new(AtomicBool::new(false)), &mut is_preset) {
log::error!("[Gyroflow Toolbox Rust] Error loading Preset: {:?}", e);
let result = CString::new("FAIL").unwrap();
return result.into_raw()
}

//---------------------------------------------------------
// Export Gyroflow data:
//---------------------------------------------------------
let gyroflow_data: String;
match stab.export_gyroflow_data(false, false, "{}") {
Ok(data) => {
gyroflow_data = data;
log::info!("[Gyroflow Toolbox Rust] Gyroflow data exported successfully");
},
Err(e) => {
log::error!("[Gyroflow Toolbox Rust] An error occured: {:?}", e);
gyroflow_data = "FAIL".to_string();
}
}

//---------------------------------------------------------
// Return Gyroflow Project data as string:
//---------------------------------------------------------
let result = CString::new(gyroflow_data).unwrap();
return result.into_raw()
},
Err(e) => {
//---------------------------------------------------------
// An error has occurred:
//---------------------------------------------------------
log::error!("[Gyroflow Toolbox Rust] Error importing Preset: {:?}", e);

let error_msg = format!("{}", e);
let result = CString::new(error_msg).unwrap();
return result.into_raw()
},
}
}

/// This function is called from Objective-C land and is responsible for clearing the cache.
///
/// # Returns
Expand Down Expand Up @@ -871,7 +984,7 @@ pub extern "C" fn processFrame(
let output_stride: usize = output_width * 4 * number_of_bytes_value;

//---------------------------------------------------------
// Stabilization time!
// Prepare the Metal Texture Image Buffers:
//---------------------------------------------------------
let mut buffers = Buffers {
output: BufferDescription {
Expand All @@ -890,6 +1003,9 @@ pub extern "C" fn processFrame(
}
};

//---------------------------------------------------------
// Get the Stabilization Result:
//---------------------------------------------------------
let _stabilization_result = match pixel_format_string.as_ref() {
"BGRA8Unorm" => {
manager.process_pixels::<BGRA8>(timestamp, &mut buffers)
Expand Down
22 changes: 18 additions & 4 deletions Source/Gyroflow.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
224321B829615C4400EA591A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 224321B729615C4400EA591A /* Assets.xcassets */; };
22BED1C32A5D6805000562A3 /* CustomButtonView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BED1BF2A5D6805000562A3 /* CustomButtonView.m */; };
22BED1C42A5D6805000562A3 /* CustomDropZoneView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BED1C22A5D6805000562A3 /* CustomDropZoneView.m */; };
22C25B1D2A7B4AB700BB135B /* BRAWToolboxXMLReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 22C25B1C2A7B4AB700BB135B /* BRAWToolboxXMLReader.m */; };
22DAC75F2953B1A7001F2E06 /* GyroflowDocument.icns in Resources */ = {isa = PBXBuildFile; fileRef = 22DAC75E2953B1A7001F2E06 /* GyroflowDocument.icns */; };
22F73D712A6009AA00A6F326 /* HeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22F73D702A6009AA00A6F326 /* HeaderView.xib */; };
22F73D742A600B3A00A6F326 /* HeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22F73D732A600B3A00A6F326 /* HeaderView.m */; };
Expand Down Expand Up @@ -122,6 +123,8 @@
22BED1C02A5D6805000562A3 /* CustomButtonView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomButtonView.h; sourceTree = "<group>"; };
22BED1C12A5D6805000562A3 /* CustomDropZoneView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomDropZoneView.h; sourceTree = "<group>"; };
22BED1C22A5D6805000562A3 /* CustomDropZoneView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomDropZoneView.m; sourceTree = "<group>"; };
22C25B1B2A7B4AB700BB135B /* BRAWToolboxXMLReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BRAWToolboxXMLReader.h; sourceTree = "<group>"; };
22C25B1C2A7B4AB700BB135B /* BRAWToolboxXMLReader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BRAWToolboxXMLReader.m; sourceTree = "<group>"; };
22DAC75E2953B1A7001F2E06 /* GyroflowDocument.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = GyroflowDocument.icns; sourceTree = "<group>"; };
22E4989F29492E8100580F67 /* Cargo.toml */ = {isa = PBXFileReference; lastKnownFileType = text; name = Cargo.toml; path = Frameworks/gyroflow/Cargo.toml; sourceTree = SOURCE_ROOT; };
22F73D6F2A5FF9A000A6F326 /* SandboxEntitlements.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SandboxEntitlements.entitlements; sourceTree = "<group>"; };
Expand Down Expand Up @@ -308,8 +311,7 @@
228E9E1929517DDA00B2571E /* GyroflowConstants.h */,
2239AB2E2943F8F600028B77 /* GyroflowPlugIn.h */,
2239AB312943F8F600028B77 /* GyroflowPlugIn.m */,
2239AB58294400CE00028B77 /* GyroflowParameters.h */,
2239AB56294400B500028B77 /* GyroflowParameters.m */,
22C25B1E2A7B5CAF00BB135B /* Helpers */,
22DAC7632953D1CF001F2E06 /* Custom Views */,
);
name = Code;
Expand All @@ -328,6 +330,17 @@
name = Extras;
sourceTree = "<group>";
};
22C25B1E2A7B5CAF00BB135B /* Helpers */ = {
isa = PBXGroup;
children = (
22C25B1B2A7B4AB700BB135B /* BRAWToolboxXMLReader.h */,
22C25B1C2A7B4AB700BB135B /* BRAWToolboxXMLReader.m */,
2239AB58294400CE00028B77 /* GyroflowParameters.h */,
2239AB56294400B500028B77 /* GyroflowParameters.m */,
);
name = Helpers;
sourceTree = "<group>";
};
22DAC7632953D1CF001F2E06 /* Custom Views */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -515,6 +528,7 @@
22F73D742A600B3A00A6F326 /* HeaderView.m in Sources */,
22F73D912A604BB100A6F326 /* TileableRemoteBRAW.metal in Sources */,
2239AB392943F8F600028B77 /* MetalDeviceCache.m in Sources */,
22C25B1D2A7B4AB700BB135B /* BRAWToolboxXMLReader.m in Sources */,
22BED1C32A5D6805000562A3 /* CustomButtonView.m in Sources */,
2239AB452943F8F600028B77 /* main.m in Sources */,
22BED1C42A5D6805000562A3 /* CustomDropZoneView.m in Sources */,
Expand Down Expand Up @@ -631,7 +645,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MACOSX_DEPLOYMENT_TARGET = 12.6;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -691,7 +705,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MACOSX_DEPLOYMENT_TARGET = 12.6;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
Expand Down
19 changes: 19 additions & 0 deletions Source/Gyroflow/Plugin/BRAWToolboxXMLReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// BRAWToolboxXMLReader.h
// Gyroflow Toolbox Renderer
//
// Created by Chris Hocking on 3/8/2023.
//

#import <Cocoa/Cocoa.h>

@interface BRAWToolboxXMLReader : NSObject <NSXMLParserDelegate>

@property (strong, nonatomic) NSString *currentElement;
@property (strong, nonatomic) NSString *filePath;
@property (strong, nonatomic) NSString *bookmarkData;
@property (nonatomic) BOOL isBRAWToolbox;

- (NSDictionary *)readXML:(NSString *)xmlString;

@end
72 changes: 72 additions & 0 deletions Source/Gyroflow/Plugin/BRAWToolboxXMLReader.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// BRAWToolboxXMLReader.m
// Gyroflow Toolbox Renderer
//
// Created by Chris Hocking on 3/8/2023.
//

#import "BRAWToolboxXMLReader.h"

//---------------------------------------------------------
// BRAW Toolbox XML Reader:
//---------------------------------------------------------

@implementation BRAWToolboxXMLReader

//---------------------------------------------------------
// Read XML file:
//---------------------------------------------------------
- (NSDictionary *)readXML:(NSString *)xmlString {
self.isBRAWToolbox = NO;
NSData *data = [xmlString dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];

if (self.filePath && self.bookmarkData) {
return @{@"File Path": self.filePath, @"Bookmark Data": self.bookmarkData};
}
return nil;
}

//---------------------------------------------------------
// XML Parser:
//---------------------------------------------------------
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
self.currentElement = elementName;

if ([elementName isEqualToString:@"filter-video"] && [[attributeDict objectForKey:@"name"] isEqualToString:@"BRAW Toolbox"]) {
self.isBRAWToolbox = YES;
}

if (self.isBRAWToolbox && [elementName isEqualToString:@"param"]) {
if ([[attributeDict objectForKey:@"name"] isEqualToString:@"File Path"]) {
self.filePath = [attributeDict objectForKey:@"value"];
} else if ([[attributeDict objectForKey:@"name"] isEqualToString:@"Bookmark Data"]) {
self.bookmarkData = [attributeDict objectForKey:@"value"];
}
}
}

//---------------------------------------------------------
// XML Parser:
//---------------------------------------------------------
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
self.currentElement = nil;
if ([elementName isEqualToString:@"filter-video"]) {
self.isBRAWToolbox = NO;
}
}

//---------------------------------------------------------
// Dealloc:
//---------------------------------------------------------
- (void)dealloc {
[_currentElement release];
[_filePath release];
[_bookmarkData release];

[super dealloc];
}

@end
30 changes: 18 additions & 12 deletions Source/Gyroflow/Plugin/CustomDropZoneView.m
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,8 @@ - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
//---------------------------------------------------------
// Trigger Dropped File Method:
//---------------------------------------------------------
//NSLog(@"[Gyroflow Toolbox Renderer] Dropped file path: %@", [fileURL path]);

NSLog(@"[Gyroflow Toolbox Renderer] Dropped file path: %@", [fileURL path]);

//---------------------------------------------------------
// Create a new security-scoped bookmark:
//---------------------------------------------------------
Expand All @@ -115,12 +114,17 @@ - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
return NO;
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
BOOL result = [_parentPlugin importDroppedMedia:bookmarkData];
#pragma clang diagnostic pop

return result;
dispatch_async(dispatch_get_main_queue(), ^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
[_parentPlugin importDroppedMedia:bookmarkData];
#pragma clang diagnostic pop
});

_dragIsOver = false;
[self needsDisplay];

return YES;
}

} else {
Expand All @@ -135,10 +139,12 @@ - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {

//NSLog(@"[Gyroflow Toolbox Renderer] Dropped Final Cut Pro data: %@", finalCutProData);

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
[_parentPlugin importDroppedClip:finalCutProData];
#pragma clang diagnostic pop
dispatch_async(dispatch_get_main_queue(), ^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
[_parentPlugin importDroppedClip:finalCutProData];
#pragma clang diagnostic pop
});

_dragIsOver = false;
[self needsDisplay];
Expand Down
1 change: 1 addition & 0 deletions Source/Gyroflow/Plugin/GyroflowConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ enum {
kCB_TopSection = 1,
kCB_Header = 2,
kCB_OpenUserGuide = 3,
kCB_Settings = 4,

//---------------------------------------------------------
// Import Section:
Expand Down
Loading

0 comments on commit eca0171

Please sign in to comment.