Export Vegas timeline markers as DVDA chapter points

WL wrote on 12/8/2003, 12:26 PM
Here is a script to export Vegas timeline markers as chapter points for import into DVDA. For PAL only. Feel free to modify it for NTSC.


/**

Objective:
==========

Script to generate *.sfl file from Vegas timeline markers, which can then be imported into
DVDA as chapter points.

Note:
=====
1) The sfl file **MUST** use the MPEG file as basename, eg. "myfile.mpg.sfl".
2) If string length (including null byte) is not word aligned, ie. odd bytes, then pad
with another null byte to make it even bytes.

History:
========
8/12/2003 WL v1.0. Creation.

**/

//----------------------------------------------------------------------------------------
import System;
import System.Text;
import System.IO;
import System.Drawing;
import System.Windows.Forms;
import SonicFoundry.Vegas;

//----------------------------------------------------------------------------------------
//
// Constants
//
var NULLCH : byte = 0;

//----------------------------------------------------------------------------------------
//
// Variables
//
var desDir = "F:\\home\\dv\\apps\\sfoundry\\vegas\\sfl";
var srcMpgFname = "*.mpg";
var desExt = ".sfl";
var desFullFname = desDir + Path.DirectorySeparatorChar + srcMpgFname + desExt;

//----------------------------------------------------------------------------------------
try {

// Show the script's dialog box.
var dialog = new getFnameDialog(srcMpgFname + desExt);
var dialogResult = dialog.ShowDialog();

// if the OK button was pressed...
if ( System.Windows.Forms.DialogResult.OK == dialogResult ) {

//
// Also need to check extension here in case user bypassed browse button.
//
desFullFname = Path.GetFullPath(dialog.fileNameBox.Text);
if ( Path.GetExtension(desFullFname) != desExt )
desFullFname += desExt;
desDir = Path.GetDirectoryName(desFullFname);
srcMpgFname = Path.GetFileNameWithoutExtension(desFullFname);

// MessageBox.Show(desDir.ToString() + "\n" + srcMpgFname.ToString() + "\n" + desFullFname.ToString());

var track = findSelectedTrack();
if ( null == track )
throw "Error: no selected track";

var mrkEnum = new Enumerator(Vegas.Project.Markers);
makeSFL(mrkEnum);

MessageBox.Show("Done.\n\n" + desFullFname);
}

} catch (e) {
MessageBox.Show(e);
}

//----------------------------------------------------------------------------------------
function openSFL(desDir, srcMpgFname) : FileStream {

if ( !Directory.Exists(desDir) ) {
// Directory.CreateDirectory(desDir);
throw "Directory does not exist:\n\n" + desDir;
}
var fs = File.Create(desFullFname);
return fs;
}

//----------------------------------------------------------------------------------------
function closeSFL(fs, binw) {

binw.Close();
fs.Close();
return null;
}

//----------------------------------------------------------------------------------------
function writeRIFF(binw, sectsize) {

binw.Write( "RIFF".ToCharArray() );
binw.Write( sectsize );
return null;
}

//----------------------------------------------------------------------------------------
function writeSFPL(binw, markerTC, markerCnt) {

var zero : double = 0;
var tc : int;
var counter : int;
var sectsize : int = (markerCnt * 24) + 4;

binw.Write( "SFPLcue ".ToCharArray() );
binw.Write( sectsize );
binw.Write( markerCnt );

for (var i : int = 0; i < markerCnt; i++) {
counter = i + 1;
tc = markerTC[i];
binw.Write( counter );
binw.Write( tc );
binw.Write( "data".ToCharArray() );
binw.Write( zero );
binw.Write( tc );
}
return sectsize;
}

//----------------------------------------------------------------------------------------
function writeLIST(binw, markerLabel, markerCnt) {

var counter : int;
var sectsize : int = 0;
var elemsize : int;

binw.Write( "LIST".ToCharArray() );
binw.Write( sectsize );

binw.Write( "adtl".ToCharArray() );
sectsize += 4;

for (var i : int = 0; i < markerCnt; i++) {
counter = i + 1;
elemsize = markerLabel[i].Length + 4 + 1;
binw.Write( "labl".ToCharArray() );
binw.Write( elemsize );
binw.Write( counter );
binw.Write( markerLabel[i].ToCharArray() );
binw.Write( NULLCH );
sectsize = sectsize + 8 + elemsize;
if ( (elemsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
}
return sectsize;
}

//----------------------------------------------------------------------------------------
function writeSFPI(binw, srcMpgFname) {

var sectsize : int = srcMpgFname.Length + 1;

binw.Write( "SFPI".ToCharArray() );
binw.Write( sectsize );
binw.Write( srcMpgFname.ToCharArray() );
binw.Write( NULLCH );
if ( (sectsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
return sectsize
}

//----------------------------------------------------------------------------------------
function rewriteSize(binw, SFPLsize, LISTsize, SFPIsize) {

var RIFFsize : int = (12 + SFPLsize) + (8 + LISTsize) + (8 + SFPIsize);

binw.Seek(0, SeekOrigin.Begin);
binw.Seek(4,SeekOrigin.Current);
binw.Write( RIFFsize );
binw.Seek(12 + SFPLsize + 4, SeekOrigin.Current);
binw.Write( LISTsize );
return null;
}

//----------------------------------------------------------------------------------------
// I think 1764 is for PAL only. Note sure about NTSC.

function makeSFL(mrkEnum) {

var markerCnt : int = 0;
var markerTC = new Array();
var markerLabel = new Array();
var nowMarker;
var SFPLsize : int, LISTsize : int, SFPIsize : int;
var RIFFsize : int = 0;

while ( !mrkEnum.atEnd() ) {
nowMarker = mrkEnum.item();
var nowMarkPos = Marker(nowMarker).Position;
markerTC[markerCnt] = nowMarkPos.FrameCount * 1764;
markerLabel[markerCnt] = Marker(nowMarker).Label;
markerCnt++;
mrkEnum.moveNext();
}

var fs = openSFL(desDir, srcMpgFname);
var binw = new BinaryWriter(fs);

writeRIFF(binw, RIFFsize);
SFPLsize = writeSFPL(binw, markerTC, markerCnt);
LISTsize = writeLIST(binw, markerLabel, markerCnt);
SFPIsize = writeSFPI(binw, srcMpgFname);
rewriteSize(binw, SFPLsize, LISTsize, SFPIsize);

closeSFL(fs, binw);
return null;
}

//----------------------------------------------------------------------------------------
function findSelectedTrack() : Track {
var trackEnum = new Enumerator(Vegas.Project.Tracks);

while (!trackEnum.atEnd()) {
var track : Track = Track(trackEnum.item());
if (track.Selected) {
return track;
}
trackEnum.moveNext();
}
return null;
}

//----------------------------------------------------------------------------------------
// Button subclass that shows a save file dialog when clicked
class BrowseButton extends Button {
var myResultBox = null;

function BrowseButton(resultBox) {
myResultBox = resultBox;
}

protected override function OnClick(e : EventArgs) {
var saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "DVDA Chapter File (*.sfl)|*.sfl|All Files (*.*)|*.*";
saveFileDialog.DefaultExt = desExt;
saveFileDialog.CheckPathExists = true;
saveFileDialog.CheckFileExists = false;
//
// saveFileDialog.AddExtension is confused because file already has .mpg extension, so
// disabling this option.
//
saveFileDialog.AddExtension = false;
if (null != myResultBox) {
var filename = myResultBox.Text;
var initialDir = Path.GetDirectoryName(filename);
if (Directory.Exists(initialDir)) {
saveFileDialog.InitialDirectory = initialDir;
}
saveFileDialog.FileName = Path.GetFileName(filename);
}

if ( System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog() ) {
if ( null != myResultBox ) {
if ( Path.GetExtension(saveFileDialog.FileName) != desExt )
saveFileDialog.FileName += desExt;
myResultBox.Text = Path.GetFullPath(saveFileDialog.FileName);
}
}
}
}

//----------------------------------------------------------------------------------------
// Form subclass that is the dialog box for this script
class getFnameDialog extends Form {
var browseButton;
var fileNameBox;
var noticeBox;

function getFnameDialog(baseFileName) {

this.Text = "Create DVDA chapter file using timeline markers";
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Width = 580;

var buttonWidth = 80;

fileNameBox = addTextControl("DVDA chapter file", 6, 480, 10, baseFileName);
noticeBox = addTextLabel("Caution: must use mpeg file as basename, eg. myfile.mpg.sfl\n", 6, fileNameBox.Bottom+5);

browseButton = new BrowseButton(fileNameBox);
browseButton.Left = fileNameBox.Right + 4;
browseButton.Top = fileNameBox.Top - 2;
browseButton.Width = buttonWidth;
browseButton.Height = browseButton.Font.Height + 12;
browseButton.Text = "Browse...";
Controls.Add(browseButton);

var buttonTop = noticeBox.Bottom + 16;

var okButton = new Button();
okButton.Text = "OK";
okButton.Left = this.Width - (2*(buttonWidth+10));
okButton.Top = buttonTop;
okButton.Width = buttonWidth;
okButton.Height = okButton.Font.Height + 12;
okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
AcceptButton = okButton;
Controls.Add(okButton);

var cancelButton = new Button();
cancelButton.Text = "Cancel";
cancelButton.Left = this.Width - (1*(buttonWidth+10));
cancelButton.Top = buttonTop;
cancelButton.Height = cancelButton.Font.Height + 12;
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
CancelButton = cancelButton;
Controls.Add(cancelButton);

var titleHeight = this.Height - this.ClientSize.Height;
this.Height = titleHeight + okButton.Bottom + 8;
}

function addTextLabel(labelName, left, top) {
var label = new Label();

label.AutoSize = true;
label.Text = labelName;
label.Left = left;
label.Top = top + 4;
Controls.Add(label);
return label;
}

function addTextControl(labelName, left, width, top, defaultValue) {
var label = new Label();
label.AutoSize = true;
label.Text = labelName + ":";
label.Left = left;
label.Top = top + 4;
Controls.Add(label);

var textbox = new TextBox();
textbox.Multiline = false;
textbox.Left = label.Right;
textbox.Top = top;
textbox.Width = width - (label.Width);
textbox.Text = defaultValue;
Controls.Add(textbox);

return textbox;
}
}

//----------------------------------------------------------------------------------------

Comments

WL wrote on 12/9/2003, 5:43 AM
Some minor enhancements and support for NTSC. Need to comment out PAL or NTSC "frameTime" variable depending on which you want to use. Currently set to PAL.

PS. Sorry about the formatting. There is no facility to attach script other than doing cut and paste.

/**

Objective:
==========

Script to generate *.sfl file from Vegas timeline markers, which can then be imported into
DVDA as chapter points.

Note:
=====
1) The sfl file **MUST** use the MPEG file as basename, eg. "myfile.mpg.sfl".
2) If string length (including null byte) is not word aligned, ie. odd bytes, then pad
with another null byte to make it even bytes.

History:
========
8/12/2003 WL v1.0. Creation.
9/12/2003 WL v1.1.
- Vegas don't write blank label. Script generated blank labels, but
was accepted by DVDA. Modified script not to write blank labels.
- Do not write LIST section if there are no labels.
- Do not create SFL file if there are no markers.
- Support for NTSC.

**/

//----------------------------------------------------------------------------------------
import System;
import System.Text;
import System.IO;
import System.Drawing;
import System.Windows.Forms;
import SonicFoundry.Vegas;

//----------------------------------------------------------------------------------------
//
// Constants
//
var NULLCH : byte = 0;

var PALFrameTime = 1764; // 25 frames/sec
var NTSCFrameTime = 1471.47; // 30000.0/1001.0 = 29.97....

//----------------------------------------------------------------------------------------
//
// Variables
//
var desDir = "F:\\home\\dv\\apps\\sfoundry\\vegas\\sfl";
var srcMpgFname = "*.mpg";
var desExt = ".sfl";
var desFullFname = desDir + Path.DirectorySeparatorChar + srcMpgFname + desExt;

var frameTime = PALFrameTime;
//var frameTime = NTSCFrameTime;

//----------------------------------------------------------------------------------------
// Button subclass that shows a save file dialog when clicked

class BrowseButton extends Button {
var myResultBox = null;

function BrowseButton(resultBox) {
myResultBox = resultBox;
}

protected override function OnClick(e : EventArgs) {
var saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "DVDA Chapter File (*.sfl)|*.sfl|All Files (*.*)|*.*";
saveFileDialog.DefaultExt = desExt;
saveFileDialog.CheckPathExists = true;
saveFileDialog.CheckFileExists = false;
//
// saveFileDialog.AddExtension is confused because file already has .mpg extension, so
// disabling this option.
//
saveFileDialog.AddExtension = false;
if (null != myResultBox) {
var filename = myResultBox.Text;
var initialDir = Path.GetDirectoryName(filename);
if (Directory.Exists(initialDir)) {
saveFileDialog.InitialDirectory = initialDir;
}
saveFileDialog.FileName = Path.GetFileName(filename);
}

if ( System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog() ) {
if ( null != myResultBox ) {
if ( Path.GetExtension(saveFileDialog.FileName) != desExt )
saveFileDialog.FileName += desExt;
myResultBox.Text = Path.GetFullPath(saveFileDialog.FileName);
}
}
}
}

//----------------------------------------------------------------------------------------
// Form subclass that is the dialog box for this script

class getFnameDialog extends Form {
var browseButton;
var fileNameBox;
var noticeBox;

function getFnameDialog(baseFileName) {

this.Text = "Create DVDA chapter file using timeline markers";
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Width = 580;

var buttonWidth = 80;

fileNameBox = addTextControl("DVDA chapter file", 6, 480, 10, baseFileName);
noticeBox = addTextLabel("Caution: must use mpeg file as basename, eg. myfile.mpg.sfl\n", 6, fileNameBox.Bottom+5);

browseButton = new BrowseButton(fileNameBox);
browseButton.Left = fileNameBox.Right + 4;
browseButton.Top = fileNameBox.Top - 2;
browseButton.Width = buttonWidth;
browseButton.Height = browseButton.Font.Height + 12;
browseButton.Text = "Browse...";
Controls.Add(browseButton);

var buttonTop = noticeBox.Bottom + 16;

var okButton = new Button();
okButton.Text = "OK";
okButton.Left = this.Width - (2*(buttonWidth+10));
okButton.Top = buttonTop;
okButton.Width = buttonWidth;
okButton.Height = okButton.Font.Height + 12;
okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
AcceptButton = okButton;
Controls.Add(okButton);

var cancelButton = new Button();
cancelButton.Text = "Cancel";
cancelButton.Left = this.Width - (1*(buttonWidth+10));
cancelButton.Top = buttonTop;
cancelButton.Height = cancelButton.Font.Height + 12;
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
CancelButton = cancelButton;
Controls.Add(cancelButton);

var titleHeight = this.Height - this.ClientSize.Height;
this.Height = titleHeight + okButton.Bottom + 8;
}

function addTextLabel(labelName, left, top) {
var label = new Label();

label.AutoSize = true;
label.Text = labelName;
label.Left = left;
label.Top = top + 4;
Controls.Add(label);
return label;
}

function addTextControl(labelName, left, width, top, defaultValue) {
var label = new Label();
label.AutoSize = true;
label.Text = labelName + ":";
label.Left = left;
label.Top = top + 4;
Controls.Add(label);

var textbox = new TextBox();
textbox.Multiline = false;
textbox.Left = label.Right;
textbox.Top = top;
textbox.Width = width - (label.Width);
textbox.Text = defaultValue;
Controls.Add(textbox);

return textbox;
}
}

//----------------------------------------------------------------------------------------
function openSFL(desDir, srcMpgFname) : FileStream {

if ( !Directory.Exists(desDir) ) {
// Directory.CreateDirectory(desDir);
throw "Directory does not exist:\n\n" + desDir;
}
var fs = File.Create(desFullFname);
return fs;
}

//----------------------------------------------------------------------------------------
function closeSFL(fs, binw) {

binw.Close();
fs.Close();
return null;
}

//----------------------------------------------------------------------------------------
function writeRIFF(binw, sectsize) {

binw.Write( "RIFF".ToCharArray() );
binw.Write( sectsize );
return null;
}

//----------------------------------------------------------------------------------------
function writeSFPL(binw, markerTC, markerCnt) {

var zero : double = 0;
var tc : int;
var counter : int = 0;
var sectsize : int = (markerCnt * 24) + 4;

binw.Write( "SFPLcue ".ToCharArray() );
binw.Write( sectsize );
binw.Write( markerCnt );

for (var i : int = 0; i < markerCnt; i++) {
counter++;
tc = System.Convert.ToInt32(markerTC[i]);
binw.Write( counter );
binw.Write( tc );
binw.Write( "data".ToCharArray() );
binw.Write( zero );
binw.Write( tc );
}
return sectsize;
}

//----------------------------------------------------------------------------------------
// Do not write blank labels.
// If all labels are blank, do not write this section.

function writeLIST(binw, markerLabel, markerCnt) {

var counter : int = 0;
var sectsize : int = 0;
var elemsize : int;

binw.Write( "LIST".ToCharArray() );
binw.Write( sectsize );

binw.Write( "adtl".ToCharArray() );
sectsize += 4;

for (var i : int = 0; i < markerCnt; i++) {
counter++;
if ( markerLabel[i].Length > 0 ) {
elemsize = markerLabel[i].Length + 4 + 1;
binw.Write( "labl".ToCharArray() );
binw.Write( elemsize );
binw.Write( counter );
binw.Write( markerLabel[i].ToCharArray() );
binw.Write( NULLCH );
sectsize = sectsize + 8 + elemsize;
if ( (elemsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
}
}
return sectsize;
}

//----------------------------------------------------------------------------------------
function writeSFPI(binw, srcMpgFname) {

var sectsize : int = srcMpgFname.Length + 1;

binw.Write( "SFPI".ToCharArray() );
binw.Write( sectsize );
binw.Write( srcMpgFname.ToCharArray() );
binw.Write( NULLCH );
if ( (sectsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
return sectsize
}

//----------------------------------------------------------------------------------------
function rewriteSize(binw, SFPLsize, LISTsize, SFPIsize) {

var RIFFsize : int = (12 + SFPLsize) + (8 + SFPIsize);

if ( LISTsize > 0 )
RIFFsize = RIFFsize + (8 + LISTsize);
binw.Seek(0, SeekOrigin.Begin);
binw.Seek(4,SeekOrigin.Current);
binw.Write( RIFFsize );

if ( LISTsize > 0 ) {
binw.Seek(12 + SFPLsize + 4, SeekOrigin.Current);
binw.Write( LISTsize );
}
return null;
}

//----------------------------------------------------------------------------------------
function makeSFL(mrkEnum) {

var markerCnt : int = 0;
var markerTC = new Array();
var markerLabel = new Array();
var sumLabelSize = 0;
var RIFFsize : int = 0;
var SFPLsize : int = 0, LISTsize : int = 0, SFPIsize : int = 0;
var nowMarker;

while ( !mrkEnum.atEnd() ) {
nowMarker = mrkEnum.item();
var nowMarkPos = Marker(nowMarker).Position;
markerTC[markerCnt] = nowMarkPos.FrameCount * frameTime;
markerLabel[markerCnt] = Marker(nowMarker).Label;
sumLabelSize += markerLabel[markerCnt].Length;
markerCnt++;
mrkEnum.moveNext();
}

if ( markerCnt == 0 )
throw "Error: no markers defined on Vegas timeline";

var fs = openSFL(desDir, srcMpgFname);
var binw = new BinaryWriter(fs);

writeRIFF(binw, RIFFsize);
SFPLsize = writeSFPL(binw, markerTC, markerCnt);
if ( sumLabelSize > 0 )
LISTsize = writeLIST(binw, markerLabel, markerCnt);
SFPIsize = writeSFPI(binw, srcMpgFname);
rewriteSize(binw, SFPLsize, LISTsize, SFPIsize);

closeSFL(fs, binw);
return null;
}

//----------------------------------------------------------------------------------------
function findSelectedTrack() : Track {
var trackEnum = new Enumerator(Vegas.Project.Tracks);

while (!trackEnum.atEnd()) {
var track : Track = Track(trackEnum.item());
if (track.Selected) {
return track;
}
trackEnum.moveNext();
}
return null;
}

//----------------------------------------------------------------------------------------
try {

// Show the script's dialog box.
var dialog = new getFnameDialog(srcMpgFname + desExt);
var dialogResult = dialog.ShowDialog();

// if the OK button was pressed...
if ( System.Windows.Forms.DialogResult.OK == dialogResult ) {

//
// Also need to check extension here in case user bypassed browse button.
//
desFullFname = Path.GetFullPath(dialog.fileNameBox.Text);
if ( Path.GetExtension(desFullFname) != desExt )
desFullFname += desExt;
desDir = Path.GetDirectoryName(desFullFname);
srcMpgFname = Path.GetFileNameWithoutExtension(desFullFname);

// MessageBox.Show(desDir.ToString() + "\n" + srcMpgFname.ToString() + "\n" + desFullFname.ToString());

var track = findSelectedTrack();
if ( null == track )
throw "Error: no selected track";

var mrkEnum = new Enumerator(Vegas.Project.Markers);
makeSFL(mrkEnum);

MessageBox.Show("Done.\n\n" + desFullFname);
}

} catch (e) {
MessageBox.Show(e);
}
jetdv wrote on 12/9/2003, 8:20 AM
If you surround the script with

< PRE >

< /PRE >

(eliminating the spaces inside the brackets) you will maintain spacing.
johnmeyer wrote on 12/9/2003, 11:21 AM
And if you want to put a blank line in the text, use the following HTML codes together:

<p><pre>

So, to produce this listing:

function FindSelectedTrack() : Track {
trackEnum = new Enumerator(Vegas.Project.Tracks);
while (!trackEnum.atEnd()) {
var track : Track = Track(trackEnum.item());


if (track.Selected) {
return track;
}
trackEnum.moveNext();
}
return null;
}
you would type:

<pre>
function FindSelectedTrack() : Track {
trackEnum = new Enumerator(Vegas.Project.Tracks);
while (!trackEnum.atEnd()) {
var track : Track = Track(trackEnum.item());
<p><pre>
if (track.Selected) {
return track;
}
trackEnum.moveNext();
}
return null;
}
</pre>
WL wrote on 12/10/2003, 12:17 PM
Thank you all for the formatting tips. To go easy on the eye and brain, here it is again ...



/**

Objective:
==========

Script to generate *.sfl file from Vegas timeline markers, which can then be imported into
DVDA as chapter points.

Note:
=====
1) The sfl file **MUST** use the MPEG file as basename, eg. "myfile.mpg.sfl".
2) If string length (including null byte) is not word aligned, ie. odd bytes, then pad
with another null byte to make it even bytes.

History:
========
8/12/2003 WL v1.0. Creation.
9/12/2003 WL v1.1.
- Vegas don't write blank label. Script generated blank labels, but
was accepted by DVDA. Modified script not to write blank labels.
- Do not write LIST section if there are no labels.
- Do not create SFL file if there are no markers.
- Support for NTSC.

**/

//----------------------------------------------------------------------------------------
import System;
import System.Text;
import System.IO;
import System.Drawing;
import System.Windows.Forms;
import SonicFoundry.Vegas;

//----------------------------------------------------------------------------------------
//
// Constants
//
var NULLCH : byte = 0;

var PALFrameTime = 1764; // 25 frames/sec
var NTSCFrameTime = 1471.47; // 30000.0/1001.0 = 29.97....

//----------------------------------------------------------------------------------------
//
// Variables
//
var desDir = "F:\\home\\dv\\apps\\sfoundry\\vegas\\sfl";
var srcMpgFname = "*.mpg";
var desExt = ".sfl";
var desFullFname = desDir + Path.DirectorySeparatorChar + srcMpgFname + desExt;

var frameTime = PALFrameTime;
//var frameTime = NTSCFrameTime;

//----------------------------------------------------------------------------------------
// Button subclass that shows a save file dialog when clicked

class BrowseButton extends Button {
var myResultBox = null;

function BrowseButton(resultBox) {
myResultBox = resultBox;
}

protected override function OnClick(e : EventArgs) {
var saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "DVDA Chapter File (*.sfl)|*.sfl|All Files (*.*)|*.*";
saveFileDialog.DefaultExt = desExt;
saveFileDialog.CheckPathExists = true;
saveFileDialog.CheckFileExists = false;
//
// saveFileDialog.AddExtension is confused because file already has .mpg extension, so
// disabling this option.
//
saveFileDialog.AddExtension = false;
if (null != myResultBox) {
var filename = myResultBox.Text;
var initialDir = Path.GetDirectoryName(filename);
if (Directory.Exists(initialDir)) {
saveFileDialog.InitialDirectory = initialDir;
}
saveFileDialog.FileName = Path.GetFileName(filename);
}

if ( System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog() ) {
if ( null != myResultBox ) {
if ( Path.GetExtension(saveFileDialog.FileName) != desExt )
saveFileDialog.FileName += desExt;
myResultBox.Text = Path.GetFullPath(saveFileDialog.FileName);
}
}
}
}

//----------------------------------------------------------------------------------------
// Form subclass that is the dialog box for this script

class getFnameDialog extends Form {
var browseButton;
var fileNameBox;
var noticeBox;

function getFnameDialog(baseFileName) {

this.Text = "Create DVDA chapter file using timeline markers";
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Width = 580;

var buttonWidth = 80;

fileNameBox = addTextControl("DVDA chapter file", 6, 480, 10, baseFileName);
noticeBox = addTextLabel("Caution: must use mpeg file as basename, eg. myfile.mpg.sfl\n", 6, fileNameBox.Bottom+5);

browseButton = new BrowseButton(fileNameBox);
browseButton.Left = fileNameBox.Right + 4;
browseButton.Top = fileNameBox.Top - 2;
browseButton.Width = buttonWidth;
browseButton.Height = browseButton.Font.Height + 12;
browseButton.Text = "Browse...";
Controls.Add(browseButton);

var buttonTop = noticeBox.Bottom + 16;

var okButton = new Button();
okButton.Text = "OK";
okButton.Left = this.Width - (2*(buttonWidth+10));
okButton.Top = buttonTop;
okButton.Width = buttonWidth;
okButton.Height = okButton.Font.Height + 12;
okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
AcceptButton = okButton;
Controls.Add(okButton);

var cancelButton = new Button();
cancelButton.Text = "Cancel";
cancelButton.Left = this.Width - (1*(buttonWidth+10));
cancelButton.Top = buttonTop;
cancelButton.Height = cancelButton.Font.Height + 12;
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
CancelButton = cancelButton;
Controls.Add(cancelButton);

var titleHeight = this.Height - this.ClientSize.Height;
this.Height = titleHeight + okButton.Bottom + 8;
}

function addTextLabel(labelName, left, top) {
var label = new Label();

label.AutoSize = true;
label.Text = labelName;
label.Left = left;
label.Top = top + 4;
Controls.Add(label);
return label;
}

function addTextControl(labelName, left, width, top, defaultValue) {
var label = new Label();
label.AutoSize = true;
label.Text = labelName + ":";
label.Left = left;
label.Top = top + 4;
Controls.Add(label);

var textbox = new TextBox();
textbox.Multiline = false;
textbox.Left = label.Right;
textbox.Top = top;
textbox.Width = width - (label.Width);
textbox.Text = defaultValue;
Controls.Add(textbox);

return textbox;
}
}

//----------------------------------------------------------------------------------------
function openSFL(desDir, srcMpgFname) : FileStream {

if ( !Directory.Exists(desDir) ) {
// Directory.CreateDirectory(desDir);
throw "Directory does not exist:\n\n" + desDir;
}
var fs = File.Create(desFullFname);
return fs;
}

//----------------------------------------------------------------------------------------
function closeSFL(fs, binw) {

binw.Close();
fs.Close();
return null;
}

//----------------------------------------------------------------------------------------
function writeRIFF(binw, sectsize) {

binw.Write( "RIFF".ToCharArray() );
binw.Write( sectsize );
return null;
}

//----------------------------------------------------------------------------------------
function writeSFPL(binw, markerTC, markerCnt) {

var zero : double = 0;
var tc : int;
var counter : int = 0;
var sectsize : int = (markerCnt * 24) + 4;

binw.Write( "SFPLcue ".ToCharArray() );
binw.Write( sectsize );
binw.Write( markerCnt );

for (var i : int = 0; i < markerCnt; i++) {
counter++;
tc = System.Convert.ToInt32(markerTC[i]);
binw.Write( counter );
binw.Write( tc );
binw.Write( "data".ToCharArray() );
binw.Write( zero );
binw.Write( tc );
}
return sectsize;
}

//----------------------------------------------------------------------------------------
// Do not write blank labels.
// If all labels are blank, do not write this section.

function writeLIST(binw, markerLabel, markerCnt) {

var counter : int = 0;
var sectsize : int = 0;
var elemsize : int;

binw.Write( "LIST".ToCharArray() );
binw.Write( sectsize );

binw.Write( "adtl".ToCharArray() );
sectsize += 4;

for (var i : int = 0; i < markerCnt; i++) {
counter++;
if ( markerLabel[i].Length > 0 ) {
elemsize = markerLabel[i].Length + 4 + 1;
binw.Write( "labl".ToCharArray() );
binw.Write( elemsize );
binw.Write( counter );
binw.Write( markerLabel[i].ToCharArray() );
binw.Write( NULLCH );
sectsize = sectsize + 8 + elemsize;
if ( (elemsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
}
}
return sectsize;
}

//----------------------------------------------------------------------------------------
function writeSFPI(binw, srcMpgFname) {

var sectsize : int = srcMpgFname.Length + 1;

binw.Write( "SFPI".ToCharArray() );
binw.Write( sectsize );
binw.Write( srcMpgFname.ToCharArray() );
binw.Write( NULLCH );
if ( (sectsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
return sectsize
}

//----------------------------------------------------------------------------------------
function rewriteSize(binw, SFPLsize, LISTsize, SFPIsize) {

var RIFFsize : int = (12 + SFPLsize) + (8 + SFPIsize);

if ( LISTsize > 0 )
RIFFsize = RIFFsize + (8 + LISTsize);
binw.Seek(0, SeekOrigin.Begin);
binw.Seek(4,SeekOrigin.Current);
binw.Write( RIFFsize );

if ( LISTsize > 0 ) {
binw.Seek(12 + SFPLsize + 4, SeekOrigin.Current);
binw.Write( LISTsize );
}
return null;
}

//----------------------------------------------------------------------------------------
function makeSFL(mrkEnum) {

var markerCnt : int = 0;
var markerTC = new Array();
var markerLabel = new Array();
var sumLabelSize = 0;
var RIFFsize : int = 0;
var SFPLsize : int = 0, LISTsize : int = 0, SFPIsize : int = 0;
var nowMarker;

while ( !mrkEnum.atEnd() ) {
nowMarker = mrkEnum.item();
var nowMarkPos = Marker(nowMarker).Position;
markerTC[markerCnt] = nowMarkPos.FrameCount * frameTime;
markerLabel[markerCnt] = Marker(nowMarker).Label;
sumLabelSize += markerLabel[markerCnt].Length;
markerCnt++;
mrkEnum.moveNext();
}

if ( markerCnt == 0 )
throw "Error: no markers defined on Vegas timeline";

var fs = openSFL(desDir, srcMpgFname);
var binw = new BinaryWriter(fs);

writeRIFF(binw, RIFFsize);
SFPLsize = writeSFPL(binw, markerTC, markerCnt);
if ( sumLabelSize > 0 )
LISTsize = writeLIST(binw, markerLabel, markerCnt);
SFPIsize = writeSFPI(binw, srcMpgFname);
rewriteSize(binw, SFPLsize, LISTsize, SFPIsize);

closeSFL(fs, binw);
return null;
}

//----------------------------------------------------------------------------------------
function findSelectedTrack() : Track {
var trackEnum = new Enumerator(Vegas.Project.Tracks);

while (!trackEnum.atEnd()) {
var track : Track = Track(trackEnum.item());
if (track.Selected) {
return track;
}
trackEnum.moveNext();
}
return null;
}

//----------------------------------------------------------------------------------------
try {

// Show the script's dialog box.
var dialog = new getFnameDialog(srcMpgFname + desExt);
var dialogResult = dialog.ShowDialog();

// if the OK button was pressed...
if ( System.Windows.Forms.DialogResult.OK == dialogResult ) {

//
// Also need to check extension here in case user bypassed browse button.
//
desFullFname = Path.GetFullPath(dialog.fileNameBox.Text);
if ( Path.GetExtension(desFullFname) != desExt )
desFullFname += desExt;
desDir = Path.GetDirectoryName(desFullFname);
srcMpgFname = Path.GetFileNameWithoutExtension(desFullFname);

// MessageBox.Show(desDir.ToString() + "\n" + srcMpgFname.ToString() + "\n" + desFullFname.ToString());

var track = findSelectedTrack();
if ( null == track )
throw "Error: no selected track";

var mrkEnum = new Enumerator(Vegas.Project.Markers);
makeSFL(mrkEnum);

MessageBox.Show("Done.\n\n" + desFullFname);
}

} catch (e) {
MessageBox.Show(e);
}


WL wrote on 1/9/2004, 10:33 PM
Some minor enhancements ...



/**

Objective:
==========

Script to generate *.sfl file from Vegas timeline markers, which can then be imported into
DVDA as chapter points.

Note:
=====
1) The sfl file **MUST** use the MPEG file as basename, eg. "myfile.mpg.sfl".
2) If string length (including null byte) is not word aligned, ie. odd bytes, then pad
with another null byte to make it even bytes.

History:
========
8/12/2003 WL v1.0. Creation.
9/12/2003 WL v1.1.
- Vegas don't write blank label. Script generated blank labels, but
was accepted by DVDA. Modified script not to write blank labels.
- Do not write LIST section if there are no labels.
- Do not create SFL file if there are no markers.
- Support for NTSC.
28/12/2003 WL v1.2.
- Modified to auto detect PAL or NTSC to set frame rate.
Only supports 25f/s and 29.97f/s.
1/1/2004 WL v1.3
- Modified to match ruler format with video format. Required for *.stl
and *.chp.
2/1/2004 WL v1.4
- Problem with some DVDA NTSC chapter points being 1 frame off near end of
tape, so used double for markerTC and round up to nearest integer, but
still no good. Work-around is to add 1 frame for each NTSC chapter points.
- Check for maxMarker.
- DVDA requires chapter length be >= 1 sec. Check when creating markers
in another script.
**/

//----------------------------------------------------------------------------------------
import System;
import System.Text;
import System.IO;
import System.Drawing;
import System.Windows.Forms;
import SonicFoundry.Vegas;

//----------------------------------------------------------------------------------------
//
// Constants
//
var NULLCH : byte = 0;
var maxMarker : int = 300;
var PALFrameTime : double = 1764; // 25 frames/sec
var NTSCFrameTime : double = 1471.47; // 30000.0/1001.0 = 29.97....

//----------------------------------------------------------------------------------------
//
// Global variables
//
var frameTime : double = PALFrameTime;
var formatMsg = "unknown";

//
// DVDA seemed to have problem with NTSC chapters points off by 1 frame near the end of tape.
// So adding 1 frame offset for NTSC chapter points. 0 for PAL.
//
var frameOffset : int = 0;

//
// Files
//
var desDir = "F:\\home\\dv\\apps\\sfoundry\\vegas\\sfl";
var srcMpgFname = "*.mpg";
var desExt = ".sfl";
var desFullFname = desDir + Path.DirectorySeparatorChar + srcMpgFname + desExt;

//----------------------------------------------------------------------------------------
function initVar() {
var frameRate = Vegas.Project.Video.FrameRate;

if ( frameRate == 25 ) {
frameTime = PALFrameTime;
frameOffset = 0;
formatMsg = "PAL, 25fps";
Vegas.Project.Ruler.Format = RulerFormat.SmpteEBU;
// MessageBox.Show(formatMsg);
}
else {
frameTime = NTSCFrameTime;
frameOffset = 1;
formatMsg = "NTSC, 29.97fps, TC=non-drop-frame";
Vegas.Project.Ruler.Format = RulerFormat.SmpteNonDrop;
// MessageBox.Show(formatMsg);
}
return null;
}

//----------------------------------------------------------------------------------------
// Button subclass that shows a save file dialog when clicked

class BrowseButton extends Button {
var myResultBox = null;

function BrowseButton(resultBox) {
myResultBox = resultBox;
}

protected override function OnClick(e : EventArgs) {
var saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "DVDA Chapter File (*.sfl)|*.sfl|All Files (*.*)|*.*";
saveFileDialog.DefaultExt = desExt;
saveFileDialog.CheckPathExists = true;
saveFileDialog.CheckFileExists = false;
//
// saveFileDialog.AddExtension is confused because file already has .mpg extension, so
// disabling this option.
//
saveFileDialog.AddExtension = false;
if (null != myResultBox) {
var filename = myResultBox.Text;
var initialDir = Path.GetDirectoryName(filename);
if (Directory.Exists(initialDir)) {
saveFileDialog.InitialDirectory = initialDir;
}
saveFileDialog.FileName = Path.GetFileName(filename);
}

if ( System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog() ) {
if ( null != myResultBox ) {
if ( Path.GetExtension(saveFileDialog.FileName) != desExt )
saveFileDialog.FileName += desExt;
myResultBox.Text = Path.GetFullPath(saveFileDialog.FileName);
}
}
}
}

//----------------------------------------------------------------------------------------
// Form subclass that is the dialog box for this script

class getFnameDialog extends Form {
var browseButton;
var fileNameBox;
var noticeBox;

function getFnameDialog(baseFileName) {

this.Text = "Create DVDA chapter file using timeline markers";
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Width = 580;

var buttonWidth = 80;

fileNameBox = addTextControl("DVDA chapter file", 6, 480, 10, baseFileName);
noticeBox = addTextLabel("Caution: must use mpeg file as basename, eg. myfile.mpg.sfl\n", 6, fileNameBox.Bottom+5);

browseButton = new BrowseButton(fileNameBox);
browseButton.Left = fileNameBox.Right + 4;
browseButton.Top = fileNameBox.Top - 2;
browseButton.Width = buttonWidth;
browseButton.Height = browseButton.Font.Height + 12;
browseButton.Text = "Browse...";
Controls.Add(browseButton);

var buttonTop = noticeBox.Bottom + 16;

var okButton = new Button();
okButton.Text = "OK";
okButton.Left = this.Width - (2*(buttonWidth+10));
okButton.Top = buttonTop;
okButton.Width = buttonWidth;
okButton.Height = okButton.Font.Height + 12;
okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
AcceptButton = okButton;
Controls.Add(okButton);

var cancelButton = new Button();
cancelButton.Text = "Cancel";
cancelButton.Left = this.Width - (1*(buttonWidth+10));
cancelButton.Top = buttonTop;
cancelButton.Height = cancelButton.Font.Height + 12;
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
CancelButton = cancelButton;
Controls.Add(cancelButton);

var titleHeight = this.Height - this.ClientSize.Height;
this.Height = titleHeight + okButton.Bottom + 8;
}

function addTextLabel(labelName, left, top) {
var label = new Label();

label.AutoSize = true;
label.Text = labelName;
label.Left = left;
label.Top = top + 4;
Controls.Add(label);
return label;
}

function addTextControl(labelName, left, width, top, defaultValue) {
var label = new Label();
label.AutoSize = true;
label.Text = labelName + ":";
label.Left = left;
label.Top = top + 4;
Controls.Add(label);

var textbox = new TextBox();
textbox.Multiline = false;
textbox.Left = label.Right;
textbox.Top = top;
textbox.Width = width - (label.Width);
textbox.Text = defaultValue;
Controls.Add(textbox);

return textbox;
}
}

//----------------------------------------------------------------------------------------
function openSFL(desDir, srcMpgFname) : FileStream {

if ( !Directory.Exists(desDir) ) {
// Directory.CreateDirectory(desDir);
throw "Directory does not exist:\n\n" + desDir;
}
var fs = File.Create(desFullFname);
return fs;
}

//----------------------------------------------------------------------------------------
function closeSFL(fs, binw) {

binw.Close();
fs.Close();
return null;
}

//----------------------------------------------------------------------------------------
function writeRIFF(binw, sectsize) {

binw.Write( "RIFF".ToCharArray() );
binw.Write( sectsize );
return null;
}

//----------------------------------------------------------------------------------------
function writeSFPL(binw, markerTC : double[], markerCnt) {

var zero : double = 0;
var tc : int;
var counter : int = 0;
var sectsize : int = (markerCnt * 24) + 4;

binw.Write( "SFPLcue ".ToCharArray() );
binw.Write( sectsize );
binw.Write( markerCnt );

for (var i : int = 0; i < markerCnt; i++) {
counter++;
tc = System.Convert.ToInt32(System.Math.Round(markerTC[i]));
binw.Write( counter );
binw.Write( tc );
binw.Write( "data".ToCharArray() );
binw.Write( zero );
binw.Write( tc );
}
return sectsize;
}

//----------------------------------------------------------------------------------------
// Do not write blank labels.
// If all labels are blank, do not write this section.

function writeLIST(binw, markerLabel, markerCnt) {

var counter : int = 0;
var sectsize : int = 0;
var elemsize : int;

binw.Write( "LIST".ToCharArray() );
binw.Write( sectsize );

binw.Write( "adtl".ToCharArray() );
sectsize += 4;

for (var i : int = 0; i < markerCnt; i++) {
counter++;
if ( markerLabel[i].Length > 0 ) {
elemsize = markerLabel[i].Length + 4 + 1;
binw.Write( "labl".ToCharArray() );
binw.Write( elemsize );
binw.Write( counter );
binw.Write( markerLabel[i].ToCharArray() );
binw.Write( NULLCH );
sectsize = sectsize + 8 + elemsize;
if ( (elemsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
}
}
return sectsize;
}

//----------------------------------------------------------------------------------------
function writeSFPI(binw, srcMpgFname) {

var sectsize : int = srcMpgFname.Length + 1;

binw.Write( "SFPI".ToCharArray() );
binw.Write( sectsize );
binw.Write( srcMpgFname.ToCharArray() );
binw.Write( NULLCH );
if ( (sectsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
return sectsize
}

//----------------------------------------------------------------------------------------
function rewriteSize(binw, SFPLsize, LISTsize, SFPIsize) {

var RIFFsize : int = (12 + SFPLsize) + (8 + SFPIsize);

if ( LISTsize > 0 )
RIFFsize = RIFFsize + (8 + LISTsize);
binw.Seek(0, SeekOrigin.Begin);
binw.Seek(4,SeekOrigin.Current);
binw.Write( RIFFsize );

if ( LISTsize > 0 ) {
binw.Seek(12 + SFPLsize + 4, SeekOrigin.Current);
binw.Write( LISTsize );
}
return null;
}

//----------------------------------------------------------------------------------------
function makeSFL(mrkEnum) {

var markerCnt : int = 0;
var totMarker : int = 0;
// var markerTC = new Array();
var markerTC : double[] = new double[maxMarker];

var markerLabel = new Array();
var sumLabelSize = 0;
var RIFFsize : int = 0;
var SFPLsize : int = 0, LISTsize : int = 0, SFPIsize : int = 0;
var nowMarker;

while ( !mrkEnum.atEnd() ) {
totMarker++;
if ( markerCnt < maxMarker ) {
nowMarker = mrkEnum.item();
var nowMarkPos = Marker(nowMarker).Position;
if ( nowMarkPos.FrameCount == 0 ) {
//
// DVDA auto creates chapter at 00:00:00:00, and creates only one if overlapped.
//
markerTC[markerCnt] = nowMarkPos.FrameCount * frameTime;
}
else {
markerTC[markerCnt] = (nowMarkPos.FrameCount + frameOffset) * frameTime;
}
markerLabel[markerCnt] = Marker(nowMarker).Label;
sumLabelSize += markerLabel[markerCnt].Length;
markerCnt++;
mrkEnum.moveNext();
}
}

if ( markerCnt == 0 )
throw "Error: no markers defined on Vegas timeline";

var fs = openSFL(desDir, srcMpgFname);
var binw = new BinaryWriter(fs);

writeRIFF(binw, RIFFsize);
SFPLsize = writeSFPL(binw, markerTC, markerCnt);
if ( sumLabelSize > 0 )
LISTsize = writeLIST(binw, markerLabel, markerCnt);
SFPIsize = writeSFPI(binw, srcMpgFname);
rewriteSize(binw, SFPLsize, LISTsize, SFPIsize);

closeSFL(fs, binw);
return totMarker;
}

//----------------------------------------------------------------------------------------
function findSelectedTrack() : Track {
var trackEnum = new Enumerator(Vegas.Project.Tracks);

while (!trackEnum.atEnd()) {
var track : Track = Track(trackEnum.item());
if (track.Selected) {
return track;
}
trackEnum.moveNext();
}
return null;
}

//----------------------------------------------------------------------------------------
try {

var totMarker : int = 0;
var missMarker : int = 0;

initVar();

// Show the script's dialog box.
var dialog = new getFnameDialog(srcMpgFname + desExt);
var dialogResult = dialog.ShowDialog();

// if the OK button was pressed...
if ( System.Windows.Forms.DialogResult.OK == dialogResult ) {

//
// Also need to check extension here in case user bypassed browse button.
//
desFullFname = Path.GetFullPath(dialog.fileNameBox.Text);
if ( Path.GetExtension(desFullFname) != desExt )
desFullFname += desExt;
desDir = Path.GetDirectoryName(desFullFname);
srcMpgFname = Path.GetFileNameWithoutExtension(desFullFname);

// MessageBox.Show(desDir.ToString() + "\n" + srcMpgFname.ToString() + "\n" + desFullFname.ToString());

var track = findSelectedTrack();
if ( null == track )
throw "Error: no selected track";

var mrkEnum = new Enumerator(Vegas.Project.Markers);
totMarker = makeSFL(mrkEnum);
if ( totMarker > maxMarker ) {
missMarker = totMarker - maxMarker;
}

MessageBox.Show(
"Done." +
"\nFile: " + desFullFname +
"\n" +
"\nFormat: " + formatMsg +
"\nTotal markers: " + totMarker.ToString() +
"\nMissed markers: " + missMarker.ToString()
);
}

} catch (e) {
MessageBox.Show(e);
}


Rosebud wrote on 1/15/2004, 11:54 PM
Nice script and very useful !
Thank you very much WL !
Invisible wrote on 1/16/2004, 10:58 AM
I would like to thank WL for your hard work on this script!!!! You saved so much time for me. It's a very good script for those who forgot to save markers in a file to import into DVDA as chapters.

Again, thanks a lot, WL!

DN
Luxo wrote on 2/12/2004, 9:22 PM
I have need for a similar script that outputs a DVD Maestro *.chp chapter list file. It is a very simple text file that looks like this:

$Spruce_IFrame_List
00:00:00:00
00:10:15:00
00:20:30:00
00:30:45:00
(...etc.)

Obviously, each timecode is a chapter. The script would have to insert the first two lines, assuming the user doesn't have a marker at the beginning of his project.

Is this script easily modified to output such a file? I am not a coder by any stretch of the imagination, though I have tried and failed miserably. Any suggestions would be helpful.
mtagliaf wrote on 2/13/2004, 8:50 AM
The script seems to be working (I'm getting an sfl file), can someone tell me how to import into DVDA? Sorry for the newbie question - I'm a programmer learning how I can interface Vegas/DVDA to a piece of software I'm writing for DVD creation capability.

PS: If anyone would be willing to answer some other "can I do this in Vegas/DVDA" questions, I'd appreciate. Contact me at mtagliaf@cleindians.com.
jetdv wrote on 2/13/2004, 11:12 AM
In DVDA, click on the Load Markers button. It *may* be necessary for the file name to be identical to the MPG file except for the extension.
WL wrote on 2/20/2004, 2:12 PM
Just upload script to SunDance,

http://www.sundancemediagroup.com/help/kb/kb_files.asp

The script is call wil_maestrochp.js

Description: Script to generate *.chp file from Vegas timeline markers, which can then be imported into DVD Maestro as chapter points.
HarrieG wrote on 3/1/2004, 1:36 PM
This is indeed a nice script. I mostly use it to make markers available in the trimmer. Perhaps this is a further enhancement. I usually edit DV-Avi. If you use the script the marker positions will gradually end up at another position. For DV-Avi I altered the Constant PALFrameTime into 1920 (being a European I only work with PAL - I suppose the right setting for NTSC will be 1601.6) and saved the script as *_PAL.

Harrie Geboers
Luxo wrote on 3/5/2004, 11:35 PM
*Thank* you WL. I hadn't checked this thread in a couple weeks, so this is a very big surprise. Kudos to you, you have my gratitude.
malowz wrote on 1/2/2013, 2:40 PM
sorry to revive 2004 thread, but anyone have modded to work on latest releases of vegas?

it does not work properly on v12.

i use external encoder, so i need to create the .sfl in a separated step
DeadRadioStar wrote on 1/2/2013, 4:00 PM
I've asked a similar question but with products like Vegasaur and Ultimate S around, it would seem hardly worth anyone's time to go modify this to work in VP12. They both seem to be able to do this, plus you get so much more.
malowz wrote on 1/3/2013, 2:27 AM
i agree, but i really don't need the hole package, i just need one function.

and considering there was one already, i would want it ;)
jetdv wrote on 1/3/2013, 9:22 AM
The first change is:

import SonicFoundry.Vegas;

to

import Sony.Vegas;

Beyond that, without actually testing it, you would then need to handle any additional issues on a case by case basis.
malowz wrote on 1/3/2013, 11:48 AM
the script generate this error:

"More than one method or property matches this argument list"
on the line:
tc = System.Convert.ToInt32(System.Math.Round(markerTC));


removing the round function, it runs, but give this error at the end:

Error: unable to cast object of type 'System.Double' to type 'System.IConvertible'

any tips?
DeadRadioStar wrote on 1/3/2013, 3:17 PM
Oh alright then ....
[EDIT:] removed my "hacked" version as an updated version apparently by the original author was found, see my post dated 1/4/2013 10:51:09 AM below.
malowz wrote on 1/3/2013, 4:49 PM
yayyyyyyyyyy, tnks DeadRadioStar!!!! it's working nice!

now i was able to mod it a bit to suit my needs ;)

EDIT: the script does have the marker name function right? cause it looks like it get the marker name, but does not write it the to the file.

maybe something more is missing from the post?


DeadRadioStar wrote on 1/4/2013, 4:51 AM
No credit is due to me, but to the original author, "WL". In the meantime, I've been able to find an updated version of this script apparently by the original author, which was contained in a file called "everything.zip" located here. Out of respect to the original author, I'm posting his version 1.6 below, and will go back and edit my post above to reflect this.
(Apologies if there's a better way to post scripts, I'm new to this!)
This file was called "wil_mksfl_vegas.js"

/**

Objective:
==========

Script to generate *.sfl file from Vegas timeline markers, which can then be imported into
DVDA as chapter points. (File format same as that saved by Vegas.)

Note:
=====
1) The sfl file **MUST** use the MPEG file as basename, eg. "myfile.mpg.sfl".
2) If string length (including null byte) is not word aligned, ie. odd bytes, then pad
with another null byte to make it even bytes.
3) Chapter point need to fall on an I-frame, so actual frame used will depend on
how DVDA search for I-frame. If there is ever an option, choose search backwards.

History:
========
8/12/2003 WL v1.0. Creation. Supports DVDA v1.0d.
9/12/2003 WL v1.1.
- Vegas don't write blank label. Script generated blank labels, but
was accepted by DVDA. Modified script not to write blank labels.
- Do not write LIST section if there are no labels.
- Do not create SFL file if there are no markers.
- Support for NTSC.
28/12/2003 WL v1.2.
- Modified to auto detect PAL or NTSC from project setting to set frame rate.
Only supports 25f/s and 29.97f/s.
1/1/2004 WL v1.3
- Modified to match ruler format with video format. Required for *.stl
and *.chp.
2/1/2004 WL v1.4
- Problem with some DVDA NTSC chapter points being 1 frame off near end of
tape, so used double for markerTC and round up to nearest integer, but
still no good. Work-around is to add 1 frame for each NTSC chapter points.
- Check for maxMarker.
- DVDA requires chapter length be >= 1 sec. Check when creating markers
in another script.
24/7/2004 WL v1.5
- Modified to be more modular. Similar to wl_mksfl_dvda (sfl by dvda).
- Found problem with Vegas v4 and v5. *Sometimes* the chapters are displayed
at the right place as viewed on the time line, but is actually referring to
the previous frame as shown by the timecode, and the same timecode is used
to create the SFL and CHP files. So the picture from the previous chapter
is used for the chapter point. Found problem when doing PAL DV. The
workaround is to also increase chapter points by 1 frame for PAL also.
8/8/2004 WL v1.6
- Due to Vegas frame problem discovered in v1.5, need to add another frame for
NTSC, ie. frameOffset=2 for NTSC.

**/

//----------------------------------------------------------------------------------------
import System;
import System.Text;
import System.IO;
import System.Drawing;
import System.Windows.Forms;
import Sony.Vegas;

//----------------------------------------------------------------------------------------
//
// Constants
//
var NULLCH : byte = 0;
var maxMarker : int = 300;
var PALFrameTime : double = 1764; // 25 frames/sec
var NTSCFrameTime : double = 1471.47; // 30000.0/1001.0 = 29.97....

//----------------------------------------------------------------------------------------
//
// Global variables
//
var frameTime : double = PALFrameTime;
var formatMsg = "unknown";

//
// DVDA seemed to have problem with NTSC chapters points off by 1 frame near the end of tape.
// So adding 1 frame offset for NTSC chapter points. 0 for PAL.
//
var frameOffset : int = 0;

//
// Files
//
var desDir = "F:\\home\\dv\\apps\\sfoundry\\vegas\\sfl";
var srcMpgFname = "*.mpg";
var desExt = ".sfl";
var desFullFname = desDir + Path.DirectorySeparatorChar + srcMpgFname + desExt;

//----------------------------------------------------------------------------------------
function initVar() {
var frameRate = Vegas.Project.Video.FrameRate;

if ( frameRate == 25 ) {
frameTime = PALFrameTime;
frameOffset = 1;
formatMsg = "PAL, 25fps";
Vegas.Project.Ruler.Format = RulerFormat.SmpteEBU;
// MessageBox.Show(formatMsg);
}
else {
frameTime = NTSCFrameTime;
frameOffset = 2;
formatMsg = "NTSC, 29.97fps, TC=non-drop-frame";
Vegas.Project.Ruler.Format = RulerFormat.SmpteNonDrop;
// MessageBox.Show(formatMsg);
}
return null;
}

//----------------------------------------------------------------------------------------
// Button subclass that shows a save file dialog when clicked

class BrowseButton extends Button {
var myResultBox = null;

function BrowseButton(resultBox) {
myResultBox = resultBox;
}

protected override function OnClick(e : EventArgs) {
var saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "DVDA Chapter File (*.sfl)|*.sfl|All Files (*.*)|*.*";
saveFileDialog.DefaultExt = desExt;
saveFileDialog.CheckPathExists = true;
saveFileDialog.CheckFileExists = false;
//
// saveFileDialog.AddExtension is confused because file already has .mpg extension, so
// disabling this option.
//
saveFileDialog.AddExtension = false;
if (null != myResultBox) {
var filename = myResultBox.Text;
var initialDir = Path.GetDirectoryName(filename);
if (Directory.Exists(initialDir)) {
saveFileDialog.InitialDirectory = initialDir;
}
saveFileDialog.FileName = Path.GetFileName(filename);
}

if ( System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog() ) {
if ( null != myResultBox ) {
if ( Path.GetExtension(saveFileDialog.FileName) != desExt )
saveFileDialog.FileName += desExt;
myResultBox.Text = Path.GetFullPath(saveFileDialog.FileName);
}
}
}
}

//----------------------------------------------------------------------------------------
// Form subclass that is the dialog box for this script

class getFnameDialog extends Form {
var browseButton;
var fileNameBox;
var noticeBox;

function getFnameDialog(baseFileName) {

this.Text = "Create DVDA chapter file using timeline markers";
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Width = 580;

var buttonWidth = 80;

fileNameBox = addTextControl("DVDA chapter file", 6, 480, 10, baseFileName);
noticeBox = addTextLabel("Caution: must use mpeg file as basename, eg. myfile.mpg.sfl\n", 6, fileNameBox.Bottom+5);

browseButton = new BrowseButton(fileNameBox);
browseButton.Left = fileNameBox.Right + 4;
browseButton.Top = fileNameBox.Top - 2;
browseButton.Width = buttonWidth;
browseButton.Height = browseButton.Font.Height + 12;
browseButton.Text = "Browse...";
Controls.Add(browseButton);

var buttonTop = noticeBox.Bottom + 16;

var okButton = new Button();
okButton.Text = "OK";
okButton.Left = this.Width - (2*(buttonWidth+10));
okButton.Top = buttonTop;
okButton.Width = buttonWidth;
okButton.Height = okButton.Font.Height + 12;
okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
AcceptButton = okButton;
Controls.Add(okButton);

var cancelButton = new Button();
cancelButton.Text = "Cancel";
cancelButton.Left = this.Width - (1*(buttonWidth+10));
cancelButton.Top = buttonTop;
cancelButton.Height = cancelButton.Font.Height + 12;
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
CancelButton = cancelButton;
Controls.Add(cancelButton);

var titleHeight = this.Height - this.ClientSize.Height;
this.Height = titleHeight + okButton.Bottom + 8;
}

function addTextLabel(labelName, left, top) {
var label = new Label();

label.AutoSize = true;
label.Text = labelName;
label.Left = left;
label.Top = top + 4;
Controls.Add(label);
return label;
}

function addTextControl(labelName, left, width, top, defaultValue) {
var label = new Label();
label.AutoSize = true;
label.Text = labelName + ":";
label.Left = left;
label.Top = top + 4;
Controls.Add(label);

var textbox = new TextBox();
textbox.Multiline = false;
textbox.Left = label.Right;
textbox.Top = top;
textbox.Width = width - (label.Width);
textbox.Text = defaultValue;
Controls.Add(textbox);

return textbox;
}
}

//----------------------------------------------------------------------------------------
function openSFL(desDir, srcMpgFname) : FileStream {

if ( !Directory.Exists(desDir) ) {
// Directory.CreateDirectory(desDir);
throw "Directory does not exist:\n\n" + desDir;
}
var fs = File.Create(desFullFname);
return fs;
}

//----------------------------------------------------------------------------------------
function closeSFL(fs, binw) {

binw.Close();
fs.Close();
return null;
}

//----------------------------------------------------------------------------------------
function writeRIFF(binw, sectsize) {

binw.Write( "RIFF".ToCharArray() );
binw.Write( sectsize );
return null;
}

//----------------------------------------------------------------------------------------
function writeSFPL(binw) {

binw.Write( "SFPL".ToCharArray() );
}

//----------------------------------------------------------------------------------------
function writeCUE(binw, markerTC : double[], markerCnt) {

var zero : double = 0;
var tc : int;
var counter : int = 0;
var sectsize : int = (markerCnt * 24) + 4;

binw.Write( "cue ".ToCharArray() );
binw.Write( sectsize );
binw.Write( markerCnt );

for (var i : int = 0; i < markerCnt; i++) {
counter++;
tc = System.Convert.ToInt32(System.Math.Round(markerTC[i]));
binw.Write( counter );
binw.Write( tc );
binw.Write( "data".ToCharArray() );
binw.Write( zero );
binw.Write( tc );
}
return sectsize;
}

//----------------------------------------------------------------------------------------
// Do not write blank labels.
// If all labels are blank, do not write this section.

function writeLIST(binw, markerLabel, markerCnt) {

var counter : int = 0;
var sectsize : int = 0;
var elemsize : int;

binw.Write( "LIST".ToCharArray() );
binw.Write( sectsize );

binw.Write( "adtl".ToCharArray() );
sectsize += 4;

for (var i : int = 0; i < markerCnt; i++) {
counter++;
if ( markerLabel[i].Length > 0 ) {
elemsize = markerLabel[i].Length + 4 + 1;
binw.Write( "labl".ToCharArray() );
binw.Write( elemsize );
binw.Write( counter );
binw.Write( markerLabel[i].ToCharArray() );
binw.Write( NULLCH );
sectsize = sectsize + 8 + elemsize;
if ( (elemsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
}
}
return sectsize;
}

//----------------------------------------------------------------------------------------
function writeSFPI(binw, srcMpgFname) {

var sectsize : int = srcMpgFname.Length + 1;

binw.Write( "SFPI".ToCharArray() );
binw.Write( sectsize );
binw.Write( srcMpgFname.ToCharArray() );
binw.Write( NULLCH );
if ( (sectsize % 2) > 0 ) {
binw.Write( NULLCH );
sectsize++;
}
return sectsize
}

//----------------------------------------------------------------------------------------
function rewriteSize(binw, CUEsize, LISTsize, SFPIsize) {

var RIFFsize : int = (12 + CUEsize) + (8 + SFPIsize);

if ( LISTsize > 0 )
RIFFsize = RIFFsize + (8 + LISTsize);
binw.Seek(0, SeekOrigin.Begin);
binw.Seek(4,SeekOrigin.Current);
binw.Write( RIFFsize );

if ( LISTsize > 0 ) {
binw.Seek((12 + CUEsize) + 4, SeekOrigin.Current);
binw.Write( LISTsize );
}
return null;
}

//----------------------------------------------------------------------------------------
function makeSFL(mrkEnum) {

var markerCnt : int = 0;
var totMarker : int = 0;
// var markerTC = new Array();
var markerTC : double[] = new double[maxMarker];

var markerLabel = new Array();
var sumLabelSize = 0;
var RIFFsize : int = 0;
var CUEsize : int = 0, LISTsize : int = 0, SFPIsize : int = 0;
var nowMarker;

while ( !mrkEnum.atEnd() ) {
totMarker++;
if ( markerCnt < maxMarker ) {
nowMarker = mrkEnum.item();
var nowMarkPos = Marker(nowMarker).Position;
if ( nowMarkPos.FrameCount == 0 ) {
//
// DVDA auto creates chapter at 00:00:00:00, and creates only one if overlapped.
//
markerTC[markerCnt] = nowMarkPos.FrameCount * frameTime;
}
else {
markerTC[markerCnt] = (nowMarkPos.FrameCount + frameOffset) * frameTime;
}
markerLabel[markerCnt] = Marker(nowMarker).Label;
sumLabelSize += markerLabel[markerCnt].Length;
markerCnt++;
mrkEnum.moveNext();
}
}

if ( markerCnt == 0 )
throw "Error: no markers defined on Vegas timeline";

var fs = openSFL(desDir, srcMpgFname);
var binw = new BinaryWriter(fs);

writeRIFF(binw, RIFFsize);
writeSFPL(binw);
CUEsize = writeCUE(binw, markerTC, markerCnt);
if ( sumLabelSize > 0 )
LISTsize = writeLIST(binw, markerLabel, markerCnt);
SFPIsize = writeSFPI(binw, srcMpgFname);
rewriteSize(binw, CUEsize, LISTsize, SFPIsize);

closeSFL(fs, binw);
return totMarker;
}

//----------------------------------------------------------------------------------------
function findSelectedTrack() : Track {
var trackEnum = new Enumerator(Vegas.Project.Tracks);

while (!trackEnum.atEnd()) {
var track : Track = Track(trackEnum.item());
if (track.Selected) {
return track;
}
trackEnum.moveNext();
}
return null;
}

//----------------------------------------------------------------------------------------
try {

var totMarker : int = 0;
var missMarker : int = 0;

initVar();

// Show the script's dialog box.
var dialog = new getFnameDialog(srcMpgFname + desExt);
var dialogResult = dialog.ShowDialog();

// if the OK button was pressed...
if ( System.Windows.Forms.DialogResult.OK == dialogResult ) {

//
// Also need to check extension here in case user bypassed browse button.
//
desFullFname = Path.GetFullPath(dialog.fileNameBox.Text);
if ( Path.GetExtension(desFullFname) != desExt )
desFullFname += desExt;
desDir = Path.GetDirectoryName(desFullFname);
srcMpgFname = Path.GetFileNameWithoutExtension(desFullFname);

// MessageBox.Show(desDir.ToString() + "\n" + srcMpgFname.ToString() + "\n" + desFullFname.ToString());

var track = findSelectedTrack();
if ( null == track )
throw "Error: no selected track";

var mrkEnum = new Enumerator(Vegas.Project.Markers);
totMarker = makeSFL(mrkEnum);
if ( totMarker > maxMarker ) {
missMarker = totMarker - maxMarker;
}

MessageBox.Show(
"Done." +
"\nFile: " + desFullFname +
"\n" +
"\nFormat: " + formatMsg +
"\nTotal markers: " + totMarker.ToString() +
"\nMissed markers: " + missMarker.ToString()
);
}

} catch (e) {
MessageBox.Show(e);
}
malowz wrote on 1/4/2013, 2:46 PM
wow, nice find! fully working now ;)

tnks everyone for the help!