Problem with calculated timestamps

I am currently using Shotcut version 22.12.21 on Windows 10

I found the same problem I got in a discussion which is from 2020: Shotcut is tripping calculating timecodes - #21 by shotcut

So the problem is: I want to write a code that automatically creates an .mlt file with cuts on the exact position where they need to be. Sometimes they are, but sometimes the cuts are a few frames before or after.
It seems like there is still a problem in shotcut with calculating the correct timestamps. Is there a pattern, which I can use for my code so even if the cuts would be actually wrong, they are correct inside shotcut? Or is there alreaydy a fix or another workaround? If not I would have to use another cutting-tool where the timecodes are correct.

I hope someone can help me out there.

Thanks in advance

Maybe there is a difference in the timecode calculation. You do not state what your project frame rate is and whether you are calculating the drop frame. To help you understand the timecodes better, I suggest you first use Shotcut to make the cuts you want, see what timecode Shotcut calculates, and then make sure your own math agrees with it.

If all the timecode stuff is too complicated, Shotcut also understands frame numbers or a time indication with a decimal point for seconds.

For example, to indicate the 100th frame in 60fps video, you could use:

  • Frames: 100
  • Time: 00:00:01.67
  • Timecode: 00:00:01:39

Note that timecodes start with 00:00:00:00, not 00:00:00:01

If you are confident that the frame is being indicated correctly, then maybe the problem is that Shotcut is not able to seek accurately in your files. To test that, and understand better, you could use Shotcut’s “Convert…” feature on one of your clips and then try using that in your testing. If you get the correct frame cuts on the converted files, and not on the original files, then that is probably the problem.

Also make sure that all timestamps are calculated as time since zero (00:00:00.000), and not as an addition to the previous clip’s end time.

I did an example now. The video used in my example has the following frames (including) for each clip:

clip 1: Frame 0 to 365
clip 2: Frame 366 to 415
clip 3: Frame 416 to 444
clip 4: Frame 445 to 795
clip 5: Frame 796 to 819
clip 6: Frame 820 to 940
clip 7: Frame 941  to 965
clip 8: Frame 966 to 990
clip 9: Frame 991 to 1019
clip 10: Frame 1020 to 1036
clip 11: Frame 1037 to 1040
clip 12: Frame 1041 to 1480
clip 13: Frame 1481 to 2272

The video a framerate of 29.97 and 2273 frames in total. This is what Shotcut calculates:

<entry producer="chain1" in="00:00:00.000" out="00:00:12.177"/>
<entry producer="chain2" in="00:00:12.211" out="00:00:13.846"/>
<entry producer="chain3" in="00:00:13.879" out="00:00:14.813"/>
<entry producer="chain4" in="00:00:14.846" out="00:00:26.523"/>
<entry producer="chain5" in="00:00:26.557" out="00:00:27.324"/>
<entry producer="chain6" in="00:00:27.357" out="00:00:31.361"/>
<entry producer="chain7" in="00:00:31.394" out="00:00:32.195"/>
<entry producer="chain8" in="00:00:32.228" out="00:00:33.029"/>
<entry producer="chain9" in="00:00:33.063" out="00:00:33.997"/>
<entry producer="chain10" in="00:00:34.030" out="00:00:34.564"/>
<entry producer="chain11" in="00:00:34.597" out="00:00:34.697"/>
<entry producer="chain12" in="00:00:34.731" out="00:00:49.377"/>
<entry producer="chain13" in="00:00:49.410" out="00:01:15.814"/>

And this is what my java code calculates:

<entry producer="chain1" in="00:00:00.000" out="00:00:12.178"/>
<entry producer="chain2" in="00:00:12.212" out="00:00:13.847"/>
<entry producer="chain3" in="00:00:13.880" out="00:00:14.814"/>
<entry producer="chain4" in="00:00:14.848" out="00:00:26.526"/>
<entry producer="chain5" in="00:00:26.559" out="00:00:27.327"/>
<entry producer="chain6" in="00:00:27.360" out="00:00:31.364"/>
<entry producer="chain7" in="00:00:31.398" out="00:00:32.198"/>
<entry producer="chain8" in="00:00:32.232" out="00:00:33.033"/>
<entry producer="chain9" in="00:00:33.066" out="00:00:34.000"/>
<entry producer="chain10" in="00:00:34.034" out="00:00:34.567"/>
<entry producer="chain11" in="00:00:34.601" out="00:00:34.701"/>
<entry producer="chain12" in="00:00:34.734" out="00:00:49.382"/>
<entry producer="chain13" in="00:00:49.416" out="00:01:15.809"/>

This is my code for calculating the timecodes at a given frame and framerate:

public static String timecode(int frameNumber, double fps) {
         double total_seconds = frameNumber / fps;
         int hours = (int) (total_seconds / 3600);
         int minutes = (int) ((total_seconds % 3600) / 60);
         int seconds = (int) (total_seconds % 60);
         int milliseconds = (int) ((total_seconds * 1000) % 1000);
         return String.format("%02d:%02d:%02d:%03d", hours, minutes, seconds, milliseconds);
     }

So the last timecode in chain13 in my version is calculated kind of like this:
Frame 2272 / FPS 29.97 = 75,8091424758091…
So 1 minute + 15 seconds and 809 milliseconds (= 75,809 seconds). But why does Shotcut calculate 814 milliseconds. This even gets worse, the longer the video is. Can someone who knows the answer, give me a correct java code for shotcuts variant of calculating these timecodes too?

Here is the code. If you attempt to state how it is wrong, bear in mind that it was written to make unit tests pass the enforce that a conversion from frame count to timecode and back to frame count (see other code in the same file) gives the same count for every 32-bit signed int. Any suggestion on your part must be in the form of a pull request that passes the unit tests included in the repo:

This is the function for calculating the clock time which you are doing above

Also, a nitpick, but might matter for longer clips: 29.97 is not precise. The actual framerate for 29.97 is:

30 x 1000 / 1001 = 29.97002997002997

I think there is still a problem, i am not sure what it is. This is my new timecode code:

public static String timecode(int frameNumber, double fps) {
        int hours, mins;
        double secs;
        int save_frames = frameNumber;

        hours = (int) (frameNumber / (fps * 3600));
        frameNumber -= (int) (hours * 3600 * fps);

        mins = (int) (frameNumber / (fps * 60));
        if (mins == 60) { // floating point error
            ++hours;
            frameNumber = save_frames - ((int) (hours * 3600 * fps));
            mins = 0;
        }
        save_frames = frameNumber;
        frameNumber -= (int) (mins * 60 * fps);

        secs = frameNumber / fps;
        if (secs >= 60.0) { // floating point error
            ++mins;
            frameNumber = save_frames - ((int) (mins * 60 * fps));
            secs = frameNumber / fps;
        }

        return String.format("%02d:%02d:%06.3f", hours, mins, secs).replace(",", ":");
    }

This is what my code calculates now:

<entry producer="chain0" in="00:00:00.000" out="00:00:12.179"/>
<entry producer="chain1" in="00:00:12.212" out="00:00:13.847"/>
<entry producer="chain2" in="00:00:13.881" out="00:00:14.815"/>
<entry producer="chain3" in="00:00:14.848" out="00:00:26.527"/>
<entry producer="chain4" in="00:00:26.560" out="00:00:27.327"/>
<entry producer="chain5" in="00:00:27.361" out="00:00:31.365"/>
<entry producer="chain6" in="00:00:31.398" out="00:00:32.199"/>
<entry producer="chain7" in="00:00:32.232" out="00:00:33.033"/>
<entry producer="chain8" in="00:00:33.066" out="00:00:34.001"/>
<entry producer="chain9" in="00:00:34.034" out="00:00:34.568"/>
<entry producer="chain10" in="00:00:34.601" out="00:00:35.669"/>
<entry producer="chain11" in="00:00:35.702" out="00:03:50.317"/>
<entry producer="chain12" in="00:03:50.350" out="00:03:51.184"/>
<entry producer="chain13" in="00:03:51.218" out="00:07:49.082"/>

Don’t mind that extra line thats just because I added another one for a test. Thanks in advance.I just translated the “time_clock_from_frames”" function to java ad I testet the 30*1000/1001 fps variant but also the 29.97 variant

Maybe this is a result of different floating point math implementations in the C vs. Java compilers. You do not need to make the MLT XML with time format exactly the same as Shotcut. Shotcut uses time clock format to try to retain fidelity when changing frame rate while changing Video Mode. If you want you can just write frame counts.

So I can just write 00:00:12:06 instead of 00:00:12:177 for the mlt in Shotcut? But then I anyways need to calculate the hours, minutes and seconds. There will still be different calculations, at least it could be bad for very very long videos. Now there is just an offset of 5 milliseconds in an 7:50 minutes video, but there will be a whole second for videos of many hours, I mean I could try at least. Thank you

Yes, what you showed is called SMPTE timecode. That works as well. Shotcut (MLT) decides if it is timecode or time-clock (with milliseconds) format based on whether there is a period character. What I meant is that for this time value you can also write only 365, which implies as 0-based frame count. This is accepted when there is no colon character in the time string.

By the way, I found out that my new timecode code was correct. I just created the wrong values for frame_rate_num and frame_rate_den in the .mlt file. I found it out by creating a project from the original video and inspected all differences from what I created. Now the question is, how can I automatically generate or get the actual frame_rate_num and frame_rate_den value despite by creating a project and copy and paste these values into my generator by hand?

num = numerator, den = denominator
I suggest to stick to standard frame rates, but if you want to do something like Automatic Video Mode, run melt -consumer xml {input-filename} or melt -consumer xml:{output-filename} {input-filename} to get the the <profile> tag.