The purpose of this post is twofold:
1. To provide a script that solves a problem (that admittedly probably plagues only a few people). Code is below.
2. To ask for help in accessing QuickTime from within a script (to get a QuickTime timecode from the file). See question in bold below.
Background: This is my first script and first time using C#. I had programmed quite a bit in C about a decade ago.
As you can see from the comments, this script has a very narrow purpose: to assign a timecode (custom timecode) so that an exported XML will have the timecode embedded in it (to be used to match the source files in Resolve). This issue is describe in excruciating detail in this thread (end is more relevant): http://www.sonycreativesoftware.com/forums/ShowMessage.asp?MessageID=853855&Replies=51.
This works on BMCC files as intended. However, there are other files that would benefit from this (e.g., Canon 5D Mark III files) and I don't think this is a great way to do this.
The key problem is that Vegas Pro 12 (Build 486) does not read the timecode record from a QuickTime file.
It seems like a much more elegant and robust solution would be to use a script to call QuickTime methods to get the timecode directly from the timecode embedded in the file. As you can see, this current script only infers it from the file name and file properties (e.g., date modified).
Question: Has anyone written a script to interact with QuickTime?
If so, I'm looking for the right "using" directives syntax. This appears to be possible. I found some QuickTime documentation that lists the data structures, etc. However, being my first time out with C# (and .Net?), I couldn't see how to get the Interop to work. So, that's the hurdle, if someone can point me in the right direction (or tell me that it isn't possible), it would be greatly appreciated!
1. To provide a script that solves a problem (that admittedly probably plagues only a few people). Code is below.
2. To ask for help in accessing QuickTime from within a script (to get a QuickTime timecode from the file). See question in bold below.
Background: This is my first script and first time using C#. I had programmed quite a bit in C about a decade ago.
As you can see from the comments, this script has a very narrow purpose: to assign a timecode (custom timecode) so that an exported XML will have the timecode embedded in it (to be used to match the source files in Resolve). This issue is describe in excruciating detail in this thread (end is more relevant): http://www.sonycreativesoftware.com/forums/ShowMessage.asp?MessageID=853855&Replies=51.
This works on BMCC files as intended. However, there are other files that would benefit from this (e.g., Canon 5D Mark III files) and I don't think this is a great way to do this.
The key problem is that Vegas Pro 12 (Build 486) does not read the timecode record from a QuickTime file.
It seems like a much more elegant and robust solution would be to use a script to call QuickTime methods to get the timecode directly from the timecode embedded in the file. As you can see, this current script only infers it from the file name and file properties (e.g., date modified).
Question: Has anyone written a script to interact with QuickTime?
If so, I'm looking for the right "using" directives syntax. This appears to be possible. I found some QuickTime documentation that lists the data structures, etc. However, being my first time out with C# (and .Net?), I couldn't see how to get the Interop to work. So, that's the hurdle, if someone can point me in the right direction (or tell me that it isn't possible), it would be greatly appreciated!
/**
This script adds a Tape Name (turns out to be useless) and Starting Time Code (critical) to
a media file's properties based on a file's name or date properties for .mov files created by the
Blackmagic Design Cinema Camera (BMCC) or by Davinci Resolve from the BMCC's raw .dng files.
The purpose of assigning a Starting T/C is for exporting an XML file from Vegas Pro 12
that can be imported in Resolve and matched to the original source files. In this case,
the original source files are the original BMCC .dng or .mov files.
This script relies on the BMCC's naming convention of having a clip number (e.g., C0001).
The workflow should be as follows for using BMCC footage with Resolve and Vegas Pro 12:
1. In Resolve: Add any BMCC raw .dng and .mov (DNxHD) files to a project's media pool.
1a. Render ONLY the .dng files to QuickTime .mov files using DNxHD encoding. Note: Do not
re-render the original BMCC .mov DNxHD files.
2. In Vegas Pro 12: Load the .mov (DNxHD) files into a project and edit.
2a. Run this script. It should ignore anything other than BMCC files based on the naming convention.
2b. Export an XML file using File->Export->Final Cut Pro 7/DaVinci Resolve (*.xml)...
Do not choose to copy the media pool.
3. In Resolve: In Conform, import the XML file, making sure to uncheck the box
that reads, "Automatically import source clips into media pool". This should import
the timeline and link your BMCC files to the original source files.
Anything beyond Step 3 is beyond the scope of this script.
Revised March 30, 2013
by Jason Greene
You may freely use, alter, and distribute this script as long as this comment information remains.
I would appreciate it if you would share any improvements to this script.
Notes:
0. This is script is necessary because Vegas Pro 12 Build 486 does not read the timecode from QuickTime files.
1. This is a ridiculously round-about and clunky way of inferring the timecode from a file based entirely
on how it appears BMCC files are named by both the BMCC and Resolve 9.1.1 and how their timecodes are determined.
This is subject to change in firmware updates to the BMCC and/or new versions of Resolve.
2. A more elegant way of doing this would be to call QuickTime methods to obtain the actual timecode from the
file itself. If anyone has experience in accessing QuickTime from a script, this would be great to add/replace
this entire script.
3. I have tried to manage exceptions, but I'm sure I missed some.
**/
using System;
using Sony.Vegas;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
class EntryPoint
{
public void FromVegas(Vegas vegas)
{
StringBuilder msg = new StringBuilder();
msg.Append("The following files were processed:\r\n");
foreach (Media media in vegas.Project.MediaPool)
{
if(!media.IsGenerated() && media.HasVideo())
{
media.TapeName = SetTapeName(media);
msg.Append("Tape Name: ");
msg.Append(media.TapeName = SetTapeName(media));
msg.Append("\r\n");
if (SetTimecode(media))
{
msg.Append("TimecodeIn: ");
msg.Append(media.TimecodeIn);
msg.Append("\r\n");
}
}
}
MessageBox.Show(msg.ToString());
}
bool SetTimecode(Media media)
{
int intFrames, movNum, c0, c1, strNum;
string strFrames;
//The starting T/C in BMCC .dng files is appended by Resolve to the filename
//after the C00xx and just before .mov as _framecount
movNum = media.FilePath.IndexOf(".mov");
if(movNum < 0) //Make sure it is even a QuickTime container
{
return false;
}
c0 = media.FilePath.IndexOf("C00",media.FilePath.Length-20); //Search for C00xx to identify it as a BMCC file
if(c0 < 0)
{
return false;
}
c1 = media.FilePath.IndexOf("_",c0); //Look for Resolve's rendering of .dng file to .mov file
if(c1 < 0)
{
return SetTimecodeUsingFileDate(media); //This handles BMCC original DNxHD .mov files
}
strFrames = media.FilePath.Substring(c1+1,movNum-c1-1);
intFrames = Convert.ToInt32(strFrames);
Timecode tcode = Timecode.FromFrames(intFrames);
media.TimecodeIn = tcode;
media.UseCustomTimecode = true;
return true;
}
bool SetTimecodeUsingFileDate(Media media)
{
DateTime utc;
int fps = 0;
utc = File.GetLastWriteTimeUtc(media.FilePath);
//The starting T/C in BMCC DNxHD is the recording time HH:MM:SS:00
switch(media.RulerFormat)
{
case RulerFormat.SmpteFilmSyncIVTC:
case RulerFormat.SmpteFilmSync:
fps = 24;
break;
case RulerFormat.SmpteEBU:
fps = 25;
break;
case RulerFormat.SmpteNonDrop:
case RulerFormat.SmpteDrop:
case RulerFormat.Smpte30:
fps = 30;
break;
default:
fps = 0;
break;
}
media.TimecodeIn = Timecode.FromFrames( (utc.Hour*60*60 + utc.Minute*60 + utc.Second)*fps );
return true;
}
String SetTapeName(Media media)
{
int c0, c1, lastSlash = 0,thisSlash = 0, lastDot = 0, thisDot = 0;
String strResult;
if(media.FilePath.Length < 1){
return "Media";
}
//Find filename, not path
while(thisSlash > -1)
{
lastSlash = thisSlash;
thisSlash = media.FilePath.IndexOf("\\",lastSlash + 1);
}
if(lastSlash < 1){
return "Media";
}
//Find file extension
while(thisDot > -1)
{
lastDot = thisDot;
thisDot = media.FilePath.IndexOf(".",lastDot + 1);
}
if(lastDot < 1){
return "Media";
}
c0 = media.FilePath.IndexOf("C00",media.FilePath.Length-20);
if(c0 < 0)
{
if(lastDot > lastSlash)
{
return media.FilePath.Substring(lastSlash + 1,lastDot - lastSlash - 1);
}else{
return media.FilePath.Substring(lastSlash + 1,media.FilePath.Length - lastSlash - 1);
}
}
c1 = media.FilePath.IndexOf("_",c0);
if(c1 < 0)
{
if(lastDot > lastSlash)
{
return media.FilePath.Substring(lastSlash + 1,lastDot - lastSlash - 1);
}else{
return media.FilePath.Substring(lastSlash + 1,media.FilePath.Length - lastSlash - 1);
}
}
if(c1 > lastSlash)
{
return media.FilePath.Substring(lastSlash + 1,c1 - lastSlash - 1);
}else{
return media.FilePath.Substring(lastSlash + 1,media.FilePath.Length - lastSlash - 1);
}
return "Tape Name";
}
}