AWS Thinkbox Discussion Forums

NOOB question - simple h.264 encoding

Hello everyone,

I’m fairly new to draft and thus I’d like to ask for a few pointers.

I need to create a template that’d take a resulting video file from a Deadline job using the implemented draft submitter (draft event plugin) and add a Timecode to it in the lower middle area of the video, then save it as the original to a different video, incl. the same compression, settings, everything.

In ffmpeg, I’d just copy the video and audio streams, I don’t need to dig through the source to figure everything out, I just need to draw the timecode and burn it into the video.

Could you please, tell me how to:

  • get the source file from the submitter (the file name was submitted with the original job)
  • take the vid, decode it, burn-in the timecode and encode it to a copy of the source video

all this in a “recipe” template that will be submitted with the original job.

Thank you a ton in advance, I have gone through the documentation and samples, but they are mostly tied to a standalone draft installation/usage, which doesn’t cover the data mining from the Deadline submission.

Cheers,

loocas

Hi,
you can open the draft UI file and manually add data that you need to it and then apply it to your template.For example->

#adding your own variable.
args.append( “color_space_value=%s” % get_color_space)
#accessing it in draft template.
expectedTypes[‘color_space_value’]=’’
get_col_space=params[“color_space_value”]

As for centering it I think this might help->
forums.thinkboxsoftware.com/vie … 79&t=10657

Hope this helps.

Thanks kmind, I appretiate it.

Though I don’t need to add my own variables, I just need to source whatever the users provide during the initial submission.

The Draft integartion in many scripts requires the user to type in the output file name/path which Draft then should use to manipulate later when processing the rendered video file.

I never found what property or which function calls upon this submitted variable.

Thanks, cheers,

The event plugin passes it in as these arguments:

ScriptArg8=inFile=“M:\Baywatch\Shots\ff_1970\2d_renders\ff_1970_comp_v004/ff_1970_comp_v004.####.exr”
ScriptArg9=outFile="/mnt/MediaDump/Baywatch/Shots/ff_1970/2d_renders/ff_1970_comp_v004/Draft/ff_1970_comp_v004.mov"
ScriptArg10=outFolder="/mnt/MediaDump/Baywatch/Shots/ff_1970/2d_renders/ff_1970_comp_v004/Draft"

So, try grabbing the input file path as “inFile”. It’ll pull that from the OutputFolder0 and OutputFile0 from the previous job, so if they’re not there then the dependant script isn’t going to work so well…

Fantastic!

Thank you, Eric!

Will give it a try. Cheers.

Hi guys, me again. :slight_smile:

Ok, so I’m a bit stuck.

I’m completely new to writing Draft templates, so, please, bear with me.

What I’m trying to do is:

  1. catch the output file provided by the user when submitting the original job for rendering (i.e.: C:\myOutputVideo.mp4)
  2. Take the video file and burn in its TIMECODE with Draft
  3. Save the video file with the very same codec settings as the original as C:\myOutputVideo_TC.mp4

That’s it.

The user will provide the output file name during the submission (there is no other way around this as we’re talking about a custom Deadline plugin that doesn’t expose any API and therefore we won’t be able to pull the render output filename from the plugin itself) and I want Draft to automatically just add TIMECODE to the rendered video.

Nothing else.

So far, I’m pretty much stuck, since I have no idea how to interact with Draft and the provided examples don’t really show much in my direction.

Further more I’m working with video files, but Deadline keeps adding #### characters to my video file names during the submission, which is annoying and unnecessary.

Thank you again in advance for your help, I very much appretiate it.

Cheers…

How do you feel about jumping on the 8.1 beta of Deadline, as really you have just described “Quick Draft” used in combination with the new “Draft Annotations” system. One of our developers blogged about it recently, but it’s only in 8.1, which is still in beta: deadline.thinkboxsoftware.com/fe … -draft-way

It’s brand new, so it might be slightly rough around the edges, but if you are up for a few cycles of testing and feedback, this would likely be a nice and clean approach for you?

I wouldn’t mind, but this needs to be done in a production on a current 8.0, no beta, no upgrades any time soon, unfortunately :frowning:

The new Quick Draft seems super cool, though. :slight_smile:

Ah, ok, that will make it more tricky then. (using 8.0 instead of 8.1).

So, have you seen our Draft cookbook examples here on TIMECODE and how to burn?
docs.thinkboxsoftware.com/produc … s-timecode

and into a video file:
docs.thinkboxsoftware.com/produc … nvideofile

In terms of pulling data from a Deadline job:
docs.thinkboxsoftware.com/produc … ntegration

docs.thinkboxsoftware.com/produc … eters.html
docs.thinkboxsoftware.com/produc … alues.html

Thank you, Mike,

I’m still trying to wrap my head around Draft. It seems unnecessarily complicated for what it’s supposed to be doing, to be honest.

Quite honestly I’m inclined to actually work around Draft rather than with it. I’d rather install a utility that does the TIMECODE burn in for me rather than trying to figure out this weird clusterf*** Draft seems.

I’m sure seasoned Draft users are rolling their eyes thinking how I could possibly think of such a simple and elegant solution that Draft for sure is, being complicated. But the truth is, Draft seems incredibly backwards to me.

Hopefully I’ll be able to figure it out today (as it is my deadline :smiley: ).

Thank you again for your help, much appretiated!

By the way, is there any way I can import Draft into my Python session so that I don’t have to debug/test/develop by trial and error (submitting jobs to Deadline and waiting for their STDOUT)?!

I can’t find the Draft module I could import into my Python session anywhere in the Deadline repo, nor in my local Deadline installation.

Thanks in advance!

sys.path.append(“C:\Users\User_name\AppData\Local\Thinkbox\Deadline8\slave\machine_name\Draft”)
Should be there :>.

If you are on Linux I dont know where it is but you can find it using inspect module xD.

You are absolutely amazing! Thank you!

I’d never thought of this location and haven’t bumped into it in any of the documentation.

Thank you again! This will speed up my R&D substantially!

How to run Draft Standalone:
docs.thinkboxsoftware.com/produc … standalone

Ahh, there it is: \SERVER\deadline\draft\Windows\64bit\

Can’t believe I missed it!

Thank you!

Sorry guys, but I’m getting a bit frustrated here and I’m SERIOUSLY considering completely skipping this Draft nonsense and use a completely different solution (EVEN NUKE for that matter) so a super simple timecode burn in. Draft just doesn’t make any sense to me. It seems as if Draft was supposed to be a Pythonic module, but was written by somebody deeply rooted in C++ or other programming language (kinda like raw Python implementation in Maya felt). Passing objects, returning objects, somehow, nothing MAKES ANY SENSE and I don’t think I am a complete Python beginner here.

Ok, se here’s my, incomplete, Draft template code that I just cannot really think of ANY way putting together from the examples in the documentation:

[code]import sys

sys.path.append(r"C:\Users\loocas\AppData\Local\Thinkbox\Deadline8\slave\DUBER\Draft")

import Draft
from DraftParamParser import ReplaceFilenameHashesWithNumber

tmpFilesToProcess = [r"D:\V1880007_lens_A.MP4"]

Create a Draft.ImageInfo object to extract a Draft.Timecode object

imageInfo = Draft.ImageInfo()

decodedVideo = Draft.VideoDecoder(tmpFilesToProcess[0])
frameImage = Draft.Image.CreateImage(decodedVideo.width, decodedVideo.height)

now, what the hell do I do here?!!! Why do I have to work with single images suddenly? And, ok, if so, WHERE THE HELL DO I REFERENCE THE IMAGE?

while(decodedVideo.DecodeNextFrame(frameImage)):
#OK, WHERE DO I REFERENCE THE frameImage object?! Where do I use it? How? Is it always overwritten in memory, meaning
the object refreshes with each DecodeNextFrame call? Why can’t I index it? Or at least Yield it? HOW DOES IT WORK?!
# If first frame and a timecode is found, specify the timecode parameter when creating the encoder
if(imageInfo.timecode):
# WHAT IS THIS?!! why am I encoding a video with no parameters and mainly no reference to the frameImage object?!
encoder = Draft.VideoEncoder( ‘C:\myMovie.mov’, timecode = imageInfo.timecode )
else:
encoder = Draft.VideoEncoder( ‘C:\myMovie.mov’ )

# Add current frame to the video.
encoder.EncodeNextFrame(frameImage)

encoder.FinalizeEncoding()[/code]

I’m sorry, but this is just one huge mess. I don’t understand the Draft structure, its logic and I am really frustrated by it not doing anything remotely logical.

I’d much rather work around Draft than work with it, to be quite honest.

And not to be completely negative, here’s my suggestion for what Draft should be:

import Draft

videoToBeProcessed = r'C:\vid.mp4'

decodedVid = Draft.DecodeVideoFile(videoToBeProcessed)

for curFrame in range(decodedVid.frameRange):
	singleImage = decodedVid.getSingleFrame(curFrame)
	
	#do some stuff to the single image object
	
	encoder = Draft.VideoEncoder(r'C:\outputFile.mov', <parameters>)
	encoder.encodeFrame(curFrame, singleImage)

encoder.FinalizeEncoding()	

This would make sense, in my opinion.

If you create a video encoder for every frame, you’ll get into trouble. In your ideal case, you’d be destroying and re-creating your video encoder. I’ll see if I can make this work for you.

Imagine the VideoEncoder is a meat grinder where you put your frames in the top and it pushes out videos. You make the meat grinder, and you feed it individual frames with encoder.EncodeNextFrame. If you re-create the meat grinder for every frame, you’re not getting a very good QuickTime sausage. :smiley:

I’ll see if I can make a simpler example for you here quickly.

Here’s the transcode sample from “[repo]/draft/Samples/Transcode”:

import sys
import Draft
from DraftParamParser import *

expectedTypes = {}
expectedTypes['inFile'] = '<string>'
expectedTypes['outFile'] = '<string>'

params = ParseCommandLine( expectedTypes, sys.argv )

inFile = params['inFile']
outFile = params['outFile']

img = Draft.Image.CreateImage( 1, 1 )

dec = Draft.VideoDecoder( inFile )

hasFrame = dec.DecodeNextFrame( img )

enc = None

while hasFrame:
    if enc is None:
        enc = Draft.VideoEncoder( outFile, 25, dec.width, dec.height, codec='mjpeg' )

    enc.EncodeNextFrame( img )
    
    hasFrame = dec.DecodeNextFrame( img )

if enc is not None:
    enc.FinalizeEncoding()

Update: I’ve got to head out, but here’s the sample I’ve got working. The codec settings don’t match the input, and it’s not burning anything in yet so right now it’s just a seriously inefficient lossy copy.

import sys

import Draft
from DraftParamParser import ReplaceFilenameHashesWithNumber

tmpFilesToProcess = [r"/Users/edwin.amsler/Downloads/draft-test/input.mov"]
FilesProcessed = [r"/Users/edwin.amsler/Downloads/draft-test/output.mov"]
codec = 'h264'

# Create a Draft.ImageInfo object to extract a Draft.Timecode object
imageInfo = Draft.ImageInfo()

decodedVideo = Draft.VideoDecoder(tmpFilesToProcess[0])
encodedVideo = Draft.VideoEncoder(FilesProcessed[0], 25, decodedVideo.width, decodedVideo.height, codec = codec)
frameImage = Draft.Image.CreateImage(decodedVideo.width, decodedVideo.height)

index = 0

while(decodedVideo.DecodeNextFrame(frameImage)):
    index += 1
    print('Frame {}\r'.format(index))
    encodedVideo.EncodeNextFrame(frameImage)

encoder.FinalizeEncoding()

Thank ou Edwin, it seems to be working.

My code was a copy&paste from the documentation that didn’t work actually. So that’s why I had problems with wrapping my head around it.

But from your example, I get the logic.

I’ll see if I can compose stff onto the currently processed image and spit it out.

Thank you very much again, I much appretiate it!

Privacy | Site terms | Cookie preferences