Post render script


#16

Ok this is working great. I am just trying to edit a section so that I can save the mov to a different directory or the adobe watch folder. The green section is what I have been trying to edit with no luck. I cant seem to track down what script to use to set the new path to [\Tta_server\3d](file://tta_server/3d) model library\AdobeWatch\fliename.mov. I Basically just replaced the green txt below with the previous string with no luck. So would I do that or should I just write copyFile to move the mov to the new location. Neither have worked for me. Any help would be greatly appreciated.

– create an output bitmap
movBitmap = bitmap iflBitmap.width iflBitmap.height
– create a mov filename

Original script movName = getFilenamePath rendOutputFilename + getFilenameFile rendOutputFilename + “.mov”

My script movName = [[color=lime]\Tta_server\3d](file://tta_server/3d) model library\AdobeWatch\ + getFilenameFile rendOutputFilename +[/color] “.mov”

– delete pre-existing quicktime mov
deleteFile movBitmap.filename
– set its name to the mov filename
movBitmap.filename = movName


#17

Ok I have had some luck using this to save the mov. But I keep getting errors now. It worked once but it hasent worked sence then.

movName = getFilenamePath " \\Tta_server\3d model library\AdobeWatch\ " + getFilenameFile rendOutputFilename + “.mov”


#18

Ok no errors in the script now but I am getting a dialog that pops up and says error opening the mov and then one right after thats says error creating.

I am wondering if there is somthing I need to do becuse it is on the network.


#19

Got it sorted out. I was writing the directory string wrong. Here is the finished working script. Works with net rendering as well.

  • get the files rendered
    files = getFiles ((getFilenamePath rendOutputFilename) + (getFilenameFile rendOutputFilename) + “*” + (getFilenameType rendOutputFilename))
    – remove any still we might have rendered
    if (files.count > 1) then (
    stillIndex = findItem files rendOutputFilename
    if (stillIndex != 0) then ( deleteItem files stillIndex )
    – make sure the frames are in the correct order
    sort files
    )
    – create an IFL
    iflName = getFilenamePath rendOutputFilename + getFilenameFile rendOutputFilename + “.ifl”
    iflFile = createFile iflName
    for f in files do ( format "%
    " f to:iflFile )
    close iflFile

– open the IFL as a bitmap
iflBitmap = openBitmap iflName

– create an output bitmap
movBitmap = bitmap iflBitmap.width iflBitmap.height
– create a mov filename
movName = “\\Tta_server\3d model library\AdobeWatch\” + getFilenameFile rendOutputFilename + “.mov”
– delete pre-existing quicktime mov
deleteFile movBitmap.filename
– set its name to the mov filename
movBitmap.filename = movName

– loop through its frames
for i = 0 to (iflBitmap.numFrames - 1) do (
iflBitmap.frame = i
– get the ifl’s frame into the mov bitmap
copy iflBitmap movBitmap
– display as we go over each frame - just so you can see something’s happening
display movBitmap
– save out the mov bitmap (appends as new frame)
save movBitmap frame:i
)

– close the mov so it is finalized
close movBitmap


#20

cool - glad you got it working :slight_smile:

Note that you can remove the ‘display’ line, or wrap it in ‘if (isnetserver()) then ( … )’, as otherwise I think the rendernodes will pop up the VFB showing the images… something you’d typically not want on a node :slight_smile: (doesn’t do any harm, other than freak out sysadmins)


#21

Yea I do comment out the display section when I use the netrendering.

I am having a new problem now though. It seems the first node to finish there assigned tasks runs the script and I need it to be the last node to run it or I need them to make sure the job is finished first. I am thinking that finding the number of frames to be rendered and then checking to makes sure they are all done before running the script might work. I am also trying some netrendering stuff to check to see if the job is complete before running. But I am having a hard time getting exactly what I want from either of them. Then nedrendering stuff only brings back an array finished jobs not the job that was submitted. And as for the frame numbers I cant seem to find a way to pull that number out and then check to see if there are that many frames. Anywone have any suggestions or ideas?


#22

Yeah, figured you might run into that… your best bet is probably to submit another job that runs the script when the original job is done. Unfortunately, you can’t easily set dependencies of one job or another via scripting. You can if you install third party external functionality, such as Python used in this thread:
http://forums.cgsociety.org/showthread.php?f=98&t=692735&highlight=dependency
Edit: err for existing jobs, anyway - for new jobs, you can submit it -with- the depencies using the command line utility

Alternatively, you could set it up by checking, after each rendered frame, whether all frames are present in the output folder… and only continue if all frames are indeed present. There’s a very, very small chance that a machine is actually in the process of writing out a frame, and an even smaller chance still that you would hit that frame in the quicktime generation in the middle of that process… but a sleep() might be a reasonable safeguard.


#23

Here what I have come up with thanks to your link to another thread. The only issue I am having is attaching the script to the dependant job.

– Created: 13-10-2008
– Last Updated: 13-11-2008
– Version: 0.14

– Author : Johan Boekhoven / johan.boekhoven [at] gmail [dot] com / subd.nl
– Version: 3ds max 2009 (11)

– Discription: Submits scene to backburner
– Usage: Just run to submit

– Credits: Helpfile / cgtalk

–************************************************** *********************************************
– MODIFY THIS AT YOUR OWN RISK
(
/* CONNECT TO THE NETWERK MANAGER */
m = netrender.getmanager()
c1 = m.connect #automatic “255.255.255.0”

– Batch it max (PEN) runs through a folder of files opening them and submitting them via this script
localFileName = maxFilePath + maxFileName

– Will be used in the mxs submit and dosCommand dependencies!
x = 1
jobName = (filterString maxFileName “.” )[1] --+ execute “x += 1” as string

/* WHEN CONNECTION AND FILE SUCCESFULLY COPIED /
if c1 then
(
/
SUBMIT JOB */
– Easy BB submit
job = m.newjob file:localFileName
job.name = jobName
job.includeMaps = true --turn on “Include Maps”
job.submit() --this uses all servers for the job

/* FILE SETTINGS */
scriptJobName1 = jobName + “_UncompressedMov”

/* OUTPUT1 - UNCOMPRESSED MOV */
– Build stringStream
jobString1 = stringStream “”

– Create jobname
format "-jobName:% " scriptJobName1 to:jobString1
– SET THE DEPENDENCY!
format "-dependencies:% " jobName to:jobString1

– Add netmask
format "-netmask:255.255.255.0 " to:jobString1

–add the render script
format "-scriptFile:\\Tta_server\3d model library\Scripts\AutoQuickTIme\autoquicktimeNetwork.ms " to:jobString1
print jobString1

– cmdJob is in the backburner folder
maxRoot = “C:\Program Files\backburner 2\”
– Build command string
cmd = “cmdjob.exe " + (jobString1 as string) + " startpath:” + maxroot + " prompt:Submitted to backburner via commandprompt"
print cmd

– Execute it
DOSCommand cmd

)
)

It seems like it should work becuse when it prints it looks good. I must be writing the -scriptfile section wrong.


#24

on further thought I decided to go with the seep() option you mentioned. I will have wait and test it to know for sure though.

/get the number of frames to be rendered/
–check to see what the time output is set to
reTime = rendTimeType
–if it is sent to animation rage then get the number of frames
if (reTime == 3 ) then (
numFrames = rendEnd
s1 = “000” + numFrames as string
s2 = “f”
s3 = “”
FrameNum = substituteString s1 s2 s3
)

–if it is sent to active time segment then get the number of frames
if (reTime == 2 ) then (
numFrames = AnimationRange.end
s1 = “000” + numFrames as string
s2 = “f”
s3 = “”
FrameNum = substituteString s1 s2 s3
)

– if the file exists then run
LastFrame = doesFileExist ((getFilenamePath rendOutputFilename) + (getFilenameFile rendOutputFilename) + FrameNum as String + (getFilenameType rendOutputFilename))
if( LastFrame == true) then (
–pause for 10 seconds to make sure all the frames are done
Print “sleeping”
sleep 10
– get the files rendered
files = getFiles ((getFilenamePath rendOutputFilename) + (getFilenameFile rendOutputFilename) + “*” + (getFilenameType rendOutputFilename))
– remove any still we might have rendered
if (files.count > 1) then (
stillIndex = findItem files rendOutputFilename
if (stillIndex != 0) then ( deleteItem files stillIndex )
– make sure the frames are in the correct order
sort files
)
– create an IFL
x = 01
iflName = getFilenamePath rendOutputFilename + getFilenameFile rendOutputFilename + execute “x += 1” as string + “.ifl”
iflFile = createFile iflName
for f in files do ( format "%
" f to:iflFile )
close iflFile

– open the IFL as a bitmap
iflBitmap = openBitmap iflName

– create an output bitmap
movBitmap = bitmap iflBitmap.width iflBitmap.height
– create a mov filename
movName = “\\Tta_server\3d model library\AdobeWatch\” + getFilenameFile rendOutputFilename + execute “x += 1” as string + “.mov”
– delete pre-existing quicktime mov
deleteFile movBitmap.filename
– set its name to the mov filename
movBitmap.filename = movName

– loop through its frames
for i = 0 to (iflBitmap.numFrames - 1) do (
iflBitmap.frame = i
– get the ifl’s frame into the mov bitmap
copy iflBitmap movBitmap
– save out the mov bitmap (appends as new frame)
save movBitmap frame:i
)

– close the mov so it is finalized
close movBitmap
)


#25

Wrong again. works great with one node on the farm but it still does nothing if there are more nodes. Any ideas? I am also trying some job submission with dependancies but cant get the script to attach to the dependancy.

/*get the number of frames to be rendered*/
 --check to see what the time output is set to  
 reTime = rendTimeType
 --if it is set to animation rage then get the number of frames
 if (reTime == 3 ) then (
 	st = rendStart
 	en = rendEnd
 	numFrames = (en - st)
 	s1 = "0" + numFrames as string
 	s2 = "f"
 	s3 = ""
 	FrameNum = substituteString s1 s2 s3
 )
 --if it is set to active time segment then get the number of frames
 else if (reTime == 2 ) then (
 	animS = animationRange.start 
 	animE = animationRange.end
 	numFrames = (animE - animS)
 	s1 = "0" + numFrames as string
 	s2 = "f"
 	s3 = ""
 	FrameNum = substituteString s1 s2 s3
 )
 
 -- Get the files rendered
 FileLoc = getFiles ((getFilenamePath rendOutputFilename) + (getFilenameFile rendOutputFilename) + "*" + (getFilenameType rendOutputFilename))
 --get the amount of files done and convert it to a number minus one
 FramesDone = FileLoc.count as integer - 1
 NewFrameNum = FrameNum as integer
 
 if (FramesDone == NewFrameNum) then (
 		--pause for 1 minute to make sure all the frames are done
 		sleep 60
 		--get the files rendered
 		files = getFiles ((getFilenamePath rendOutputFilename) + (getFilenameFile rendOutputFilename) + "*" + (getFilenameType rendOutputFilename))
 	
 						-- remove any still we might have rendered
 						if (files.count > 1) then (
 							stillIndex = findItem files rendOutputFilename
 							if (stillIndex != 0) then ( deleteItem files stillIndex )
 							-- make sure the frames are in the correct order
 							sort files
 						)
 						
 		-- create an IFL
 		iflName = getFilenamePath rendOutputFilename + getFilenameFile rendOutputFilename + ".ifl"
 		iflFile = createFile iflName
 		for f in files do ( format "%
" f to:iflFile )
 		close iflFile
 
 	-- open the IFL as a bitmap
 	iflBitmap = openBitmap iflName
 
 	-- create an output bitmap
 	movBitmap = bitmap iflBitmap.width iflBitmap.height
 	-- create a mov filename
 	movName = "\\\\Tta_server\\3d model library\\AdobeWatch\\" + getFilenameFile rendOutputFilename + ".mov"
 	-- delete pre-existing quicktime mov
 	deleteFile movBitmap.filename
 	-- set its name to the mov filename
 	movBitmap.filename = movName
 
 	-- loop through its frames
 	for i = 0 to (iflBitmap.numFrames - 1) do (
 		iflBitmap.frame = i
 		-- get the ifl's frame into the mov bitmap
 		copy iflBitmap movBitmap
 		-- save out the mov bitmap (appends as new frame)
 		save movBitmap frame:i
 		)
 
 -- close the mov so it is finalized
 close movBitmap
 )

#26

Here is what I have for submiting a job and adding the dependancy. I got most of this code from another thread it was written by Johan Boekhoven / johan.boekhoven [at] gmail [dot] com / subd.nl


  (
	  /* CONNECT TO THE NETWERK MANAGER */
	  m = netrender.getmanager()
	  c1 = m.connect #automatic "255.255.255.0"
	  
	  -- Batch it max (PEN) runs through a folder of files opening them and submitting them via this script
	  localFileName = maxFilePath + maxFileName
	  
	  -- Will be used in the mxs submit and dosCommand dependencies!
	  jobName = (filterString maxFileName "." )[1] --  < add some extra string here to allow to sent unique jobs
	  
	  /* WHEN CONNECTION AND FILE SUCCESFULLY COPIED */
	  if c1 then
	  (
		  /* SUBMIT JOB */
		  -- Easy BB submit
		  job = m.newjob file:localFileName
		  job.name = jobName
		  job.includeMaps = true --turn on "Include Maps"
		  job.submit() --this uses all servers for the job
		  
		
		  /* FILE SETTINGS */

		  scriptJobName1 = jobName + "_UncompressedMov"
  
		  /* OUTPUT1 - UNCOMPRESSED AVI */
		  -- Build stringStream
		  jobString1 = stringStream ""
		  
		--attach the script pretty sure this is the wrong way to do this
		files = getFiles "\\\\Tta_server\\3d model library\\Scripts\\AutoQuickTIme\\autoquicktimeFinale121608.ms"
		for file in files do fileIn file
			
		  -- Create jobname
		  format "-jobName:% " scriptJobName1 to:jobString1

		  -- SET THE DEPENDENCY!
		  format "-dependencies:% " jobName to:jobString1
		  
		  -- Add netmask
		  format "-netmask:255.255.255.0 " to:jobString1
  
		  -- This is probably wrong since cmdJob is in the backburner folder, but it works.... I should check that out!
		  maxRoot = "C:\\Program Files\\Autodesk\\backburner\\jobs\\"
		  
		  -- Build command string
		  cmd = "cmdjob.exe " + (jobString1 as string) + " startpath:" + maxroot + " prompt:Submitted to backburner via commandprompt"
		  
		  -- Execute it
		  DOSCommand cmd
  
	  )
  )

#27

I haven’t read the thread so feel free to pay no attention if I’m way off base. Can’t you just render frames to an uncompressed AVI and then use a command-line encoder (Mencoder or ffmpeg) to convert to a .mov/.mp4 file? Then again I haven’t taken the time to read the thread to get context on what you have to do, but I thought I’d just throw that out there.


#28

yes he could - which would take the minor part of loading the images and saving to quicktime, via script, out of the equation :slight_smile:


#29

That depends. We need to render through our render farm which has multiple nodes so I belive the only way to do this is to render an image sequence first. Unless I am mistken that is.

I also dont need .mov if I could get an uncompressed .avi that would be fine. I just need a file format that adobe media encoder can read.

The end result here is just to automate the process of convert image sequences to .flv files. Which is what all are work needs to be at the end of our pipline. So if there is a command line encoder that could do that I would need to write this script anymore. I know adobe has a solution for this but it is around $6,000. and my company is pretty small so I am just rying to find a workaround and save all the man hours we spend setting at our computers using photoshop to encode .flv’s.


#30

Writing frames to an uncompressed avi is really easy, actually. You just need to render frames, and this is what I do:


fn createSequence animBmpFilename bmpArr width height =
(
	local animBmp = bitmap width height filename:animBmpFilename
	for i = 1 to bmpArr.count do
	(
		copy (openBitmap bmpArr[i]) animBmp
		save animBmp frame:i
	)
	close animBmp
)

There’s probably a way to get the width and height from the file without having to pass them in. animBmpFilename is something like “C:\ empComp.avi” and bmpArr is an array of bitmap filenames. Make sure you have the save <bitmap> frame:<integer> in there or you will run into memory issues.


#31

And you use this as a post render script with netrendering?


#32

No, I run this in my rendering utility (basically a wrapper and auto-setup for useful animation rendering things) after I render out frames and composite them together (can render from multiple views). We don’t do any post or net rendering (we are in games). But I think the idea would be the same?


#33

I will give it a try. Thanks


#34

Ok finally done. I ended up using the dependancy script written by Johan Boekhoven mentioned in a previous thread. I just modified it to work with ffmpeg. It is now a 1 button press to an FLV on are render farm. Here is the script.

 macroScript FLVrenderer
 category:"Mikes"
 toolTip:""
(
 /* CONNECT TO THE NETWERK MANAGER */
  m = netrender.getmanager()
  c1 = m.connect #automatic "255.255.255.0"
  
  -- Batch it max (PEN) runs through a folder of files opening them and submitting them via this script
  localFileName = maxFilePath + maxFileName
  
  --saves the settings
  saveMaxFile localFileName
  
  -- Will be used in the mxs submit and dosCommand dependencies!
  jobName = (filterString maxFileName "." )[1] --  < add some extra string here to allow to sent unique jobs
  
  /* WHEN CONNECTION AND FILE SUCCESFULLY COPIED */
  if c1 then
  (
   /* SUBMIT JOB */
   -- Easy BB submit
   job = m.newjob file:localFileName
   job.name = jobName
   job.includeMaps = true --turn on "Include Maps"
   job.submit() --this uses all servers for the job

   
   /* FILE SETTINGS */
   -- Set the parameters that ffmpeg needs
   startTime = "%%04d"
   fPath =  getFilenamePath rendOutputFilename 
   s1 = toLower fpath
   s2 = "[\\\	ta_server\\3d](http://forums.cgsociety.org/) model library\\" 
   s3 = " z:\\"
   filePath = substituteString s1 s2 s3 
   
   fileName = (getFilenameFile rendOutputFilename )
   fileNameExt = getFilenameType rendOutputFilename
   
   vInput = filePath + fileName + startTime + fileNameExt
   
   ffmpeg = @"z:\ffmpeg.exe "
   vScript1 = @"-f image2 -i " + vInput 
   vOutput1 = @" -b 700k -vcodec flv -y " + filePath + fileName  + ".flv"
   scriptJobName1 = jobName + "_FLV"
   
   print ffmpeg + vScript1 + vOutput1
   
   /* OUTPUT1 - UNCOMPRESSED AVI */
   -- Build stringStream
   jobString1 = stringStream ""
   
   -- Create jobname
   format "-jobName:% " scriptJobName1 to:jobString1
   
   -- SET THE DEPENDENCY!
   format "-dependencies:% " jobName to:jobString1
   
   -- Add netmask
   format "-netmask:255.255.255.0 " to:jobString1
	
   -- Add execution string
   format "% " (ffmpeg + vScript1 + vOutput1) to:jobString1
   
   -- max root
   maxRoot = pathConfig.GetDir #maxroot
   
   -- Build command string
   cmd = "cmdjob.exe " + (jobString1 as string) 
   
   -- Execute it
   DOSCommand cmd
   
  )
)

#35

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.