DPX sequence to MOV script with Audio & TC - Batch not working
Copy link to clipboard
Copied
Can please someone here help me out on this topic, i am new to AFX/java scripting and i already spent around 15h on that
subject but it simply does not work-
the background:
we are shooting DPX sequences with a Convergent Design ODYSSEY SSD recorder, thats the only way for it to get perfect
image quality inside the box, i want 4:4:4 and RGB together with minimal compression (and the box is not yet able to do ProRes4444).
For editing/finishing purpose it is way easier to work with .MOV files instead of image sequences (as we are producing around 100.000 DPX files a day,
compared to around 80 .MOV files)
the task:
create a script that imports a DPX sequence from a folder,
imports the corresponding .WAV file with same starting name too,
creates a new timeline in AFX "from DPX sequence selection" (to keep the timcode!)
renders that timeline with a given output module to another given folder
deletes all items and projects afterwards
Somehow, I managed to do that, it works most of the time but function "app.executeCommand(app.findMenuCommandId("New Comp from Selection"
seems to be buggy somehow, does not work everytime or just after you did that at least once manually inside AFX ?
the bonus task (thats where i failed)
create a folder selection dialog that reads all subfolders (with the corresponding DPX sequences inside) to an array
use that array to get the sequence file names and count the number of Sub-directories
do the above (Seq conversion from "the task") to ALL THOSE SUBDIRECTORIES (using the names from the array)
this cant be that complex ... right ???
i tried to implement it but somehow i always get the error "/e/ODYSSEY/S020_AK0787/S020_AK0787_0000000.dpx is not a File or Folder"
(as this is the image sequence that should be imported - there must be some wrong interpretation between the file name with whole filepath and
the import function ?)
Any help is hugely appreciated, i am also willing to donate for help/a working script
(as i cannot afford to enter around 1.000 folders by myself)
i can also provide such a Odyssey file structure for testing/help purposes via wetransfer
thanks
Script below:
_______________________________________________________
var SourceFolder = Folder.selectDialog("Choose SOURCE folder: ");
var SourcePath = decodeURI(SourceFolder.toString());
var DestFolder = Folder.selectDialog("Choose DESTINATION folder: ");
var DestPath = decodeURI(DestFolder.toString());
var scriptName = "DPX Sequence TO MOV DNxHD with Audio + TC";
var intendedFootageFPS = 25;
var fileToImport, fileToImport2;sidecarFile, sidecarContents, importOpts, footageItem, filePath, fileBaseName, audioFile, audioFootageItem;
var FolderName, SourcePath;
var scriptName = "Change Render Locations";
function checkForFiles(folderItem, tabString) {
var theFiles = folderItem.getFiles();
for(var c = 0; c < theFiles.length; c++){
//resultArray.push(tabString + theFiles
resultArray.push(tabString + theFiles
//if (theFiles
{
// checkForFiles(theFiles
}
}
}
function AFXConvert(FolderName) {
app.newProject();
// fileToImport = File.openDialog("Select file from the DPX sequence", "*.dpx", false);
// if (!fileToImport || !fileToImport.exists) {
// }
app.beginUndoGroup(scriptName);
app.project.showWindow = true;
fileToImport2 = (SourcePath + "/"+ e + "/" + e + "_0000000.dpx");
alert("Folder Import Name " + fileToImport2);
importOpts = new ImportOptions(fileToImport2);
importOpts.sequence = true; // import as sequence
importOpts.forceAlphabetical = true; // force alphabetical order (to work around 3709647)
app.project.importFile(importOpts);
app.executeCommand(app.findMenuCommandId("New Comp from Selection"));
//app.executeCommand(app.findMenuCommandId("New Comp from Selection")); //sometimes it works better with 2 or 3x ???
//app.executeCommand(app.findMenuCommandId("New Comp from Selection"));
footageItem.name = decodeURI(fileToImport2.name).replace(/\.\d+\.png/, ""); // remove the numeric part for the footage item name
footageItem.mainSource.conformFrameRate = 25;
// if matching audio recording (WAV file), import that
filePath = footageItem.file.path;
fileBaseName = (footageItem.file.name).replace("_0000000.dpx","");
audioFile = new File(filePath + "/" + fileBaseName + ".WAV");
audioFootageItem = app.project.importFile(new ImportOptions(audioFile));
comp = app.project.item(1).layers.add(audioFootageItem);
audioFootageItem.selected = true;
comp.selected = true;
comp = app.project.item(1);
comp.openInViewer();
app.project.item(1).layer(2).moveToBeginning();
app.endUndoGroup();
app.project.renderQueue.items.add(comp);
app.project.renderQueue.item(1);
app.project.renderQueue.item(1).outputModule(1).file = new File("D:/" + e + ".MOV");
//alert("d:/" + fileBaseName + ".MOV");
app.project.renderQueue.item(1).outputModule(1).applyTemplate("QUICKTIME DNxHD 365 RGB444 Audio");
app.project.renderQueue.item(1).outputModule(1).postRenderAction.NONE;
app.project.renderQueue.render(1);
app.project.renderQueue.item(1).remove()
app.project.item(1).remove();
app.project.item(1).remove();
app.project.item(1).remove();
}
//----------------------------------------------------------------------------------------------------------------------------
//PROGRAM START
//----------------------------------------------------------------------------------------------------------------------------
app.project.close(CloseOptions.DO_NOT_SAVE_CHANGES);
if(SourceFolder != null){
var resultArray = new Array(1); //clear old array to 1 entry
var resultArray = new Array();
checkForFiles(SourceFolder, "");
$.writeln(resultArray.toString().replace("",""));
//alert(resultArray);
var FolderCount = resultArray.length;
alert("Number of folders: " + FolderCount);
}
if(DestFolder != null){ //Makes sure root folder choice was not canceled
var d1 = resultArray.toString();
}
//----ENCODING LOOP ----------------------------------------------------------
var e = resultArray.shift();
for(var k=0; k<FolderCount; k++){
alert("Array/Folder Counter: " + k +":" + e);
//resultArray.toString(resultArray);
fObj = Folder(DestPath + "/"+ e);
fObj.create();
AFXConvert(e);
var e = resultArray.shift();
}
Copy link to clipboard
Copied
It's not exactly what you describe, but it may be a good foundation to modify from. I put this together for my own internal batch processing of DPX sequences into Quicktime movies. There are three variables at the top that need to be manually changed for the render output names and structure. I've also only used this on Mac, so I'm not sure if it works on Windows properly yet.
{
try{
/*
MANUALLY TYPE IN THE VALUES FOR THE NEXT VARIABLES--------------------
*/
var renderSettingChoice = "Best Settings";
var outputModuleChoice = "Client_LowRezPreview";
var fileNameExpression = "[projectName]_[compName].[fileExtension]"; //Uses After Effects "Output To" syntax
/*
END USER INPUT--------------------------------------------------------------------------------
*/
var os = ($.os.indexOf("Mac") != (-1)); //True is MAC, false is PC
var sep = (os == true) ? "/" : "\\";
var dpxFolder = Folder.selectDialog("Choose folder containing source DPX folders.");
var renderToFolder = Folder.selectDialog("Select folder to render to.");
var globalFPS = 25;
if(dpxFolder != null){
if(renderToFolder != null){
//Declare Variables
var allSubFolders, allSubFoldersLen, curFolder, dpxFrames, dpxFramesLen, curDPXFrame, nameSplit, dpxFramesCollect, dpxFramesCollectLen, dpxName, dpxDuration, dpxStartFrame, dpxFPS, io, dpxImported, newDPXComp, newQueueItem, fullFilePath;
allSubFolders = dpxFolder.getFiles(); //Get all files inside folder
allSubFoldersLen = allSubFolders.length;
dpxFramesCollect = new Array();
app.beginUndoGroup("Convert DPX to QT");
//Process Main folder
for(var f=0; f<allSubFoldersLen; f++){
dpxFramesCollect.length = 0;
curFolder = allSubFolders
; dpxName = curFolder.displayName;
//Begin per DPX seq processing
if(curFolder instanceof Folder){ //Verify item is a folder object otherwise skip to next item
dpxFrames = curFolder.getFiles(); //Get all DPX frames
dpxFramesLen = dpxFrames.length;
for(var d=0; d<dpxFramesLen; d++){
curDPXFrame = dpxFrames
; nameSplit = curDPXFrame.displayName.split(".");
ext = nameSplit[nameSplit.length-1];
if(ext == "DPX" || ext = "dpx"){ //Verify file is a DPX frame
dpxFramesCollect.push(curDPXFrame);
}
}
dpxFramesCollectLen = dpxFramesCollect.length;
dpxFramesCollect.sort();
if(dpxFramesCollectLen > 0){ //Checks if more than 0 DPX frames exists.
firstFrame = dpxFramesCollect[0];
dpxFPS = globalFPS;
io = new ImportOptions(firstFrame);
io.sequence = true;
dpxImported = app.project.importFile(io);
dpxImported.mainSource.conformFrameRate = dpxFPS;
newDPXComp = app.project.items.addComp(dpxName, dpxImported.width, dpxImported.height, dpxImported.pixelAspect, dpxImported.duration, dpxFPS); //Makes new comp
dpxStartFrame = (Number(firstFrame.displayName.split(".")[1]) * newDPXComp.frameDuration) + 0.01; //0.01 helps fix (mostly) the frameDuration math
newDPXComp.displayStartTime = dpxStartFrame;
newDPXComp.layers.add(dpxImported); //Adds footage to comp
newQueueItem = app.project.renderQueue.items.add(newDPXComp); //Adds comp to renderqueue
newQueueItem.applyTemplate(renderSettingChoice);
newQueueItem.outputModule(1).applyTemplate(outputModuleChoice);
fullFilePath = renderToFolder.toString() + sep + dpxName;
if(!fullFilePath.exists){ //Creates render folder if it does not already exist
Folder(fullFilePath).create();
}
newQueueItem.outputModule(1).file = File(fullFilePath + sep + fileNameExpression); //Sets Output To file
}
}
}
app.endUndoGroup();
}else{
alert("Folder selection for rendering was canceled.");
}
}else{
alert("DPX folder selection was canceled.");
}
}catch(e){alert(e.line.toString() + "\n" + e.toString())}
}
Copy link to clipboard
Copied
Thank you David, appreciate it!
I will check it out on the weekend and report back to you 🙂
Copy link to clipboard
Copied
This will not work if the filename has any periods in it:
nameSplit = curDPXFrame.displayName.split(".");
This is a much better way to detect an extension in a filename:
nameSplit = curDPXFrame.displayName.match(/[^\.]+$/);
And this will match regardless of case:
if(ext.toUpperCase() == "DPX"){
Cheers,
Lloyd
Copy link to clipboard
Copied
This will not work if the filename has any periods in it:
Which is why I added the next variable that grabs the last item in that split, but of course neither option will work if the extension is hidden and not part of the name.
ext = nameSplit[nameSplit.length-1];
.match(/[^\.]+$/);
As much as I love to use Regular Expressions, their syntax can be extremely confusing for new learners. Which is why I steer away from it most times. It is powerful stuff though, I will not deny that.
Copy link to clipboard
Copied
I'm currently trying to batch some DPX's in folders to Quicktimes (using the folder names as filenames). David's Script looked really useful, but I had a few error messages when I tried to run it (first due to the position of the Undogroup, then afterwards due to it not ignoring mac .DS_Store system files). I've done some small bug fixes now and here's the updated script, which seems to work OK. I've also moved the "GlobalFPS" variable into the user variable section at the top (should really make that a dialog box too, I guess)
Here's the updated script (tested in CC2017):
{
try{
/*
MANUALLY TYPE IN THE VALUES FOR THE NEXT VARIABLES--------------------
*/
var renderSettingChoice = "Best Settings";
var outputModuleChoice = "ProRes4444 trillions"; // type in the name of the default output module you want to assign here
var fileNameExpression = "[projectName]_[compName].[fileExtension]"; //Uses After Effects "Output To" syntax
var globalFPS = 24; // moved this into the user variables - set the correct frame rate here
/*
END USER INPUT--------------------------------------------------------------------------------
*/
var os = ($.os.indexOf("Mac") != (-1)); //True is MAC, false is PC
var sep = (os == true) ? "/" : "\\";
var dpxFolder = Folder.selectDialog("Choose folder containing source DPX folders.");
var renderToFolder = Folder.selectDialog("Select folder to render to.");
if(dpxFolder != null){
if(renderToFolder != null){
app.beginUndoGroup("Convert DPX to QT");
//Declare Variables
var allSubFolders, allSubFoldersLen, curFolder, dpxFrames, dpxFramesLen, curDPXFrame, nameSplit, dpxFramesCollect, dpxFramesCollectLen, dpxName, dpxDuration, dpxStartFrame, dpxFPS, io, dpxImported, newDPXComp, newQueueItem, fullFilePath;
allSubFolders = dpxFolder.getFiles(); //Get all files inside folder
allSubFoldersLen = allSubFolders.length;
dpxFramesCollect = new Array();
//Process Main folder
for(var f=0; f<allSubFoldersLen; f++){
dpxFramesCollect.length = 0;
curFolder = allSubFolders
; dpxName = curFolder.displayName;
//Begin per DPX seq processing
if(curFolder instanceof Folder){ //Verify item is a folder object otherwise skip to next item
dpxFrames = curFolder.getFiles(); //Get all DPX frames
dpxFramesLen = dpxFrames.length;
for(var d=0; d<dpxFramesLen; d++){
curDPXFrame = dpxFrames
; nameSplit = curDPXFrame.displayName.split(".");
ext = nameSplit[nameSplit.length-1];
if(ext == "DPX" || ext = "dpx" && ext != "DS_Store"){ //Verify file is a DPX frame
dpxFramesCollect.push(curDPXFrame);
}
}
dpxFramesCollectLen = dpxFramesCollect.length;
dpxFramesCollect.sort();
if(dpxFramesCollectLen > 0){ //Checks if more than 0 DPX frames exists.
firstFrame = dpxFramesCollect[0];
dpxFPS = globalFPS;
io = new ImportOptions(firstFrame);
io.sequence = true;
dpxImported = app.project.importFile(io);
dpxImported.mainSource.conformFrameRate = dpxFPS;
newDPXComp = app.project.items.addComp(dpxName, dpxImported.width, dpxImported.height, dpxImported.pixelAspect, dpxImported.duration, dpxFPS); //Makes new comp
dpxStartFrame = (Number(firstFrame.displayName.split(".")[1]) * newDPXComp.frameDuration) + 0.01; //0.01 helps fix (mostly) the frameDuration math
newDPXComp.displayStartTime = dpxStartFrame;
newDPXComp.layers.add(dpxImported); //Adds footage to comp
newQueueItem = app.project.renderQueue.items.add(newDPXComp); //Adds comp to renderqueue
newQueueItem.applyTemplate(renderSettingChoice);
newQueueItem.outputModule(1).applyTemplate(outputModuleChoice);
fullFilePath = renderToFolder.toString() + sep + dpxName;
if(!fullFilePath.exists){ //Creates render folder if it does not already exist
Folder(fullFilePath).create();
}
newQueueItem.outputModule(1).file = File(fullFilePath + sep + fileNameExpression); //Sets Output To file
}
}
}
app.endUndoGroup();
}else{
alert("Folder selection for rendering was canceled.");
}
}else{
alert("DPX folder selection was canceled.");
}
}catch(e){alert(e.line.toString() + "\n" + e.toString())}
}

