I saw your original posts about the .srt importer and wanted to chime in, but didn’t have time to write up an example back then. (I’m following up on your post in the 25->50fps thread, and figured it would be more relevant over here.)
The drift is due to frame math and is not related to Shotcut. All editors would do the same thing. When the math is round-tripped through a frame number, subtitles will remain frame-accurate even at the two-hour mark (which is the furthest I’ve tested them so far).
The trick is to not look at the .srt timings as if they are the authority. The output format is the authority, and whatever its frame rate is must be the king. All else must be conformed to match it if frame alignment is going to happen. This means converting SRT milliseconds to a frame number, making sure that frame isn’t already used, then converting back to milliseconds. This is standard practice, not Shotcut-specific busywork.
Here is another part of the issue: the Project (the xml in the back-end records whats going on) respects the time (like 00:00:04.956 etc.), but the Editor in the front-end respects the frame numbers.
While the XML file may look like a milliseconds free-for-all (and technically can be), it really isn’t in practice. The milliseconds used in the XML file are usually exact frame boundary timings, and not some random time in the middle of a frame. For all practical purposes, the XML file could have just as effectively used the frame number instead of milliseconds. They are synchronized that closely. The challenge of a .srt to .mlt converter is finding the frames that contain the subtitles and then shifting the .srt timings to the actual frame boundary timings based on the project’s frame rate, all while not double-booking any frames.
Here’s an example SRT file to illustrate:
1
00:00:00,000 --> 00:00:04,004
The first subtitle with 29.97fps timings.
2
00:00:05,480 --> 00:00:08,000
The second subtitle with 25fps timings.
Conversion from .srt to .mlt would look something like this:
Sort ( Subtitles In SrtFile By TimeIn )
PrevFrameOut = -1
ForEach ( Subtitle In SrtFile ) {
FrameIn = Truncate(Subtitle.TimeIn.Milliseconds * fpsNum / fpsDen / 1000)
If ( FrameIn <= PrevFrameOut ) FrameIn = PrevFrameOut + 1
TempOut = Min(Subtitle.TimeOut.Milliseconds, NextSubtitle.TimeIn.Milliseconds - 1)
FrameOut = Truncate(TempOut * fpsNum / fpsDen / 1000)
If ( FrameIn - PrevFrameOut > 1 ) {
BlankLength = Ceiling((FrameIn - PrevFrameOut - 1) * 1000 * fpsDen / fpsNum) / 1000
// Write a MLT "/mlt/playlist/blank" element for BlankLength
}
TimeIn = Ceiling(FrameIn * 1000 * fpsDen / fpsNum) / 1000
TimeOut = Ceiling(FrameOut * 1000 * fpsDen / fpsNum) / 1000
// Write a MLT "/mlt/playlist/entry" element with
// "in" = 0.000 and "out" = TimeOut - TimeIn
PrevFrameOut = FrameOut
}
Here are the MLT clip timings at two different frame rates:
NTSC - 30000/1001
- Subtitle 1: Frames 0 - 120, time 0.000 - 4.004
- Blank: 1.435 s
- Subtitle 2: Frames 164 - 239, time 5.473 - 7.975
PAL - 25000/1000
- Subtitle 1: Frames 0 - 100, time 0.000 - 4.000
- Blank: 1.440 s
- Subtitle 2: Frames 137 - 200, time 5.480 - 8.000
The millisecond numbers change, but they’re still accurately pointing to the start of the frame (in the native frame rate) that contains the subtitle timing in question, and none of the frames are double-booked.