Shotcut Quick Subtitle .srt to .mlt converter

Run it, pick .srt subtitle file, then it will generate a Shotcut .mlt project file in the same folder. All the subtitle dialogs will become text clips in V2 track.

If you use it for music lyrics like .lrc or .ass files etc, use an online converter to convert it to .srt subtitle file.

The .srt must be simple text subtitle, without fancy formattings.

If you need to change font color or font size etc. use text editor search/batch replace in result .mlt file.



Really cool! :+1:

Can’t wait to test it out!

Can you explain this step further? I don’t understand.

So I tested this with 2 srt subtitles I have. There is an issue where they start okay but then after 30 seconds the subtitles become more and more delayed. It could be that it seems that the mlt file that is created defaults to 1080p 30fps and the srt files I had were timed to videos that were 23.98fps. You might have to have a screen that appears when the srt is chosen that lets the user set the screen resolution and fps to match the video.

Also, it would be nice to allow the user to name the mlt file that will be created. It’s not like your proxy script where the name for the mlt file was important for the proxy. It would help cover if the user just happens to have an mlt file created for the project that is the same as the srt file seeing as how srt files have to have the same name as the video file it’s for in order for a video player to detect it.

As you can see from the screenshot, open the.mlt showing shotcut:pointsize is 28, so the subtitle will be font size 28. If you need a bigger font, use “replace all text” function in any text editor, replace all of them to 36 for example. There you go.

This same procedure applies to change font color, changing positions etc. etc.

Inside the .mlt file, everything is logged using “milliseconds” not “number of frame”, so the fps number doesn’t really matter and doing nothing. There maybe something else, I will look into it later tomorrow. Time for my lunar new year!

Please give me an estimate, like, after how many lines it showed then you got eg. 0.1 seconds delay, something like that.

I am thinking a “placeholder” problem inside the .mlt may causes the delay, I only tested with 1 minutes videos and it was fine… will check it out later.

The subtitler works pretty well.
Changed the font size, used SP to position the subs.
The only issue I found is that if one wants to subtitle an entire movie it might take all night to generate the mlt.
I started a subtitle generating process for a 1 hr 23 min movie 5 minutes ago. Will report the end time.
Took about 18 minutes +/-.

The subtitle mlt for the movie is 1.60 MB. Shotcut will not load it. Displays a Failed to open message.

LVK subtitled

1 Like

The .mlt this tool generates is very light weight already. There is no dumb rubbish in it. I didn’t try a subtitle that big. But if it failed to load, maybe there is shotcut limitation.

The speed issue will be fixed. This quick coding is not optimised I am aware, and I have ideas how to speed it up bigly.

Seems to work OK, although only tried it on a short srt file.
As to different frame rates, could the drift that @DRM is referring to be time step related?

What I mean is, at 25 FPS, everything is in 40mS steps, whereas he is using 23.98 fps (41.7mS)?
The error will get bigger and bigger.

A suggestion, why not prompt the user for things like, font size, colour and position.
At this point, the frames per second can also be entered and timings calculated based on that.

What is also important in subtitles is italics for some words, although it would be difficult
to implement changing from regular to italics only for certain words.

Seems there is no Shotcut limitation.
I loaded the large subtitle mlt. Checked the app log for errors. Found this.

[Error ] [producer_xml] parse fatal: xmlParseEntityRef: no name row: 11689 col: 11

Looked at the mlt. This is the error.


Replaced the & with and, saved and loaded the mlt. It worked.
There is substantial drift as the video progresses.


Wonder how many other “special” characters will cause it to fail?
Thinking about ~ " < > @ although the tilda (~) is not often used.

Have you tried “escaping” the & with a backslash ?
Sorry can’t type it as the forum software filters it out.

That’s the first thing I tried. Did not work.
When I open the mlt in SC, put the & back and save, it works. Then, when I use that mlt to sub the video everything is completely out of whack.

Thanks guys for all the testing. This release is a concept/please-work version, I quickly wrote it and put it here without debugging yet (because yesterday I only got like 3 hours spare before the lunar new year party)

The delay is most likely caused by frame placeholder issue, means a 0.001 second longer clip will occupy a whole frame (a whole frame is 0.033 second etc. ) . I have an idea to fix it.

I’ll add a line of code to remove some special characters.

I’ll speed up the program like 1000 fold for large subtitles.

Later today.

1 Like

@Paul2 @sauron @DRM

Okey, let you guys know that it has been updated, download it again if you need it.


  1. Move the subtitle to V2, leave a blank V1, so you can add actually video under the text.
  2. Speed up the conversion 100+ times. Now full movie subtitle can be created in seconds.
  3. Use regex to remove lots of fancy formattings and replaced the special marks like ><&’ etc to xml accepted letters.
  4. Majorly fixed the drift issue. But due to Shotcut clips using timestamps relative to each other(instead of a global time start from the beginning) and some frame length holding issues, there will still be some time drifts after few hundreds of dialogs. (Luckily with “ripple trim & drag” button it can be easily adjusted by yourself)

Now this little project is marked as final.

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:

00:00:00,000 --> 00:00:04,004
The first subtitle with 29.97fps timings.

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.

1 Like

I totally understand what you are saying. I spent hours dug deep into this. Your example code is very close to one of my test codes. (there are hidden problems in it, it will drift. It ends up that I need a “master offset” to log and decide if the next clip should be 1 frame longer or 1 frame shorter)

I still think it is Shotcut’s fault, as when users change fps (video mode), even Shotcut editor itself can not hold the same timing. (which may not be called a bug, but it is unusual for a video editor)

A 5:00 minutes multi-clip track + 5:00 minutes song, video clips sync with audio beats.
If I change video fps to 23.98, the video track length will become something like 5:02 (while audio is still 5:00)
If I change video fps again to 50fps, the video track may become like 5:05, and audio is completely out-of-sync.
More tiny clips in the track, the drift will be more severe.

So there is no way to make a subtitle (or multiple clips) that sync well for all fps. This issue affects all the users who need accurate audio-video sync and changing fps.

Deep down, it is how Shotcut editor decide where the 10th clip starts, NOT BY adding early 9 clips length “time” together and pick the next frame (clip timing will be accurate across all fps if it’s in this way)

Instead, Shotcut calculates it by converting 9 clips length time into frame number one-by-one, and sum up the total frame number.

1 Like

This looks like we’re talking about two different problems. I was only looking at getting subtitle clips onto the timeline without drift in whatever the project’s current FPS is. Changing FPS in the middle of a project is a recipe for disaster in all cases, so I wasn’t concerned about that use case.

For clarification, where/how is this FPS change happening? Does this mean your tool loads text clips into an MLT file that’s configured for 29.97fps, and then the video mode of that MLT file is changed to 23.98? Or is a project created at 29.97fps, it’s changed to 23.98, and then the subtitle clips are loaded on last?

Based on what you’re saying, it sounds like there is no way to change FPS reliably in the middle of a project, which has the downstream effect of making subtitle sync impossible. So long as FPS doesn’t change, subtitles can sync up at any frame rate just fine.

hell yea, there are multiple problems in the chain. I understand your saying and I think I am over that issue already, so I move on to next problem I am facing (the in/out issue, frame milliseconds issue, .srt time to “frame time” adding up offset issue, are handled or partly handled)

Hell yea again. but in real life, this happens quite often. I was forced to change my project video mode a few times during the editing for various reasons.

Now I remember I did noticed background music out-of-sync after change fps. But at that time I thought I miss-clicked something so I just fixed it manually.

So far, I can generate the perfectly timed subtitle .mlt for certain fps (1000fps\100fps\50fps\25fps), not others. But people use it for movie film 24fps, or youtube music lyrics 60fps etc. So fps change happens.
FYI, open a .mlt as a clip is the same as change fps.

One thing that confuses me is how Shotcut editor handle the frame length. I did lots of tests, from the results I know Shotcut uses a frame time around 4 digits right to decimal. eg. 30fps video a frame is 33.3333 milliseconds (00:00:00.0333333 round to 00:00:00.033, definitely not 1000/30 ). But if I check the .mlt file timestamp and do the dividing, sometimes it fits 33.33330, sometimes it fits 33.33340. So my generated .mlt will be 1 frame longer or shorter randomly, it will drift a little after dozens of clips. Anyway, it doesn’t matter, I am not gonna update my “.srt to .mlt” tool. It is good enough atm.

What matters is, I wish the Shotcut clip position could honor the “time” but not “frame count”, A user place a clip at 04:12, it should always stay at 04:12, even changing the “video mode” it should stay at closest frame near 04:12, not like drifts few seconds away.

1 Like

Thanks for this. Unfortunately the actual download is reported to be malicious by 8 scan engines. Can you please check if that are false positives. I really like to use it.

How many reported safe?

Since I made some code changes after I uploaded it, I lost the “local copy” that is same to the website, so I can not tell directly if it has been modified.

To be safe, I simply compile it again, and overwrite the website copy.

From comparing the compressed size of the new and website old, I would say it was clean. (any malware infection/repack will cause the file entropy changed by a lot. This time the compressed size only different by few bytes)

I am 99.99% sure my workstation and server are virus-free. But if you notice my program release any files to the system, let me know asap.(this app is simple portable and standalone, should not inject/change/write anything to the system)