orchetect / TimecodeKit

The definitive SMPTE timecode library for Swift.
MIT License
91 stars 8 forks source link

Unexpected Result Converting 23.976 Timecode #78

Closed latenitefilms closed 3 months ago

latenitefilms commented 3 months ago

Bug Description, Steps to Reproduce, Crash Logs, Screenshots, etc.

Hi @orchetect !

I've run into a problem with TimecodeKit that I haven't been able to get my head around.

Here's my simple code:

@objc func convertTimecodeStringToFCPXMLString(_ timecodeString: String, frameRate: String) -> String {
    do {
        guard let frameRateEnum = frameRateEnum(from: frameRate) else {
            NSLog("[Marker Toolbox] ERROR - convertTimecodeStringToFCPXMLString - Invalid frame rate string: \(frameRate)")
            return "0s"
        }

        let tc = try Timecode(.string(timecodeString), at: frameRateEnum, base: .max80SubFrames, limit: .max24Hours, by: .clamping)

        NSLog("[Marker Toolbox] AIM: 01:17:54:18 = 116868 frames = 4674.72 seconds")

        NSLog("[Marker Toolbox] convertTimecodeStringToFCPXMLString")
        NSLog("[Marker Toolbox]  - Using frame rate: \(frameRateEnum)")
        NSLog("[Marker Toolbox]  - timecodeString: \(timecodeString)")
        NSLog("[Marker Toolbox]  - tc: \(tc)")
        NSLog("[Marker Toolbox]  - tc frameCount: \(tc.frameCount)")
        NSLog("[Marker Toolbox]  - tc seconds: \(tc.seconds)")
        NSLog("[Marker Toolbox]  - tc rationalValue: \(tc.rationalValue)")
        NSLog("[Marker Toolbox]  - tc fcpxmlStringValue: \(tc.rationalValue.fcpxmlStringValue)")

        return tc.rationalValue.fcpxmlStringValue
    } catch {
        NSLog("[Marker Toolbox] ERROR - convertTimecodeStringToFCPXMLString - Error creating timecode: \(error)")
        return "0s"
    }
}

If I feed in 01:17:54:18 at 23.976fps I expect the output to be 116868 frames and 4674.72 seconds.

However, I get this:

[Marker Toolbox] AIM: 01:17:54:18 = 116868 frames = 4674.72 seconds
[Marker Toolbox] convertTimecodeStringToFCPXMLString
[Marker Toolbox]  - Using frame rate: 23.976
[Marker Toolbox]  - timecodeString: 01:17:54:18
[Marker Toolbox]  - tc: 01:17:54:18.00
[Marker Toolbox]  - tc frameCount: 112194.0
[Marker Toolbox]  - tc seconds: 54
[Marker Toolbox]  - tc rationalValue: 18717699/4000
[Marker Toolbox]  - tc fcpxmlStringValue: 18717699/4000s

...and I'm not really sure why? What am I misunderstanding?

latenitefilms commented 3 months ago

I've also tried doing this:

@objc func convertTimecodeComponentsToFCPXMLString(_ hours: Int, mins: Int, seconds: Int, frames: Int, frameRate: String) -> String {
    guard let frameRateEnum = frameRateEnum(from: frameRate) else {
        NSLog("[Marker Toolbox] ERROR - convertTimecodeStringToFCPXMLString - Invalid frame rate string: \(frameRate)")
        return "0s"
    }

    let tc = Timecode(.components(h: hours, m: mins, s: seconds, f: frames), at: frameRateEnum, base: .max80SubFrames, limit: .max24Hours, by: .clamping)

    NSLog("[Marker Toolbox] AIM: 01:17:54:18 = 116868 frames = 4674.72 seconds")

    NSLog("[Marker Toolbox] convertTimecodeStringToFCPXMLString")
    NSLog("[Marker Toolbox]  - Using frame rate: \(frameRateEnum)")
    NSLog("[Marker Toolbox]  - hours: \(hours)")
    NSLog("[Marker Toolbox]  - mins: \(mins)")
    NSLog("[Marker Toolbox]  - seconds: \(seconds)")
    NSLog("[Marker Toolbox]  - frames: \(frames)")
    NSLog("[Marker Toolbox]  - tc: \(tc)")
    NSLog("[Marker Toolbox]  - tc frameCount: \(tc.frameCount)")
    NSLog("[Marker Toolbox]  - tc seconds: \(tc.seconds)")
    NSLog("[Marker Toolbox]  - tc rationalValue: \(tc.rationalValue)")
    NSLog("[Marker Toolbox]  - tc fcpxmlStringValue: \(tc.rationalValue.fcpxmlStringValue)")

    return tc.rationalValue.fcpxmlStringValue
}

But same result:

[Marker Toolbox] AIM: 01:17:54:18 = 116868 frames = 4674.72 seconds
[Marker Toolbox] convertTimecodeStringToFCPXMLString
[Marker Toolbox]  - Using frame rate: 23.976
[Marker Toolbox]  - hours: 1
[Marker Toolbox]  - mins: 17
[Marker Toolbox]  - seconds: 54
[Marker Toolbox]  - frames: 18
[Marker Toolbox]  - tc: 01:17:54:18.00
[Marker Toolbox]  - tc frameCount: 112194.0
[Marker Toolbox]  - tc seconds: 54
[Marker Toolbox]  - tc rationalValue: 18717699/4000
[Marker Toolbox]  - tc fcpxmlStringValue: 18717699/4000s

What am I misunderstanding or is there a bug in the maths?

latenitefilms commented 3 months ago

Actually... I'm am idiot, I think this is wrong 01:17:54:18 = 116868 frames = 4674.72 seconds - I think I incorrectly had 25fps. Let me check.

latenitefilms commented 3 months ago

Ok at 23.976fps, it should actually be: 01:17:54:18 = 112194 frames = 4679.42 seconds

latenitefilms commented 3 months ago

Ignore - it does look like TimecodeKit is behaving correctly. There must be something wrong either in my code, or Final Cut Pro is doing some very weird. Apologies for the noise!