Skip to content

Instantly share code, notes, and snippets.

@dancbruce
Created April 6, 2020 12:35
Show Gist options
  • Save dancbruce/aaddcea25629853cae19ad7c2bf5f2fc to your computer and use it in GitHub Desktop.
Save dancbruce/aaddcea25629853cae19ad7c2bf5f2fc to your computer and use it in GitHub Desktop.
FFmpegAutoSubmission
from System.Collections.Specialized import *
from System.IO import *
from System.Text import *
from Deadline.Scripting import *
from DeadlineUI.Controls.Scripting.DeadlineScriptDialog import DeadlineScriptDialog
########################################################################
## Globals
########################################################################
scriptDialog = None
settings = None
########################################################################
## Main Function Called By Deadline
########################################################################
def __main__():
global scriptDialog
global settings
scriptDialog = DeadlineScriptDialog()
selectedJobs = MonitorUtils.GetSelectedJobs()
if len(selectedJobs) > 1:
scriptDialog.ShowMessageBox( "Only one job can be selected at a time.", "Multiple Jobs Selected" )
return
job = selectedJobs[0]
outputFilenameCount = len(job.JobOutputFileNames)
scriptDialog.SetTitle( "Submit FFmpeg Job To Deadline" )
scriptDialog.SetIcon( scriptDialog.GetIcon( 'FFmpeg' ) )
scriptDialog.AddTabControl("Tabs", 0, 0)
scriptDialog.AddTabPage("Job Options")
scriptDialog.AddGrid()
scriptDialog.AddControlToGrid( "Separator1", "SeparatorControl", "Job Description", 0, 0 )
scriptDialog.EndGrid()
scriptDialog.AddGrid()
scriptDialog.AddControlToGrid( "NameLabel", "LabelControl", "Job Name", 0, 0, "The name of your job. This is optional, and if left blank, it will default to 'Untitled'.", False )
scriptDialog.AddControlToGrid( "NameBox", "TextControl", job.JobName, 0, 1 )
scriptDialog.AddControlToGrid( "CommentLabel", "LabelControl", "Comment", 1, 0, "A simple description of your job. This is optional and can be left blank.", False )
scriptDialog.AddControlToGrid( "CommentBox", "TextControl", "mp4 video", 1, 1 )
scriptDialog.AddControlToGrid( "DepartmentLabel", "LabelControl", "Department", 2, 0, "The department you belong to. This is optional and can be left blank.", False )
scriptDialog.AddControlToGrid( "DepartmentBox", "TextControl", "", 2, 1 )
scriptDialog.EndGrid()
scriptDialog.AddGrid()
scriptDialog.AddControlToGrid( "Separator2", "SeparatorControl", "Job Options", 0, 0 )
scriptDialog.EndGrid()
scriptDialog.AddGrid()
scriptDialog.AddControlToGrid( "PoolLabel", "LabelControl", "Pool", 0, 0, "The pool that your job will be submitted to.", False )
scriptDialog.AddControlToGrid( "PoolBox", "PoolComboControl", "none", 0, 1 )
scriptDialog.AddControlToGrid( "SecondaryPoolLabel", "LabelControl", "Secondary Pool", 1, 0, "The secondary pool lets you specify a Pool to use if the primary Pool does not have any available Workers.", False )
scriptDialog.AddControlToGrid( "SecondaryPoolBox", "SecondaryPoolComboControl", "", 1, 1 )
scriptDialog.AddControlToGrid( "GroupLabel", "LabelControl", "Group", 2, 0, "The group that your job will be submitted to.", False )
scriptDialog.AddControlToGrid( "GroupBox", "GroupComboControl", "none", 2, 1 )
scriptDialog.AddControlToGrid( "PriorityLabel", "LabelControl", "Priority", 3, 0, "A job can have a numeric priority ranging from 0 to 100, where 0 is the lowest priority and 100 is the highest priority.", False )
scriptDialog.AddRangeControlToGrid( "PriorityBox", "RangeControl", RepositoryUtils.GetMaximumPriority() / 2, 0, RepositoryUtils.GetMaximumPriority(), 0, 1, 3, 1 )
scriptDialog.AddControlToGrid( "TaskTimeoutLabel", "LabelControl", "Task Timeout", 4, 0, "The number of minutes a Worker has to render a task for this job before it requeues it. Specify 0 for no limit.", False )
scriptDialog.AddRangeControlToGrid( "TaskTimeoutBox", "RangeControl", 0, 0, 1000000, 0, 1, 4, 1 )
scriptDialog.AddSelectionControlToGrid( "AutoTimeoutBox", "CheckBoxControl", False, "Enable Auto Task Timeout", 4, 2, "If the Auto Task Timeout is properly configured in the Repository Options, then enabling this will allow a task timeout to be automatically calculated based on the render times of previous frames for the job. ", False )
scriptDialog.AddControlToGrid( "ConcurrentTasksLabel", "LabelControl", "Concurrent Tasks", 5, 0, "The number of tasks that can render concurrently on a single Worker. This is useful if the rendering application only uses one thread to render and your Workers have multiple CPUs.", False )
scriptDialog.AddRangeControlToGrid( "ConcurrentTasksBox", "RangeControl", 1, 1, 16, 0, 1, 5, 1 )
scriptDialog.AddSelectionControlToGrid( "LimitConcurrentTasksBox", "CheckBoxControl", True, "Limit Tasks To Worker's Task Limit", 5, 2, "If you limit the tasks to a Worker's task limit, then by default, the Worker won't dequeue more tasks then it has CPUs. This task limit can be overridden for individual Workers by an administrator." )
scriptDialog.AddControlToGrid( "MachineLimitLabel", "LabelControl", "Machine Limit", 6, 0, "Use the Machine Limit to specify the maximum number of machines that can render your job at one time. Specify 0 for no limit.", False )
scriptDialog.AddRangeControlToGrid( "MachineLimitBox", "RangeControl", 0, 0, 1000000, 0, 1, 6, 1 )
scriptDialog.AddSelectionControlToGrid( "IsBlacklistBox", "CheckBoxControl", False, "Machine List Is A Blacklist", 6, 2, "You can force the job to render on specific machines by using a whitelist, or you can avoid specific machines by using a blacklist." )
scriptDialog.AddControlToGrid( "MachineListLabel", "LabelControl", "Machine List", 7, 0, "The whitelisted or blacklisted list of machines.", False )
scriptDialog.AddControlToGrid( "MachineListBox", "MachineListControl", "", 7, 1, colSpan=2 )
scriptDialog.AddControlToGrid( "LimitGroupLabel", "LabelControl", "Limits", 8, 0, "The Limits that your job requires.", False )
scriptDialog.AddControlToGrid( "LimitGroupBox", "LimitGroupControl", "", 8, 1, colSpan=2 )
scriptDialog.AddControlToGrid( "DependencyLabel", "LabelControl", "Dependencies", 9, 0, "Specify existing jobs that this job will be dependent on. This job will not start until the specified dependencies finish rendering.", False )
scriptDialog.AddControlToGrid( "DependencyBox", "DependencyControl", job.JobId , 9, 1, colSpan=2 )
scriptDialog.AddControlToGrid( "OnJobCompleteLabel", "LabelControl", "On Job Complete", 10, 0, "If desired, you can automatically archive or delete the job when it completes.", False )
scriptDialog.AddControlToGrid( "OnJobCompleteBox", "OnJobCompleteControl", "Nothing", 10, 1 )
scriptDialog.AddSelectionControlToGrid( "SubmitSuspendedBox", "CheckBoxControl", False, "Submit Job As Suspended", 10, 2, "If enabled, the job will submit in the suspended state. This is useful if you don't want the job to start rendering right away. Just resume it from the Monitor when you want it to render." )
scriptDialog.EndGrid()
scriptDialog.AddGrid()
scriptDialog.AddControlToGrid( "Separator3", "SeparatorControl", "FFmpeg Options", 0, 0, colSpan=2 )
outputFilename = Path.Combine( job.JobOutputDirectories[0], job.JobOutputFileNames[0])
outputFilename = FrameUtils.ReplacePaddingWithFrameNumber( outputFilename, job.JobFramesList[0] )
scriptDialog.AddControlToGrid( "Input0Label", "LabelControl", "Input File", 1, 0, "The input file to process.", False )
scriptDialog.AddSelectionControlToGrid( "Input0Box", "FileBrowserControl", outputFilename, "AVI Files (*.avi);;M2V Files (*.m2v);;MPG Files (*.mpg);;VOB Files (*.vob);;WAV Files (*.wav);;All Files (*)", 1, 1 )
scriptDialog.AddControlToGrid( "Input0ArgsLabel", "LabelControl", "Input Arguments", 2, 0, "Additional command line arguments for the input file. ", False )
scriptDialog.AddControlToGrid( "Input0ArgsBox", "TextControl", "-gamma 2.2 -start_number "+str(job.JobFramesList[0])+" -framerate 24", 2, 1 )
scriptDialog.AddSelectionControlToGrid( "Input0ReplacePaddingBox", "CheckBoxControl", True, "Replace Frame in Input File(s) With Padding (file%04d.ext)", 3, 1, "If enabled, the frame number in the file name will be replaced by frame padding before being passed to FFMpeg. This should be enabled if you are passing a sequence of images as input." )
listFileName = outputFilename.split('.')
videoFileName = listFileName[0]+'.mp4'
scriptDialog.AddControlToGrid("OutputLabel","LabelControl","Output File", 4, 0, "The output file path.", False)
scriptDialog.AddSelectionControlToGrid("OutputBox","FileSaverControl", videoFileName , "All Files (*)", 4, 1 )
scriptDialog.AddControlToGrid( "OutputArgsLabel", "LabelControl", "Output Arguments", 5, 0, "Additional command line arguments for the output file. ", False )
scriptDialog.AddControlToGrid( "OutputArgsBox", "TextControl", "-crf 23 -pix_fmt yuv420p", 5, 1 )
scriptDialog.AddControlToGrid( "AdditionalArgsLabel", "LabelControl", "Additional Arguments", 6, 0, "Additional general command line arguments.", False )
scriptDialog.AddControlToGrid( "AdditionalArgsBox", "TextControl", "", 6, 1 )
scriptDialog.EndGrid()
scriptDialog.EndTabPage()
scriptDialog.AddTabPage("Additional Input Files")
scriptDialog.AddGrid()
scriptDialog.AddControlToGrid( "Separator4", "SeparatorControl", "Additional Input Files", 0, 0, colSpan=2 )
useSameArgsBox = scriptDialog.AddSelectionControlToGrid( "UseSameArgsBox", "CheckBoxControl", False, "All Inputs Use Same Arguments as Input 1", 1, 0, "If enabled, all additional input files will use the same arguments as the main input file.", False )
useSameArgsBox.ValueModified.connect( UseSameArgsModified )
scriptDialog.EndGrid()
scriptDialog.AddGrid()
currRow = 0
for i in range(1,9):
scriptDialog.AddControlToGrid( "Input%dLabel" % i, "LabelControl", "Input File %d" % (i + 1), currRow, 0, "An additional input file to process.", False )
scriptDialog.AddSelectionControlToGrid( "Input%dBox" % i, "FileBrowserControl", "", "AVI Files (*.avi);;M2V Files (*.m2v);;MPG Files (*.mpg);;VOB Files (*.vob);;WAV Files (*.wav);;All Files (*)", currRow, 1, colSpan=2 )
currRow += 1
scriptDialog.AddControlToGrid( "Input%dArgsLabel" % i, "LabelControl", "Input Arguments %d" % (i + 1), currRow, 0, "Additional command line arguments for the input file above.", False )
scriptDialog.AddControlToGrid( "Input%dArgsBox" % i, "TextControl", "", currRow, 1 )
scriptDialog.AddSelectionControlToGrid( "Input%dReplacePaddingBox" % i, "CheckBoxControl", True, "Replace Padding", currRow, 2, "If enabled, the frame number in the file name will be replaced by frame padding before being passed to FFMpeg. This should be enabled if you are passing a sequence of images as input.", expand = False )
currRow += 1
scriptDialog.EndGrid()
scriptDialog.EndTabPage()
scriptDialog.AddTabPage("FFmpeg Preset Files")
scriptDialog.AddGrid()
scriptDialog.AddControlToGrid( "Separator5", "SeparatorControl", "FFmpeg Preset Files", 0, 0, colSpan=2 )
scriptDialog.AddControlToGrid( "VideoPresetLabel", "LabelControl", "Video Preset File", 1, 0, "The video preset file.", False )
scriptDialog.AddSelectionControlToGrid( "VideoPresetBox", "FileBrowserControl", "", "FFmpeg Preset (*.ffpreset);;All Files (*)", 1, 1 )
scriptDialog.AddControlToGrid( "AudioPresetLabel", "LabelControl", "Audio Preset File", 2, 0, "The audio preset file.", False )
scriptDialog.AddSelectionControlToGrid( "AudioPresetBox", "FileBrowserControl", "", "FFmpeg Preset (*.ffpreset);;All Files (*)", 2, 1 )
scriptDialog.AddControlToGrid( "SubtitlePresetLabel", "LabelControl", "Subtitle Preset File", 3, 0, "The subtitle preset file.", False )
scriptDialog.AddSelectionControlToGrid( "SubtitlePresetBox", "FileBrowserControl", "", "FFmpeg Preset (*.ffpreset);;All Files (*)", 3, 1 )
scriptDialog.EndGrid()
scriptDialog.EndTabPage()
scriptDialog.EndTabControl()
scriptDialog.AddGrid()
scriptDialog.AddHorizontalSpacerToGrid( "HSpacer1", 0, 0 )
submitButton = scriptDialog.AddControlToGrid( "SubmitButton", "ButtonControl", "Submit", 0, 1, expand=False )
submitButton.ValueModified.connect(SubmitButtonPressed)
closeButton = scriptDialog.AddControlToGrid( "CloseButton", "ButtonControl", "Close", 0, 2, expand=False )
closeButton.ValueModified.connect(scriptDialog.closeEvent)
scriptDialog.EndGrid()
#Application Box must be listed before version box or else the application changed event will change the version
settings = ("DepartmentBox","CategoryBox","PoolBox","SecondaryPoolBox","GroupBox","PriorityBox","MachineLimitBox","IsBlacklistBox","MachineListBox","LimitGroupBox","SceneBox","FramesBox","ChunkSizeBox")
scriptDialog.LoadSettings( GetSettingsFilename(), settings )
scriptDialog.EnabledStickySaving( settings, GetSettingsFilename() )
UseSameArgsModified( None )
scriptDialog.ShowDialog( False )
def GetSettingsFilename():
return Path.Combine( ClientUtils.GetUsersSettingsDirectory(), "FFmpegSettings.ini" )
def UseSameArgsModified(*args):
global scriptDialog
useDifferentArgs = not scriptDialog.GetValue( "UseSameArgsBox" )
for i in range(1,9):
scriptDialog.SetEnabled( "Input%dArgsLabel" % i, useDifferentArgs )
scriptDialog.SetEnabled( "Input%dArgsBox" % i, useDifferentArgs )
def SubmitButtonPressed(*args):
global scriptDialog
# Check output file.
outputFile = (scriptDialog.GetValue( "OutputBox" )).strip()
if( outputFile == "" ):
scriptDialog.ShowMessageBox( "No output file specified", "Error" )
return
else:
if( PathUtils.IsPathLocal( outputFile ) ):
result = scriptDialog.ShowMessageBox( "Output file %s is local, are you sure you want to continue?" % outputFile, "Warning", ("Yes","No") )
if( result == "No" ):
return
# Check video preset file
vpreFile = (scriptDialog.GetValue( "VideoPresetBox" )).strip()
if( vpreFile != "" ):
if( not File.Exists( vpreFile ) ):
scriptDialog.ShowMessageBox( "Video preset file \"%s\" does not exist" % vpreFile, "Error" )
return
elif (PathUtils.IsPathLocal(vpreFile)):
result = scriptDialog.ShowMessageBox( "Video preset file %s is local. Are you sure you want to continue?" % vpreFile, "Warning", ("Yes","No") )
if(result=="No"):
return
# Check audio preset file
apreFile = (scriptDialog.GetValue( "AudioPresetBox" )).strip()
if( apreFile != "" ):
if( not File.Exists( apreFile ) ):
scriptDialog.ShowMessageBox( "Audio preset file \"%s\" does not exist" % apreFile, "Error" )
return
elif (PathUtils.IsPathLocal(apreFile)):
result = scriptDialog.ShowMessageBox( "Audio preset file %s is local. Are you sure you want to continue?" % apreFile, "Warning", ("Yes","No") )
if(result=="No"):
return
# Check subtitle preset file
spreFile = (scriptDialog.GetValue( "SubtitlePresetBox" )).strip()
if( spreFile != "" ):
if( not File.Exists( spreFile ) ):
scriptDialog.ShowMessageBox( "Subtitle preset file \"%s\" does not exist" % spreFile, "Error" )
return
elif ( PathUtils.IsPathLocal( spreFile ) ):
result = scriptDialog.ShowMessageBox( "Subtitle preset file %s is local. Are you sure you want to continue?" % spreFile, "Warning", ("Yes","No") )
if( result=="No" ):
return
# Submit each scene file separately.
# Create job info file.
jobInfoFilename = Path.Combine( ClientUtils.GetDeadlineTempPath(), "ffmpeg_job_info.job" )
writer = StreamWriter( jobInfoFilename, False, Encoding.Unicode )
writer.WriteLine( "Plugin=FFmpeg" )
writer.WriteLine( "Name=%s" % scriptDialog.GetValue( "NameBox" ) )
writer.WriteLine( "Comment=%s" % scriptDialog.GetValue( "CommentBox" ) )
writer.WriteLine( "Department=%s" % scriptDialog.GetValue( "DepartmentBox" ) )
writer.WriteLine( "Pool=%s" % scriptDialog.GetValue( "PoolBox" ) )
writer.WriteLine( "SecondaryPool=%s" % scriptDialog.GetValue( "SecondaryPoolBox" ) )
writer.WriteLine( "Group=%s" % scriptDialog.GetValue( "GroupBox" ) )
writer.WriteLine( "Priority=%s" % scriptDialog.GetValue( "PriorityBox" ) )
writer.WriteLine( "TaskTimeoutMinutes=%s" % scriptDialog.GetValue( "TaskTimeoutBox" ) )
writer.WriteLine( "EnableAutoTimeout=%s" % scriptDialog.GetValue( "AutoTimeoutBox" ) )
writer.WriteLine( "ConcurrentTasks=%s" % scriptDialog.GetValue( "ConcurrentTasksBox" ) )
writer.WriteLine( "LimitConcurrentTasksToNumberOfCpus=%s" % scriptDialog.GetValue( "LimitConcurrentTasksBox" ) )
writer.WriteLine( "MachineLimit=%s" % scriptDialog.GetValue( "MachineLimitBox" ) )
if( bool(scriptDialog.GetValue( "IsBlacklistBox" )) ):
writer.WriteLine( "Blacklist=%s" % scriptDialog.GetValue( "MachineListBox" ) )
else:
writer.WriteLine( "Whitelist=%s" % scriptDialog.GetValue( "MachineListBox" ) )
writer.WriteLine( "LimitGroups=%s" % scriptDialog.GetValue( "LimitGroupBox" ) )
writer.WriteLine( "JobDependencies=%s" % scriptDialog.GetValue( "DependencyBox" ) )
writer.WriteLine( "OnJobComplete=%s" % scriptDialog.GetValue( "OnJobCompleteBox" ) )
if( bool(scriptDialog.GetValue( "SubmitSuspendedBox" )) ):
writer.WriteLine( "InitialStatus=Suspended" )
writer.WriteLine( "Frames=0" ) #%s" % frames )
writer.WriteLine( "ChunkSize=1" ) #%s" % scriptDialog.GetValue( "ChunkSizeBox" ) )
writer.WriteLine( "OutputFilename0=%s" % outputFile )
writer.Close()
# Create plugin info file.
pluginInfoFilename = Path.Combine( ClientUtils.GetDeadlineTempPath(), "ffmpeg_plugin_info.job" )
writer = StreamWriter( pluginInfoFilename, False, Encoding.Unicode )
for i in range(0,9):
writer.WriteLine( "InputFile%d=%s" % (i, scriptDialog.GetValue( "Input%dBox" % i ).strip()) )
writer.WriteLine( "InputArgs%d=%s" % (i, scriptDialog.GetValue( "Input%dArgsBox" % i ).strip()) )
writer.WriteLine( "ReplacePadding%d=%s" % (i, scriptDialog.GetValue( "Input%dReplacePaddingBox" % i )) )
writer.WriteLine( "OutputFile=%s" % outputFile )
writer.WriteLine( "OutputArgs=%s" % scriptDialog.GetValue( "OutputArgsBox" ).strip() )
writer.WriteLine( "UseSameInputArgs=%s" % scriptDialog.GetValue( "UseSameArgsBox" ) )
writer.WriteLine( "AdditionalArgs=%s" % scriptDialog.GetValue( "AdditionalArgsBox" ) )
writer.WriteLine( "VideoPreset=%s" % scriptDialog.GetValue( "VideoPresetBox" ) )
writer.WriteLine( "AudioPreset=%s" % scriptDialog.GetValue( "AudioPresetBox" ) )
writer.WriteLine( "SubtitlePreset=%s" % scriptDialog.GetValue( "SubtitlePresetBox" ) )
writer.Close()
# Setup the command line arguments.
arguments = StringCollection()
arguments.Add( jobInfoFilename )
arguments.Add( pluginInfoFilename )
# Now submit the job.
results = ClientUtils.ExecuteCommandAndGetOutput( arguments )
scriptDialog.ShowMessageBox( results, "Submission Results" )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment