Skip to content

Instantly share code, notes, and snippets.

@jeangjenq
Forked from jedypod/README.md
Created October 17, 2019 05:51
Show Gist options
  • Save jeangjenq/acec576298b2140f26aa91ade3139b2b to your computer and use it in GitHub Desktop.
Save jeangjenq/acec576298b2140f26aa91ade3139b2b to your computer and use it in GitHub Desktop.
Nuke ffmpeg Render

Nuke ffmpeg Render

Writeffmpeg is a python script and a node that allows you to render from Nuke directly into ffmpeg. Instead of a 2 step process where you render from Nuke to a temporary image sequence that you then transcode using ffmpeg, this solution writes to a single uint16 cache tiff file and this data gets piped into ffmpeg.

I've included a little screen recordingto help demo how it works.

Files

ffmpeg_render.py Writeffmpeg.nk

Dependencies

from __future__ import with_statement
from __future__ import print_function
from __future__ import division
import os, sys
import subprocess, shlex
import argparse
import tempfile
import numpy as np
from libtiff import TIFF
import nuke
from sys import platform as __platform
if __platform == "linux" or __platform == "linux2":
_platform = 'linux'
elif __platform == "darwin":
_platform = 'osx'
elif __platform == "win32":
_platform = 'win'
def frames_to_tc(total_frames, frame_rate):
fps_int = int(round(frame_rate))
smpte_token = ":"
hours = int(total_frames / (3600 * fps_int))
minutes = int(total_frames / (60 * fps_int) % 60)
seconds = int(total_frames / fps_int % 60)
frames = int(total_frames % fps_int)
return "%02d:%02d:%02d%s%02d" % (hours, minutes, seconds, smpte_token, frames)
def terminal_render():
parser = argparse.ArgumentParser(description='Render from Nuke to ffmpeg.')
parser.add_argument("nuke_script",
help="Nuke script to render.")
parser.add_argument("-X", "--write",
help="Name of the WriteFFMPEG node to render.")
parser.add_argument("-F", "--framerange",
help="framerange to render. Please specify <start>-<end>.",
required=False)
parser.add_argument("-o", "--output",
help="Output qt to render to. Will use the value of the file knob on the WriteFFMPEG node if not specified.",
required=False)
args = parser.parse_args()
nuke_script = args.nuke_script
nuke.scriptOpen(nuke_script)
node = nuke.toNode(args.write)
node.begin()
write = nuke.toNode('write_tmp')
if args.framerange and "-" in args.framerange:
fr = nuke.FrameRange()
fr.setLast(int(args.framerange.split('-')[-1]))
fr.setFirst(int(args.framerange.split('-')[0]))
else:
node_framerange = node['framerange'].getValue()
if node_framerange and "-" in node_framerange:
fr = nuke.FrameRange()
fr.setLast(int(node_framerange.split('-')[-1]))
fr.setFirst(int(node_framerange.split('-')[0]))
else:
fr = node.frameRange()
tmpimg = tempfile.mkstemp('.tiff', "ffmpeg_temp_")[1]
write['file'].setValue(tmpimg)
framerate = node['framerate'].getValue()
output = node['file'].getValue()
tc = frames_to_tc(fr.first(), framerate)
ffmpeg_args = "ffmpeg -hide_banner -loglevel info -y \
-f rawvideo -pixel_format rgb48le -video_size {0}x{1} \
-framerate {2} -i pipe:0 -timecode {3} {4} {5}".format(
node.width(), node.height(), framerate, tc,
node['ffmpeg_args'].getValue(), output)
print(ffmpeg_args)
ffproc = subprocess.Popen(
shlex.split(ffmpeg_args),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE
)
for i, f in enumerate(fr):
nuke.execute(write, f, f)
print("Rendering frame \t{0} of {1}".format(i, fr.frames()))
img = TIFF.open(tmpimg, mode='r')
img = img.read_image()
img.tofile(ffproc.stdin)
os.remove(tmpimg)
result, error = ffproc.communicate()
if __name__=="__main__":
terminal_render()
def prep():
nuke.scriptSave()
node = nuke.thisNode()
ffpy = __file__
ffpy = ffpy.replace('pyc', 'py')
node_framerange = node['framerange'].getValue()
nk_cmd = "{0} -t {1} {2} --write {3} --output {4}".format(
nuke.EXE_PATH,
ffpy,
nuke.root().knob("name").value(),
node.fullName(),
node['file'].getValue())
print("RENDER COMMAND:\n\t{0}".format(nk_cmd))
if _platform == "win":
nuke.message("Windows not supported.")
return
if _platform == "osx":
cmd = '''osascript 2>/dev/null <<EOF
tell application "Terminal"
if not (exists window 1) then reopen
activate
do script "{0}"
end tell
EOF'''.format(nk_cmd)
elif _platform == "linux":
# cmd = 'xterm -e "bash {0}"'.format(nk_cmd)
cmd = 'gnome-terminal -e "bash -c \\"{0}; exec bash\\""'.format(nk_cmd)
#cmd = 'gnome-terminal -e "bash -c \\"{0}\\""'.format(nk_cmd)
subprocess.Popen(cmd, shell=True)
set cut_paste_input [stack 0]
push $cut_paste_input
Group {
name Writeffmpeg
tile_color 0xbfbf00ff
addUserKnob {20 ffmpeg}
addUserKnob {35 presets M {"Prores 422" "knobs this \{ffmpeg_args \"-c:v prores_ks -profile:v 2 -qscale:v 7 -pix_fmt yuv444p10le -r 24 -vf colormatrix=bt601:bt709 -vendor ap10 -metadata:s encoder=\\\"Apple ProRes 422\\\"\" framerate 24 label \"Prores 422\"\}" "Prores 422 HQ" "knobs this \{ffmpeg_args \"-c:v prores_ks -profile:v 3 -qscale:v 7 -pix_fmt yuv444p10le -r 24 -vf colormatrix=bt601:bt709 -vendor ap10 -metadata:s encoder=\\\"Apple ProRes 422 HQ\\\"\" framerate 24 label \"Prores 422 HQ\"\}" "Prores 4444" "knobs this \{ffmpeg_args \"-c:v prores_ks -profile:v 4 -qscale:v 5 -pix_fmt yuv444p10le -r 24 -vf colormatrix=bt601:bt709 -vendor ap10 -metadata:s encoder=\\\"Apple ProRes 4444\\\"\\\"\" framerate 24 label \"Prores 4444\"\}" "DNxHD 36" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhd -pix_fmt yuv422p -b:v 36M -vf \\\"scale=1920:1080,fps=24000/1001,colormatrix=bt601:bt709\\\"\" framerate 23.976 label \"DNxHD 36\"\}" "DNxHD 115" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhd -pix_fmt yuv422p -b:v 115M -vf \\\"scale=1920:1080,fps=24000/1001,colormatrix=bt601:bt709\\\"\" framerate 23.976 label \"DNxHD 115\"\}" "DNxHD 175" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhd -pix_fmt yuv422p -b:v 175M -vf \\\"scale=1920:1080,fps=24000/1001,colormatrix=bt601:bt709\\\"\" framerate 23.976 label \"DNxHD 175\"\}" "DNxHD 175 10bit" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhd -pix_fmt yuv422p10 -b:v 175M -vf \\\"scale=1920:1080,fps=24000/1001,colormatrix=bt601:bt709\\\"\" framerate 23.976 label \"DNxHD 175 10bit\"\}" "DNxHD 220 10bit" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhd -pix_fmt yuv422p10 -b:v 220M -vf \\\"scale=1920:1080,fps=24000/1001,colormatrix=bt601:bt709\\\"\" framerate 23.976 label \"DNxHD 220 10bit\"\}" "DNxHR HQ" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -vf \\\"colormatrix=bt601:bt709\\\"\" framerate 24 label \"DNxHR HQ\"\}" "DNxHR HQX" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhr_hqx -pix_fmt yuv422p10le -vf \\\"colormatrix=bt601:bt709\\\"\" framerate 24 label \"DNxHR HQX\"\}" "DNxHR 444" "knobs this \{ffmpeg_args \"-c:v dnxhd -profile:v dnxhr_444 -pix_fmt yuv444p10le -vf \\\"colormatrix=bt601:bt709\\\"\" framerate 24 label \"DNxHR 444\"\}" "h264 standard" "knobs this \{ffmpeg_args \"-c:v libx264 -profile:v high -crf 15 -preset slow -tune film -pix_fmt yuv420p -g 4 -bf 2 -vf colormatrix=bt601:bt709\" framerate 24 label \"h264 standard\"\}" "h264 intra" "knobs this \{ffmpeg_args \"-c:v libx264 -profile:v high -crf 12 -preset slow -tune film -pix_fmt yuv420p -g 1 -bf 0 -vf colormatrix=bt601:bt709\" framerate 24 label \"h264 intra\"\}" "h264 intra 444" "knobs this \{ffmpeg_args \"-c:v libx264 -profile:v high444 -crf 12 -preset slow -tune film -pix_fmt yuv444p -g 1 -bf 0 -vf colormatrix=bt601:bt709\" framerate 24 label \"h264 intra 444\"\}" "h264 intra 444 10bit" "knobs this \{ffmpeg_args \"-c:v libx264 -profile:v high444 -crf 12 -preset slow -tune film -pix_fmt yuv444p10le -g 1 -bf 0 -vf colormatrix=bt601:bt709\" framerate 24 label \"h264 intra 444 10bit\"\}" "h265 standard 10bit" "knobs this \{ffmpeg_args \"-c:v libx265 -profile:v main10 -crf 15 -preset slow -tune psnr -pix_fmt yuv420p10le -g 2 -bf 0 -vf colormatrix=bt601:bt709\" framerate 24 label \"h265 standard 10bit\"\}" "h265 intra 422 10bit" "knobs this \{ffmpeg_args \"-c:v libx265 -profile:v main422-10-intra -crf 12 -preset slow -tune psnr -pix_fmt yuv422p10le -g 1 -bf 0 -vf colormatrix=bt601:bt709\" framerate 24 label \"h265 intra 10bit\"\}" "h265 intra 444 10bit" "knobs this \{ffmpeg_args \"-c:v libx265 -profile:v main444-10-intra -crf 12 -preset slow -tune psnr -pix_fmt yuv444p10le -g 1 -bf 0 -vf colormatrix=bt601:bt709\" framerate 24 label \"h265 intra 444 10bit\"\}" ""}}
addUserKnob {2 file t "output file"}
addUserKnob {7 framerate R 23 30}
framerate 24
addUserKnob {1 ffmpeg_args l "ffmpeg args"}
addUserKnob {1 ffmpeg_cmd l "ffmpeg command" t "Enter the path to the ffmpeg executable. \n\nffmpeg without a path will use the environment."}
ffmpeg_cmd ffmpeg
addUserKnob {1 framerange -STARTLINE}
addUserKnob {22 set_framerange l "Set to Input" -STARTLINE T "n = nuke.thisNode()\nfr = n.frameRange()\nn\['framerange'].setValue(\"\{0\}-\{1\}\".format(fr.first(), fr.last()))"}
addUserKnob {22 render l Render T "import ffmpeg_render\nffmpeg_render.prep()" +STARTLINE}
}
Input {
inputs 0
name Input
xpos -40
ypos -10
}
Write {
raw true
file_type tiff
datatype "16 bit"
compression none
checkHashOnRead false
version 486
name write_tmp
selected true
xpos -40
ypos 98
}
Output {
name Output
xpos -40
ypos 230
}
end_group
This file has been truncated, but you can view the full file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment