Help! Problem with script to generate an editlist

NickHope wrote on 9/27/2015, 10:16 AM
In my never-ending quest to find a way to smart trim my GH4 footage, I am trying to create a script that generates a text list showing media, start timecode and length. The list can then be processed with ffmpeg via a Windows batch file. The script is based on JohnnyRoy's old script, WombleExport.cs, but I have modified (= horribly butchered) it a lot.

The clips trimmed by ffmpeg decode in Vegas Pro a bit strangely at the ends. When the trimmed clips are put back on the timeline they usually have about 3 duplicate frames at the finish. At the start they are normally frame-accurate, but if the start is not being trimmed at all then there are 2 duplicate frames. If the start is trimmed by just 1 frame then there is 1 duplicate frame (I think).

To deal with this I want to add 2 frames to the start and 3 frames to the finish of all clips in this script, then subtract 2 of those added frames at the start for clips that are not being trimmed at the start, or subtract 1 of those added frames for clips that are being trimmed by just 1 frame, correspondingly compensating the length.

Then later I will use another script to trim the trimmed clips when they are put back on the timeline, by 2 frames at the start and 3 frames at the finish.

I can get the basic script working, but I am having trouble with the code to determine if the clips are not being trimmed at all or by just one frame. The problem seems to be with the "if" statement in line 72 and/or the rest of that "if -else if - else" section up to line 87.

I am not a programmer and my "cobbling together" skills are failing me. I've run out of things to try, so can anyone tell me what I've got wrong? I'd also greatly appreciate any suggestions for improvement, as I'm sure it's inelegant and bloated as it is. Also, is there a way (if necessary) of increasing the accuracy of lines 95 and 96 (e.g. from milliseconds to micro or nanoseconds)?

Thanks!

/** * Program: Export ffmpeg trimlist.cs
* Author: Nick Hope
* Adapted from the script WombleExport.cs by John Rofrano
* Purpose: This script will export the first Vegas Pro video track as a list in a .txt file.
* Each line contains the name of the media file, the timecode in, and the length of the event on the timeline
* separated by spaces.
* This file can then be used by a batch file to trim the files with ffmpeg
*
* Revision Date: Sept. 27, 2015
**/
using System;
using System.IO;
using System.Windows.Forms;
using Sony.Vegas;
class EntryPoint
{
public void FromVegas(Vegas vegas)
{
Timecode oneFrame = Timecode.FromFrames(1); // Get 1 frame in timecode format to use later
Timecode startAdd = Timecode.FromFrames(2); // Change number of frames to add to start
Timecode endAdd = Timecode.FromFrames(3); // Change number of frames to add to end
// get the first video track
VideoTrack videoTrack = null;
foreach (Track track in vegas.Project.Tracks)
{
if (track.IsVideo())
{
videoTrack = (VideoTrack)track;
break;
}
}
// if we didn't find a track then tell the user we can't continue
if (videoTrack == null)
{
MessageBox.Show("You must have at least one video track in your project",
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// make sure the project has a name
if (vegas.Project.FilePath == null)
{
MessageBox.Show("You must give your project a name by saving it before running this script",
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string trimlistFilename = String.Format("E:\\trimlist.txt");
// Alternative to create the trim list name from the project name
//string trimlistFilename = Path.ChangeExtension(vegas.Project.FilePath, ".txt");
int eventsProcessed = 0;
StreamWriter writer = null;
try
{
writer = new StreamWriter(trimlistFilename);

for (int i = 0; i < videoTrack.Events.Count; i++)
{
VideoEvent videoEvent = (VideoEvent)videoTrack.Events[i];

// Get the input file name
string infile = videoEvent.ActiveTake.MediaPath;
// get the path and filename without the extension
string basename = Path.Combine(Path.GetDirectoryName(infile), Path.GetFileNameWithoutExtension(infile));

Timecode clipOffsetOriginal = videoEvent.ActiveTake.Offset;
// clipOffsetOriginal as a number of frames
Int64 clipOffsetOriginalFrames = videoEvent.ActiveTake.Offset.FrameCount;

Timecode clipOffset = clipOffsetOriginal - startAdd;
Timecode clipDuration = videoEvent.Length + startAdd + endAdd;

// Reset start to zero if start was not trimmed at all, and compensate length
if (clipOffsetOriginalFrames == 0)
{
int OffsetAdjusterFrames = 2;
int DurationAdjusterFrames = -2;
}
// Reset start to zero if start had been trimmed by just 1 frame, and compensate length
else if (clipOffsetOriginalFrames == 1)
{
int OffsetAdjusterFrames = 1;
int DurationAdjusterFrames = -1;
}
else
{
int OffsetAdjusterFrames = 0;
int DurationAdjusterFrames = 0;
}

Timecode OffsetAdjuster = Timecode.FromFrames(OffsetAdjusterFrames);
Timecode DurationAdjuster = Timecode.FromFrames(DurationAdjusterFrames);
Timecode clipOffsetAdjusted = clipOffset + OffsetAdjuster;
Timecode clipDurationAdjusted = clipDuration + DurationAdjuster;

// Convert start and duration from timecode to seconds
double start = clipOffsetAdjusted.ToMilliseconds() / 1000;
double duration = clipDurationAdjusted.ToMilliseconds() / 1000;

string triminfo = String.Format(basename + ".mp4 " + start + " " + duration);
writer.WriteLine(triminfo);
eventsProcessed++;
}
writer.Close();
}
catch (Exception e)
{
if (null != writer)
{
writer.Close();
}
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
MessageBox.Show("Processed: " + eventsProcessed + " events",
"Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}

Comments

NickHope wrote on 9/27/2015, 12:01 PM
In case someone is working on this, I received a solution to my problem here.

After sleep and coffee I have also improved and simplified the script a lot so please don't waste time working on it.

However I would still welcome answers to my question about accuracy.

When finished I will publish the finished script here and my whole smart-trimming workflow on the video forum.
NickHope wrote on 10/2/2015, 6:11 AM
The updated script and accompanying workflow is described on the video forum here.
Warper wrote on 10/12/2015, 9:28 AM
Only a bit more precise is possible according to script API.
Take a look at TimeCode description:
Int64 Nanos Get or set the timecode's internal representation in hundred nanosecond units.

Something like clipOffsetAdjusted.Nanos/ 10000.0
It might be 10 times more precise than milliseconds.

On the other side, provided you have frame-accurate cuts, you can get framerate from project settings, FrameCount property of TimeCode and compute time with any precision you want.
NickHope wrote on 10/13/2015, 2:45 AM
Thanks Warper. The problems I had were because I was switching between units too early in the script. In the final version I made sure I was working in frames (integers) throughout the script, then converted to "double" only at the very last moment to get the value to write to the list. In this way the rounding errors disappeared.