gyroflow / gyroflow-ofx

GNU General Public License v3.0
114 stars 7 forks source link

Code that detects if there's gyro data needs updating. #41

Closed latenitefilms closed 11 months ago

latenitefilms commented 1 year ago

Looking at this code:

if path.ends_with(".gyroflow") {
    if let Ok(data) = std::fs::read_to_string(&path) {
        if !data.contains("\"raw_imu\": null") || !data.contains("\"quaternions\": null") {
            instance_data.param_project_data.set_value(data.clone())?;
        } else {
            if let Some((_, stab)) = instance_data.gyrodata.peek_lru() {
                if let Ok(data) = stab.export_gyroflow_data(false, false, "{}") {
                    instance_data.param_project_data.set_value(data)?;
                }
            }
        }
    } else {
        instance_data.param_project_data.set_value("".to_string())?;
    }
} else {
    if let Some((_, stab)) = instance_data.gyrodata.peek_lru() {
        if let Ok(data) = stab.export_gyroflow_data(false, false, "{}") {
            instance_data.param_project_data.set_value(data)?;
        }
    }
}

Currently it's reading the Gyroflow Project JSON as a string, and checking for raw_imu and quaternions strings - however, in the current Gyroflow Project JSON, gyro_source > file_metadata is stored as a blob of data - so you'll never find the raw_imu and quaternions strings.

This should be updated to read the raw_imu and quaternions data from the file_metadata contents.

However, I'm currently using this code in Gyroflow Toolbox:

//---------------------------------------------------------
// Does the Gyroflow Project contain Stabilisation Data?
// Returns "YES" or a failure string.
//---------------------------------------------------------
#[no_mangle]
pub extern "C" fn doesGyroflowProjectContainStabilisationData(
    gyroflow_project_data: *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();

    let stab = StabilizationManager::default();

    //---------------------------------------------------------
    // Import the `gyroflow_project_data_string`:
    //---------------------------------------------------------
    let blocking = true;    
    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, 
        None, 
        |_|(),
        cancel_flag,
        &mut is_preset
    ) {
        Ok(_) => {
            //---------------------------------------------------------
            // Check if gyroflow project contains stabilization data:
            //---------------------------------------------------------
            let has_motion = { 
                let gyro = stab.gyro.read(); 
                !gyro.file_metadata.raw_imu.is_empty() || !gyro.file_metadata.quaternions.is_empty()
            };

            //---------------------------------------------------------
            // Return the result as a string:
            //---------------------------------------------------------
            let result_string = if has_motion {
                "YES"
            } else {
                "NO"
            };

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

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

...and it returns NO for an R3D Gyroflow Project that is synced and working, so I think something is wrong in gyroflow_core too?

latenitefilms commented 1 year ago

Ummm... I'm getting very strange results. In this case it was working fine:

image
latenitefilms commented 1 year ago

...in this case it returns nothing:

image

Even though is looks right in Gyroflow:

image

...and there's definitely file_metadata in the saved Gyroflow Project:

image

I'll keep digging, as it's probably something wrong in my code.

latenitefilms commented 1 year ago

Here's an example of a Gyroflow Project that's failing my doesGyroflowProjectContainStabilisationData() function:

image image

A003_A002_1223KO_001.gyroflow.zip

latenitefilms commented 1 year ago

Ahhh.... I think this might be my issue:

image
latenitefilms commented 1 year ago

I think the problem why my code fails sometimes is a sandbox issue. gyroflow_core doesn't actually have read access to the R3D file which contains the gyro data, so the import_gyroflow_data function in gyroflow_core doesn't seem to just load the gyro data from the JSON in this case.

AdrianEddy commented 1 year ago

This shouldn't be a sandbox issue because there's a check if the file can actually be opened and read in this condition you linked

latenitefilms commented 1 year ago

Ummm... well, then I'm not sure why import_gyroflow_data isn't populating the file_metadata.raw_imu and file_metadata.quaternions values properly then.

I might see if there's a way I can just decompress the file_metadata outside of gyroflow_core so that I can better debug what's going on.

latenitefilms commented 1 year ago

It is however getting some data though, just not raw_imu and quaternions, so there's some logic error in there somewhere.

For example, if I add the following logging:

image

I get this:

image

In this case I've granted gyroflow_core access to the R3D file too.

latenitefilms commented 1 year ago

Note to self, I tried adding recompute_gyro():

image

...but didn't help:

image
latenitefilms commented 1 year ago

Doing some more digging into gyroflow_core and this seems to be the issue:

image

It seems that is_compressed is returning false, when in this case it should be returning true.

let is_compressed = obj.get("raw_imu").map(|x| x.is_string()).unwrap_or_default();
latenitefilms commented 1 year ago

I tweaked the is_compressed logic, but still not working:

let is_compressed = obj.get("raw_imu").map(|x| !x.is_string()).unwrap_or(true);
image

...and further down the rabbit hole I go...

latenitefilms commented 1 year ago

Note to self...

image
latenitefilms commented 1 year ago

Note to self...

Interestingly... if I open up FCPX, and import the Gyroflow project, without granting Gyroflow Toolbox sandbox access to the R3D it works correctly. It still works correctly when I press Reload Gyroflow Project too.

std::fs::File::open(&gyro_path).is_err(): true
image

However, if I then delete the Gyroflow Toolbox effect, delete the Gyroflow project at the Finder level, then try and import the R3D file - I get errors.

image

So the problem isn't in the Gyroflow Project/JSON data itself, and it most likely not in how gyroflow_core reads the data. It might be some kind of caching in StabilizationManager?

latenitefilms commented 1 year ago

Ok, I'm not sure why, but I can confirm... I can only get my code to work when gyroflow_core DOESN'T have access to the R3D file. If gyroflow_core can't access the R3D file (due to the macOS sandbox) then my doesGyroflowProjectContainStabilisationData() check works as intended. However, if it does have sandbox access, then it will return NO.

I do think there might be a logic error in is_compressed in gyroflow_core - i.e. I think this might be the opposite way around?

let is_compressed = obj.get("raw_imu").map(|x| x.is_string()).unwrap_or_default();

...and I also think there might be some logic error somewhere in here:

 } else if gyro_path.exists() && blocking {
                    if let Err(e) = self.load_gyro_data(&util::path_to_str(&gyro_path), is_main_video, &Default::default(), progress_cb, cancel_flag) {
                        ::log::warn!("Failed to load gyro data from {:?}: {:?}", gyro_path, e);
                    }
                }
latenitefilms commented 1 year ago

Note to self... turned out that the issue I was having with R3D files was due to sandbox permissions.

This has been resolved in: https://github.com/gyroflow/gyroflow/commit/10c8853a1d0a54aac5538e0122665f558c7eadc2

However, the original issue - i.e. the OpenFX bug - still needs to be resolved.

AdrianEddy commented 11 months ago

Fixed in https://github.com/gyroflow/gyroflow-ofx/commit/33d71a80c0d6cdacc36cdeeb90b779f50535b504#diff-62a6c326342846993ba024144b4abbf39a3bf82efa6a748164b5062ab8254fc4R928 In GyroflowToolbox you can now use StabilizationManager::project_has_motion_data