mirror of
https://github.com/stevenrobertson/cuburn.git
synced 2025-02-05 11:40:04 -05:00
cuburn.profile.
This commit is contained in:
parent
c02573472a
commit
909643c3b4
@ -109,13 +109,21 @@ prof_filters['logscale']['scale'] = refscalar(1, 'camera.scale')
|
|||||||
profile = (
|
profile = (
|
||||||
{ 'duration': RefScalar(30, 'time.duration', 'Base duration in seconds')
|
{ 'duration': RefScalar(30, 'time.duration', 'Base duration in seconds')
|
||||||
, 'fps': Scalar(24, 'Frames per second')
|
, 'fps': Scalar(24, 'Frames per second')
|
||||||
|
, 'frame_width': refscalar(1, 'time.frame_width')
|
||||||
|
|
||||||
|
, 'start': Scalar(None, 'First frame to render (1-indexed, inclusive)')
|
||||||
|
, 'end': Scalar(None, 'Last frame to render (1-indexed, exclusive; '
|
||||||
|
'negative indexes from the end)')
|
||||||
|
, 'skip': Scalar(0, 'Skip this many frames between each rendered frame')
|
||||||
|
|
||||||
, 'height': Scalar(1920, 'Output height in pixels')
|
, 'height': Scalar(1920, 'Output height in pixels')
|
||||||
, 'width': Scalar(1080, 'Output width in pixels')
|
, 'width': Scalar(1080, 'Output width in pixels')
|
||||||
, 'frame_width': refscalar(1, 'time.frame_width')
|
|
||||||
, 'spp': RefScalar(2000, 'camera.spp', 'Base samples per pixel')
|
, 'spp': RefScalar(2000, 'camera.spp', 'Base samples per pixel')
|
||||||
, 'skip': Scalar(0, 'Skip this many frames between each rendered frame')
|
|
||||||
, 'filter_order': list_(enum(filters.keys()), default_filters)
|
, 'filter_order': list_(enum(filters.keys()), default_filters)
|
||||||
, 'filters': prof_filters
|
, 'filters': prof_filters
|
||||||
|
|
||||||
|
, 'output_format': enum('jpg png tif', 'jpg')
|
||||||
})
|
})
|
||||||
|
|
||||||
# Types recognized as independent units with a 'type' key
|
# Types recognized as independent units with a 'type' key
|
||||||
|
@ -199,14 +199,3 @@ class SplineEval(object):
|
|||||||
plt.xlim(0.0, 1.0)
|
plt.xlim(0.0, 1.0)
|
||||||
if show:
|
if show:
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
def wrap_genome(prof, gnm):
|
|
||||||
# It's not obvious that this is what needs to happen, so we wrap. The
|
|
||||||
# timing is simplistic, and may get expanded or moved later.
|
|
||||||
scale = gnm.get('time', {}).get('duration', 1)
|
|
||||||
gprof = RefWrapper(prof, toplevels['profile'],
|
|
||||||
other=SplineWrapper(gnm, scale=scale))
|
|
||||||
nframes = round(gprof.fps * gprof.duration)
|
|
||||||
times = np.linspace(0, 1, nframes + 1)
|
|
||||||
times = times[:-1] + 0.5 * (times[1] - times[0])
|
|
||||||
return gprof, times
|
|
||||||
|
94
cuburn/profile.py
Normal file
94
cuburn/profile.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import numpy as np
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from genome.specs import toplevels
|
||||||
|
from genome.use import RefWrapper, SplineWrapper
|
||||||
|
|
||||||
|
BUILTIN={
|
||||||
|
'1080p': dict(width=1920, height=1080),
|
||||||
|
'720p': dict(width=1280, height=720),
|
||||||
|
'540p': dict(width=960, height=540),
|
||||||
|
'preview': dict(width=640, height=360, spp=1200, skip=1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_args(parser=None):
|
||||||
|
"""
|
||||||
|
Add profile argument groups to an ArgumentParser, for use with
|
||||||
|
get_from_args. (If `parser` is None, a new one will be made.)
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser() if parser is None else parser
|
||||||
|
prof = parser.add_argument_group('Profile options')
|
||||||
|
prof.add_argument('--builtin-profile', '-P', choices=BUILTIN.keys(),
|
||||||
|
help='Set parameters below from a builtin profile. (default: 720p)',
|
||||||
|
default='720p')
|
||||||
|
prof.add_argument('--profile', '-p', type=argparse.FileType(),
|
||||||
|
metavar='PROFILE', help='Set profile from a JSON file.')
|
||||||
|
|
||||||
|
tmp = parser.add_argument_group('Temporal options')
|
||||||
|
tmp.add_argument('--duration', type=float, metavar='TIME',
|
||||||
|
help="Override base duration in seconds")
|
||||||
|
tmp.add_argument('--fps', type=float, dest='fps',
|
||||||
|
help="Override frames per second")
|
||||||
|
tmp.add_argument('--start', metavar='FRAME_NO', type=int,
|
||||||
|
help="First frame to render (1-indexed, inclusive)")
|
||||||
|
tmp.add_argument('--end', metavar='FRAME_NO', type=int,
|
||||||
|
help="Last frame to render (1-indexed, exclusive, negative from end)")
|
||||||
|
tmp.add_argument('--skip', dest='skip', metavar='N', type=int,
|
||||||
|
help="Skip N frames between each rendered frame")
|
||||||
|
tmp.add_argument('--still', action='store_true',
|
||||||
|
help='Override start, end, and temporal frame width to render one '
|
||||||
|
'frame without motion blur.')
|
||||||
|
|
||||||
|
spa = parser.add_argument_group('Spatial options')
|
||||||
|
spa.add_argument('--spp', type=int, metavar='SPP',
|
||||||
|
help="Set base samples per pixel")
|
||||||
|
spa.add_argument('--width', type=int, metavar='PX')
|
||||||
|
spa.add_argument('--height', type=int, metavar='PX')
|
||||||
|
|
||||||
|
out = parser.add_argument_group('Output options')
|
||||||
|
out.add_argument('--codec', choices=['jpg', 'png', 'tiff'])
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def get_from_args(args):
|
||||||
|
"""
|
||||||
|
Get profile from an ArgumentParser result. Returns `(name, prof)`.
|
||||||
|
"""
|
||||||
|
if args.profile:
|
||||||
|
name = args.profile.name
|
||||||
|
base = json.load(args.profile)
|
||||||
|
else:
|
||||||
|
name = args.builtin_profile
|
||||||
|
base = BUILTIN[args.builtin_profile]
|
||||||
|
|
||||||
|
if args.still:
|
||||||
|
base.update(frame_width=0, start=1, end=2)
|
||||||
|
for arg in 'duration fps start end skip spp width height'.split():
|
||||||
|
if getattr(args, arg, None) is not None:
|
||||||
|
base[arg] = getattr(args, arg)
|
||||||
|
|
||||||
|
return name, base
|
||||||
|
|
||||||
|
def wrap(prof, gnm):
|
||||||
|
"""
|
||||||
|
Create a wrapped profile from plain dicts `prof` and `gnm`. The wrapped
|
||||||
|
profile follows the structure of the profile but returns genome-adjusted
|
||||||
|
data for any RefScalar value in its spec.
|
||||||
|
"""
|
||||||
|
scale = gnm.get('time', {}).get('duration', 1)
|
||||||
|
return RefWrapper(prof, toplevels['profile'],
|
||||||
|
other=SplineWrapper(gnm, scale=scale))
|
||||||
|
|
||||||
|
def enumerate_times(gprof):
|
||||||
|
"""
|
||||||
|
Given a profile, return a list of `(frame_no, center_time)` pairs. Note
|
||||||
|
that the enumeration is applied before `start`, `end`, and `skip`, and so
|
||||||
|
`frame_no` may be non-contiguous.
|
||||||
|
"""
|
||||||
|
nframes = round(gprof.fps * gprof.duration)
|
||||||
|
times = np.linspace(0, 1, nframes + 1)
|
||||||
|
times = list(enumerate(times[:-1] + 0.5 * (times[1] - times[0]), 1))
|
||||||
|
if gprof.end is not None:
|
||||||
|
times = times[:gprof.end]
|
||||||
|
if gprof.start is not None:
|
||||||
|
times = times[gprof.start:]
|
||||||
|
return times[::gprof.skip+1]
|
67
main.py
67
main.py
@ -23,16 +23,9 @@ import numpy as np
|
|||||||
import pycuda.driver as cuda
|
import pycuda.driver as cuda
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
from cuburn import render, filters, output
|
from cuburn import render, filters, output, profile
|
||||||
from cuburn.genome import convert, use, db
|
from cuburn.genome import convert, use, db
|
||||||
|
|
||||||
profiles = {
|
|
||||||
'1080p': dict(width=1920, height=1080),
|
|
||||||
'720p': dict(width=1280, height=720),
|
|
||||||
'540p': dict(width=960, height=540),
|
|
||||||
'preview': dict(width=640, height=360, spp=1200, skip=1)
|
|
||||||
}
|
|
||||||
|
|
||||||
def save(out):
|
def save(out):
|
||||||
# Temporary! TODO: fix this
|
# Temporary! TODO: fix this
|
||||||
output.PILOutput.save(out.buf, out.idx)
|
output.PILOutput.save(out.buf, out.idx)
|
||||||
@ -44,23 +37,20 @@ def main(args, prof):
|
|||||||
gdb = db.connect(args.genomedb)
|
gdb = db.connect(args.genomedb)
|
||||||
|
|
||||||
gnm, basename = gdb.get_anim(args.flame, args.half)
|
gnm, basename = gdb.get_anim(args.flame, args.half)
|
||||||
gprof, times = use.wrap_genome(prof, gnm)
|
gprof = profile.wrap(prof, gnm)
|
||||||
rmgr = render.RenderManager()
|
|
||||||
|
|
||||||
basename += '_'
|
basename += '_'
|
||||||
if args.name is not None:
|
if args.name is not None:
|
||||||
basename = args.name
|
basename = args.name
|
||||||
prefix = os.path.join(args.dir, basename)
|
prefix = os.path.join(args.dir, basename)
|
||||||
frames = [('%s%05d%s.jpg' % (prefix, (i+1), args.suffix), t)
|
frames = [('%s%05d%s.jpg' % (prefix, (i+1), args.suffix), t)
|
||||||
for i, t in enumerate(times)]
|
for i, t in profile.enumerate_times(gprof)]
|
||||||
if args.end:
|
|
||||||
frames = frames[:args.end]
|
|
||||||
frames = frames[args.start::gprof.skip+1]
|
|
||||||
if args.resume:
|
if args.resume:
|
||||||
m = os.path.getmtime(args.flame)
|
m = os.path.getmtime(args.flame)
|
||||||
frames = (f for f in frames
|
frames = (f for f in frames
|
||||||
if not os.path.isfile(f[0]) or m > os.path.getmtime(f[0]))
|
if not os.path.isfile(f[0]) or m > os.path.getmtime(f[0]))
|
||||||
|
|
||||||
|
rmgr = render.RenderManager()
|
||||||
gen = rmgr.render(gnm, gprof, frames)
|
gen = rmgr.render(gnm, gprof, frames)
|
||||||
|
|
||||||
if not args.gfx:
|
if not args.gfx:
|
||||||
@ -110,8 +100,6 @@ def main(args, prof):
|
|||||||
label.text = '%s (%g fps)' % (out.idx, 1./real_dt)
|
label.text = '%s (%g fps)' % (out.idx, 1./real_dt)
|
||||||
else:
|
else:
|
||||||
label.text += '.'
|
label.text += '.'
|
||||||
if args.sync:
|
|
||||||
cuda.Context.synchronize()
|
|
||||||
|
|
||||||
pyglet.clock.set_fps_limit(30)
|
pyglet.clock.set_fps_limit(30)
|
||||||
pyglet.clock.schedule_interval(poll, 1/30.)
|
pyglet.clock.schedule_interval(poll, 1/30.)
|
||||||
@ -138,49 +126,10 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument('--genomedb', '-d', metavar='PATH', type=str,
|
parser.add_argument('--genomedb', '-d', metavar='PATH', type=str,
|
||||||
help="Path to genome database (file or directory, default '.')",
|
help="Path to genome database (file or directory, default '.')",
|
||||||
default='.')
|
default='.')
|
||||||
|
parser.add_argument('--half', action='store_true',
|
||||||
parser.add_argument('--sync', action='store_true', dest='sync',
|
help='Use half-loops when converting nodes to animations')
|
||||||
help='Use synchronous launches whenever possible')
|
profile.add_args(parser)
|
||||||
|
|
||||||
parser.add_argument('--duration', type=float, metavar='TIME',
|
|
||||||
help="Set base duration in seconds (30)", default=30)
|
|
||||||
parser.add_argument('--start', metavar='FRAME_NO', type=int,
|
|
||||||
default=0, help="First frame to render (inclusive)")
|
|
||||||
parser.add_argument('--end', metavar='FRAME_NO', type=int,
|
|
||||||
help="Last frame to render (exclusive, negative OK)")
|
|
||||||
|
|
||||||
prof = parser.add_argument_group('Profile options')
|
|
||||||
prof.add_argument('-p', dest='prof', choices=profiles.keys(),
|
|
||||||
default='preview', help='Set profile, specifying defaults for all '
|
|
||||||
'options below. (default: "preview")')
|
|
||||||
prof.add_argument('--pfile', type=argparse.FileType(), metavar='PROFILE',
|
|
||||||
help='Set profile using a JSON file, overriding -p.')
|
|
||||||
prof.add_argument('--skip', dest='skip', metavar='N', type=int,
|
|
||||||
help="Skip N frames between each rendered frame")
|
|
||||||
prof.add_argument('--quality', type=int, metavar='SPP',
|
|
||||||
help="Set base samples per pixel")
|
|
||||||
prof.add_argument('--fps', type=float, dest='fps',
|
|
||||||
help="Set frames per second (24)")
|
|
||||||
prof.add_argument('--width', type=int, metavar='PX')
|
|
||||||
prof.add_argument('--height', type=int, metavar='PX')
|
|
||||||
|
|
||||||
node = parser.add_argument_group('Node options')
|
|
||||||
node.add_argument('--half', action='store_true',
|
|
||||||
help='Use a half-loop when rendering a node.')
|
|
||||||
node.add_argument('--still', action='store_true',
|
|
||||||
help='Override start, end, and temporal frame width to render one '
|
|
||||||
'frame without motion blur. (Works on edges too)')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
prof = dict(profiles[args.prof])
|
pname, prof = profile.get_from_args(args)
|
||||||
if args.pfile:
|
|
||||||
prof = json.load(open(args.pfile))
|
|
||||||
for k in ['duration', 'skip', 'quality', 'fps', 'width', 'height']:
|
|
||||||
if getattr(args, k) is not None:
|
|
||||||
prof[k] = getattr(args, k)
|
|
||||||
if args.still:
|
|
||||||
args.start = 0
|
|
||||||
args.end = 1
|
|
||||||
prof['frame_width'] = 0
|
|
||||||
|
|
||||||
main(args, prof)
|
main(args, prof)
|
||||||
|
Loading…
Reference in New Issue
Block a user