I've been working on a script, the reason for which is discussed here on the video forum. Rather than explain it again, it's easiest to read the purpose in the top lines of the code below.
In this first version, the end of the event does not become correctly quantized to the end of the media's video stream. It's a frame or two too long or too short. I think this may be because of problems with the way I'm setting eventLengthTC in line 75 of the script. Instead, I want to try explicitly setting it by multiplying the number of frames in the video stream by the target frame rate, but I don't know how to convert that "double" value (e.g. 149.8501498501499 for a 5 second event) into a Vegas timecode. My failed effort is shown in lines 77 and 78.
Can anyone tell me how to convert double to timecode (or suggest another way of doing it)?
(p.s. Further development of the script would be most welcome, if anyone has the mood. After this change it still might not be frame accurate at the end, and it could also do with code to close the gaps on the timeline.)
In this first version, the end of the event does not become correctly quantized to the end of the media's video stream. It's a frame or two too long or too short. I think this may be because of problems with the way I'm setting eventLengthTC in line 75 of the script. Instead, I want to try explicitly setting it by multiplying the number of frames in the video stream by the target frame rate, but I don't know how to convert that "double" value (e.g. 149.8501498501499 for a 5 second event) into a Vegas timecode. My failed effort is shown in lines 77 and 78.
Can anyone tell me how to convert double to timecode (or suggest another way of doing it)?
(p.s. Further development of the script would be most welcome, if anyone has the mood. After this change it still might not be frame accurate at the end, and it could also do with code to close the gaps on the timeline.)
//* Quantize_Frames.cs
//*
//* Written by Nick Hope, based on Fix30pMedia.cs, written by John Rofrano
//* and modified by wwaag. Quantization code based on quantize_selected.js
//* written by Randall Campbell. Notes from those 2 programs shown below,
//* including copyright information.
//*
//* The script is useful for quantizing variable frame rate media such as that
//* recorded by some mobile phones, wherein the file is reported as variable
//* frame rate but does in fact exhibit video of a constant (but non-standard)
//* frame rate when placed on the Vegas timeline.
//*
//* To use, set the targetfps variable in the script to the desiered frame rate, then
//* select events on the timeline and run script.
//*
//* This script sets the project frame rate to your target frame rate, then
//* stretches or squeezes selected events so that their frames line up with the
//* timeline's frame intervals, and it quantizes the start and end of the event,
//* trimming the length of the audio stream to that of the video stream.
//*
//* This script will not work on video that has a truly variable frame rate.
//*
//* Because of bugs in Vegas decoders, files placed on the timeline may have repeat
//* frames at the start or end. You can remove those before after this script by
//* downloading the following script, written by jonask:
//* https://dl.dropboxusercontent.com/u/21489814/Trim Captured Clips v1.0.cs
//*
//* Feb 6, 2016 (NH) End of file is not correctly quantized to the end of the media's video stream
//*
//****************************************************************************
//* Program: Fix30pMedia.cs
//* Author: John Rofrano
//* Description: This script changes the playback rate of 30p media to 29.97
//* Created: July 25, 2010
//* Updated: Jul 28, 2010 (JR) Added Disable Resample
//* Aug 4, 2010 (JR) Changed audio to match video
//* Feb 3, 2016 (JR) Changed to only process selected events
//* Feb 4, 2016 (wwaag) Changed to process media of any frame rate
//*
//* Copyright: (c) 2010, 2016 Sundance Media Group / VASST. All Rights Reserved
//****************************************************************************
// Author: Randall Campbell, info@peachrock.com, www.peachrock.com
// © Copyright 2004-2005, Peach Rock Productions, LLC.
// You are free to use or modify this code as long as the copyright information is not removed.
// This software is provided AS IS, no warranty is expressed or implied
//****************************************************************************
using System;
using System.Collections;
using System.Windows.Forms;
using Sony.Vegas;
class EntryPoint
{
public void FromVegas(Vegas vegas)
{
double targetfps = 29.97002997002997; // for 60p change to 59.94005994005994
vegas.Project.Video.FrameRate = targetfps;
int counter = 0;
try
{
foreach (Track track in vegas.Project.Tracks)
{
if (!track.IsVideo()) continue;
foreach (VideoEvent videoEvent in track.Events)
{
// Only process selected events
if (!videoEvent.Selected) continue;
VideoStream videoStream = videoEvent.ActiveTake.MediaStream as VideoStream;
int videoStreamFrames = (int)videoEvent.ActiveTake.MediaStream.Length.FrameCount;
//THE LINE BELOW SORT OF WORKS BUT IS NOT FRAME ACCURATE. MAYBE IT'S USING THE FRAME RATE OF THE MEDIA, NOT THE PROJECT
Timecode eventLengthTC = Timecode.FromFrames(videoStreamFrames);
//THE 2 LINES BELOW MAY BE MORE ACCURATE THAN THE ABOVE ONE BUT I DON'T KNOW HOW TO CONVERT eventLength INTO TIMECODE. HELP!
// double eventLength = videoStreamFrames * targetfps;
// Timecode eventLengthTC = Timecode(eventLength);
double adjust = 1.0 /(videoStream.FrameRate / targetfps);
videoEvent.AdjustPlaybackRate(adjust, true);
if (videoStream.FrameRate > targetfps) videoEvent.UnderSampleRate = adjust;
videoEvent.ResampleMode = VideoResampleMode.Disable;
Timecode eventStart = Quantize(videoEvent.Start);
Timecode eventEnd = Quantize(videoEvent.Start + eventLengthTC);
videoEvent.AdjustStartLength(eventStart, eventEnd - eventStart, true);
counter++;
// check for audio in the same file and change it too
if (videoEvent.IsGrouped)
{
foreach (TrackEvent trackEvent in videoEvent.Group)
{
if (!trackEvent.IsAudio()) continue;
// see if they are from the same file
if (trackEvent.ActiveTake != null && trackEvent.ActiveTake.MediaPath.Equals(videoEvent.ActiveTake.MediaPath))
{
AudioEvent audioEvent = trackEvent as AudioEvent;
audioEvent.AdjustPlaybackRate(adjust, true);
trackEvent.AdjustStartLength(eventStart, eventEnd - eventStart, true);
}
}
}
}
}
// let the user know we are done
MessageBox.Show(String.Format("{0} events changed", counter), "Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Unexpected Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
// Round the timecode value to the nearest frame
// Returns the quantized timecode value
Timecode Quantize ( Timecode timecode )
{
Timecode newTimecode = new Timecode();
newTimecode.Nanos = timecode.Nanos;
long originalNanos = newTimecode.Nanos;
newTimecode.FrameCount = newTimecode.FrameCount;
long nano1 = newTimecode.Nanos;
newTimecode.FrameCount = newTimecode.FrameCount + 1;
long nano2 = newTimecode.Nanos;
long nanoMiddle = Convert.ToInt64((nano2 - nano1) / 2);
if (originalNanos < nano1 + nanoMiddle)
newTimecode.FrameCount = newTimecode.FrameCount - 1;
return newTimecode;
}
}