latenitefilms / GyroflowToolbox

Allows you to import Gyroflow Projects into Apple's Final Cut Pro
https://gyroflowtoolbox.io
MIT License
24 stars 1 forks source link

29.97 Compound Clip fails in 23.98 Project #32

Open latenitefilms opened 2 months ago

latenitefilms commented 2 months ago

Reported by Dustin Svehlak via email.

Let's say we have a 29.97fps GoPro Clip. We create a 29.97fps Compound Clip, and apply Gyroflow Toolbox - everything works great! If we apply it to a 29.97fps Project/Timeline, it works as expected. However, if we put this 29.97fps Compound Clip in a 23.98 Project/Timeline, things break.

I believe this is due to how Final Cut Pro handles Rate Conform.

image

As a possible workaround, applying an Automatic Speed Effect to the Compound Clip will fix it - but may not be visually what the user wants, as it'll now be Slow 80%.

image

Or you could render out the Compound Clip and import it back in (which is less than ideal - and goes against the whole reason Gyroflow Toolbox exists in the first place).

This MIGHT be possible to fix - although I'm not sure that FxPlug gives us the information we need to do the maths.

FWIW - I've tried using a Synchronised Clip instead, creating another Compound Clip with the Automatic Speed Effect applied, etc but none of these workarounds work.

For reference, here's our current method of detecting the current frame:

    //---------------------------------------------------------
    // Get the frame to render:
    //---------------------------------------------------------
    CMTime timelineFrameDuration = kCMTimeZero;
    timelineFrameDuration = CMTimeMake( [timingAPI timelineFpsDenominatorForEffect:self],
                                       (int)[timingAPI timelineFpsNumeratorForEffect:self] );

    CMTime timelineTime = kCMTimeZero;
    [timingAPI timelineTime:&timelineTime fromInputTime:renderTime];

    CMTime startTimeOfInputToFilter = kCMTimeZero;
    [timingAPI startTimeForEffect:&startTimeOfInputToFilter];

    CMTime startTimeOfInputToFilterInTimelineTime = kCMTimeZero;
    [timingAPI timelineTime:&startTimeOfInputToFilterInTimelineTime fromInputTime:startTimeOfInputToFilter];

    Float64 timelineTimeMinusStartTimeOfInputToFilterNumerator = (Float64)timelineTime.value * (Float64)startTimeOfInputToFilterInTimelineTime.timescale - (Float64)startTimeOfInputToFilterInTimelineTime.value * (Float64)timelineTime.timescale;
    Float64 timelineTimeMinusStartTimeOfInputToFilterDenominator = (Float64)timelineTime.timescale * (Float64)startTimeOfInputToFilterInTimelineTime.timescale;

    Float64 frame = ( ((Float64)timelineTimeMinusStartTimeOfInputToFilterNumerator / (Float64)timelineTimeMinusStartTimeOfInputToFilterDenominator) / ((Float64)timelineFrameDuration.value / (Float64)timelineFrameDuration.timescale) );

    //---------------------------------------------------------
    // Calculate the Timestamp:
    //---------------------------------------------------------
    Float64 timelineFpsNumerator    = [timingAPI timelineFpsNumeratorForEffect:self];
    Float64 timelineFpsDenominator  = [timingAPI timelineFpsDenominatorForEffect:self];
    Float64 frameRate               = timelineFpsNumerator / timelineFpsDenominator;
    Float64 timestamp               = (frame / frameRate) * 1000000.0;
    params.timestamp                = [[[NSNumber alloc] initWithFloat:timestamp] autorelease];

See: Understanding time in FxPlug

@AdrianEddy - Any ideas?

latenitefilms commented 2 months ago

When adding this debugging code:

NSLog(@"---------------------------------");
NSLog(@"timelineFrameDuration: %.2f seconds", CMTimeGetSeconds(timelineFrameDuration));
NSLog(@"timelineTime: %.2f seconds", CMTimeGetSeconds(timelineTime));
NSLog(@"startTimeOfInputToFilter: %.2f seconds", CMTimeGetSeconds(startTimeOfInputToFilter));
NSLog(@"startTimeOfInputToFilterInTimelineTime: %.2f seconds", CMTimeGetSeconds(startTimeOfInputToFilterInTimelineTime));
NSLog(@"timelineTimeMinusStartTimeOfInputToFilterNumerator: %f", timelineTimeMinusStartTimeOfInputToFilterNumerator);
NSLog(@"timelineTimeMinusStartTimeOfInputToFilterDenominator: %f", timelineTimeMinusStartTimeOfInputToFilterDenominator);
NSLog(@"frame: %f", frame);
NSLog(@"timelineFpsNumerator: %f", timelineFpsNumerator);
NSLog(@"timelineFpsDenominator: %f", timelineFpsDenominator);
NSLog(@"frameRate: %f", frameRate);
NSLog(@"timestamp: %f", timestamp);
NSLog(@"---------------------------------");

For the first frame of the 29.97fps Compound Clip I get:

timelineFrameDuration: 0.03 seconds
timelineTime: 0.00 seconds
startTimeOfInputToFilter: 37960.22 seconds
startTimeOfInputToFilterInTimelineTime: 0.00 seconds
timelineTimeMinusStartTimeOfInputToFilterNumerator: 0.000000
timelineTimeMinusStartTimeOfInputToFilterDenominator: 8100000000.000000
frame: 0.000000
timelineFpsNumerator: 30000.000000
timelineFpsDenominator: 1001.000000
frameRate: 29.970030
timestamp: 0.000000

For the first frame of the 23.98fps Project/Timeline I get:

timelineFrameDuration: 0.03 seconds
timelineTime: 0.00 seconds
startTimeOfInputToFilter: 37960.22 seconds
startTimeOfInputToFilterInTimelineTime: 0.00 seconds
timelineTimeMinusStartTimeOfInputToFilterNumerator: 0.000000
timelineTimeMinusStartTimeOfInputToFilterDenominator: 8100000000.000000
frame: 0.000000
timelineFpsNumerator: 30000.000000
timelineFpsDenominator: 1001.000000
frameRate: 29.970030
timestamp: 0.000000

So maybe what is needed is a way to enter the "Project/Timeline Frame Rate" in the Effect, and then we can scale the frame number accordingly?

latenitefilms commented 1 month ago

The Final Cut Pro team confirm:

We don’t currently have a method to do what you’re looking for.

randomeizer commented 1 month ago

Haha, so helpful.