Export Regions as SRT Subtitle - a little help pls

NickHope wrote on 10/18/2009, 6:23 AM
http://www.pixelsplasher.com/_downloads/scripts/Sony.Vegas.export.regions.as.srt.subtitles.for.YouTube.script/Pixelsplasher.com[link] has kindly modified Sony's bundled "Export Regions as Subtitles" script to export as a SubRip .srt subtitle file which can be used for YouTube closed captioning and also to import to DVD authoring packages such as TMGEnc Authoring Works.

There were a couple of bugs in the modified script which I have fixed. Firstly the subtitle count was incorrect from 100-109, 200-209 etc.. Secondly the millisecond count was incorrect.

I have now got it working but the final digit always reads zero. I had a go at getting it to be accurate down the final digit (milliseconds) but my efforts failed.

That much accuracy is not very important but for the sake of completeness, if any of you bright sparks could take a look at it I suspect it would be fairly straightforward to get that working perfectly.

My code is below. Save as a .cs file. The lines that need work are 62-86.

Thanks!


/**
* You can use this script to export Vegas regions in the standard .srt format
* for use in YouTube and various DVD Authoring programs.
*
* To use this script:
*
* 1) Create named Vegas regions.
* 2) Confirm no overlapped regions.
* 3) Vegas>tools>scripting>run script>ExportRegionsAsSRTSubtitles.cs; save
* 4) Import into YouTube or your DVD Authoring program.
*
* Revision Date: February 25, 2009.
* Added .srt format support by Pixelsplasher (www.pixelsplasher.com)
* for updates, visit http://www.pixelsplasher.com/_downloads/scripts/Sony.Vegas.export.regions.as.srt.subtitles.for.YouTube.script/
*
* Revision Date: October 18, 2009 by Nick Hope nick@bubblevision.com
* Fixed incorrect numbering for subtitles 101-109, 201-209 etc.
* Fixed incorrect millisecond count
* Removed ability to save to DVD Architect .sub format (to make it easier to read and edit the script). Sony's bundled script can do that anyway.
* Note: Script may benefit from accuracy in the final digit (milliseconds) which currently always reads zero. My efforts failed.
**/
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Windows.Forms;
using System.Globalization;
using Sony.Vegas;

public class EntryPoint
{
Vegas myVegas;

public void FromVegas(Vegas vegas) {
myVegas = vegas;

String projName;

String projFile = myVegas.Project.FilePath;
if (String.IsNullOrEmpty(projFile)) {
projName = "Untitled";
} else {
projName = Path.GetFileNameWithoutExtension(projFile);
}

String exportFile = ShowSaveFileDialog("SubRip (*.srt)|*.srt|" +
"Vegas Region List (*.txt)|*.txt",
"Save Regions as Subtitles", projName);

if (null != exportFile) {
String ext = Path.GetExtension(exportFile);
// Works even if prev lastIndexOf fails or if the ext
// contains but not equal to "sub"
if ((null != ext) && (ext.ToUpper() == ".SRT"))
ExportRegionsToSRT(exportFile);
else
ExportRegionsToTXT(exportFile);
}
}


String TimeToStringSRT(Timecode time) {
String[] decimalSeparators = new String[] {CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator};
Int64 nanosPerCentisecond = 100000;

// first round the time to the nearest centisecond
Int64 nanos = time.Nanos;
Double tmp = ((Double) nanos / (Double) nanosPerCentisecond) + 0.5;
nanos = (Int64) tmp * nanosPerCentisecond;
time = Timecode.FromNanos(nanos);

// {"hh:mm:ss", "ddd"}
String[] rgTime = time.ToString(RulerFormat.Time).Split(decimalSeparators, StringSplitOptions.None);
StringBuilder sbRes = new StringBuilder();

sbRes.Append(rgTime[0]);
sbRes.Append(':');

int iCentiseconds = (int) Math.Round(Double.Parse(rgTime[1]));

sbRes.Append(((iCentiseconds / 100) >> 0 ) % 10);
sbRes.Append(((iCentiseconds / 10) >> 0 ) % 10);
sbRes.Append(((iCentiseconds / 1) >> 0 ) % 10);

return sbRes.ToString();
}

StreamWriter CreateStreamWriter(String fileName, Encoding encoding) {
FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
StreamWriter sw = new StreamWriter(fs, encoding);
return sw;
}

void ExportRegionsToSRT(String exportFile) {
StreamWriter streamWriter = null;
try {
streamWriter = CreateStreamWriter(exportFile, System.Text.Encoding.Unicode);
//streamWriter.WriteLine("Start\tEnd\tLength\tName");
int iSubtitle = 1;
foreach (Region region in myVegas.Project.Regions) {
StringBuilder tsv = new StringBuilder();
tsv.Append( iSubtitle );
tsv.Append('\n');
tsv.Append( TimeToStringSRT( region.Position ));
tsv.Append(' ');
tsv.Append('-');
tsv.Append('-');
tsv.Append('>');
tsv.Append(' ');
tsv.Append( TimeToStringSRT( region.End ));
tsv.Append('\n');
tsv.Append(region.Label);
streamWriter.WriteLine(tsv.ToString());
streamWriter.WriteLine();
iSubtitle++;
}
} finally {
if (null != streamWriter)
streamWriter.Close();
}
}

void ExportRegionsToTXT(String exportFile) {
StreamWriter streamWriter = null;
try {
streamWriter = CreateStreamWriter(exportFile, System.Text.Encoding.Unicode);
streamWriter.WriteLine("Start\tEnd\tLength\tName");
foreach (Region region in myVegas.Project.Regions) {
StringBuilder tsv = new StringBuilder();
tsv.Append( region.Position.ToString( RulerFormat.Time ));
tsv.Append('\t');
tsv.Append( region.End.ToString( RulerFormat.Time ));
tsv.Append('\t');
tsv.Append( region.Length.ToString( RulerFormat.Time ));
tsv.Append('\t');
tsv.Append(region.Label);
streamWriter.WriteLine(tsv.ToString());
}
} finally {
if (null != streamWriter)
streamWriter.Close();
}
}

// an example filter: "PNG File (*.png)|*.png|JPEG File (*.jpg)|*.jpg"
String ShowSaveFileDialog(String filter, String title, String defaultFilename) {
SaveFileDialog saveFileDialog = new SaveFileDialog();
if (null == filter) {
filter = "All Files (*.*)|*.*";
}
saveFileDialog.Filter = filter;
if (null != title)
saveFileDialog.Title = title;
saveFileDialog.CheckPathExists = true;
saveFileDialog.AddExtension = true;
if (null != defaultFilename) {
String initialDir = Path.GetDirectoryName(defaultFilename);
if (Directory.Exists(initialDir)) {
saveFileDialog.InitialDirectory = initialDir;
}
saveFileDialog.DefaultExt = Path.GetExtension(defaultFilename);
saveFileDialog.FileName = Path.GetFileName(defaultFilename);
}
if (System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog()) {
return Path.GetFullPath(saveFileDialog.FileName);
} else {
return null;
}
}
}

Comments

NickHope wrote on 11/8/2009, 10:44 PM
OK, so short of a full fix, how would we change line 83 to simply append a number "5" to minimise the error so we can get this published?
MarkWWWW wrote on 11/10/2009, 5:45 AM
I'm no expert at this stuff, but it seems that you are expecting the output to be accurate to milliseconds? This is never going to happen with the script as it is presented because the script takes steps specifically to ensure that it won't.

Have a look at lines 66-70. Here the times are rounded to centiseconds, i.e. units of one hundredth of a second (=10 milliseconds). Because of this you are always going to get a zero in the last place of your millisecond output rather than the correct figure.

In order to get it to output accurate to milliseconds you are going to need to remove the (for your purposes) overstrong rounding routine and replace it with one that rounds to the nearest millisecond, rather than the nearest 10 milliseconds.

Unfortunately, as I say, I am not enough of an expert to actually do this for you. But I'm sure it would be pretty simple for someone familiar with Vegas scripting to do this for you. (The obvious choice would be the original author of the script.)

But this raises the question of whether you really need to be accurate to milliseconds. There's no real point in a subtitle timing being more than field- or even frame-accurate. In PAL land, where I am, this would require only an accuracy of 20 or 40 ms (20 if you need to be field accurate, 40 if you only need frame accuracy) and in NTSC land it would be approximately 33 or 17 ms, still more than a centisecond. I suspect that this is the reason the original writer of the script decided to work in centiseconds - he/she knew that there was no point in working to any greater accuracy since it couldn't improve the accuracy of the output in any meaningful way.

But I don't see why you shouldn't work in milliseconds if you'd prefer, it just won't make any difference to the outcome. Best of luck in finding someone who can make this change for you.

Mark
NickHope wrote on 11/20/2009, 8:50 AM
Thanks Mark. An improved rounding routine was basically what I was asking for. I realise that it's pretty irrelevant, and in my case it's totally irrelevant as my last digit is always zero because I work in 50i and I have quantize to frames on.

Anyway, Pixelsplasher has kindly fixed the script and updated it. Download from here:

http://www.pixelsplasher.com/_downloads/scripts/Sony.Vegas.export.regions.as.srt.subtitles.for.YouTube.script/
Sirio wrote on 12/29/2015, 11:21 AM
Hello
Good idea this script, it works better than the built-in script of Vegas 13 which export regions in .sub.
However I don't understand how to make an "Carriage Return Line Feed". Which special character did I have to put in my region name to split my line in two lines?
Thanks.
Sirio wrote on 12/30/2015, 1:55 PM
I found the solution:
I have just write to the programmer of Subtitle Edit to allow in the "replace" function to replace a special character of your choice by a "\n" (new line). This guy did it in the new beta release in the "Edit -> Multiple replace" function, soon in the "replace" function too. Wonderful
https://github.com/SubtitleEdit/subtitleedit/releases/download/3.4.10/SubtitleEditBetaTest.zip
So, soon it will possible to see this in the stable release.