render fixes, encode vides in render command

This commit is contained in:
j 2023-10-09 20:29:11 +01:00
parent e84ea31147
commit 5075394318
4 changed files with 35 additions and 7 deletions

View file

@ -19,10 +19,12 @@ class Command(BaseCommand):
clips = [] clips = []
for i in item.models.Item.objects.filter(data__type__contains="Original"): for i in item.models.Item.objects.filter(data__type__contains="Original"):
qs = item.models.Item.objects.filter(data__title=i.data['title']).exclude(id=i.id) qs = item.models.Item.objects.filter(data__title=i.data['title']).exclude(id=i.id)
if qs.count() == 2: if qs.count() >= 2:
clip = {} clip = {}
durations = [] durations = []
for e in item.models.Item.objects.filter(data__title=i.data['title']): for e in item.models.Item.objects.filter(data__title=i.data['title']):
if 'type' not in e.data:
print("ignoring invalid video", e)
source = e.files.all()[0].data.path source = e.files.all()[0].data.path
ext = os.path.splitext(source)[1] ext = os.path.splitext(source)[1]
type_ = e.data['type'][0].lower() type_ = e.data['type'][0].lower()
@ -35,7 +37,10 @@ class Command(BaseCommand):
durations.append(e.files.all()[0].duration) durations.append(e.files.all()[0].duration)
clip["duration"] = min(durations) clip["duration"] = min(durations)
clip['tags'] = i.data.get('tags', []) clip['tags'] = i.data.get('tags', [])
clips.append(clip) if "original" in clip and "foreground" in clip and "background" in clip:
clips.append(clip)
else:
print("ignoring incomplete video", i)
with open(os.path.join(prefix, 'clips.json'), 'w') as fd: with open(os.path.join(prefix, 'clips.json'), 'w') as fd:
json.dump(clips, fd, indent=2, ensure_ascii=False) json.dump(clips, fd, indent=2, ensure_ascii=False)

View file

@ -1,5 +1,6 @@
import json import json
import os import os
import subprocess
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.conf import settings from django.conf import settings
@ -14,6 +15,7 @@ class Command(BaseCommand):
parser.add_argument('--prefix', action='store', dest='prefix', default="/srv/t_for_time", help='prefix to build clips in') parser.add_argument('--prefix', action='store', dest='prefix', default="/srv/t_for_time", help='prefix to build clips in')
parser.add_argument('--duration', action='store', dest='duration', default="150", help='target duration in seconds') parser.add_argument('--duration', action='store', dest='duration', default="150", help='target duration in seconds')
parser.add_argument('--offset', action='store', dest='offset', default="1024", help='inital offset in pi') parser.add_argument('--offset', action='store', dest='offset', default="1024", help='inital offset in pi')
parser.add_argument('--no-video', action='store_true', dest='no_video', default=False, help='don\'t render video')
def handle(self, **options): def handle(self, **options):
prefix = options['prefix'] prefix = options['prefix']
@ -23,7 +25,15 @@ class Command(BaseCommand):
with open(os.path.join(prefix, "clips.json")) as fd: with open(os.path.join(prefix, "clips.json")) as fd:
clips = json.load(fd) clips = json.load(fd)
scene = compose(clips, target=target, base=base) scene = compose(clips, target=target, base=base)
render(prefix, scene, 'scene-%s-' % base) timelines = render(prefix, scene, 'scene-%s-' % base)
with open(os.path.join(prefix, 'scene-%s.json' % base), 'w') as fd: with open(os.path.join(prefix, 'scene-%s.json' % base), 'w') as fd:
json.dump(scene, fd, indent=2, ensure_ascii=False) json.dump(scene, fd, indent=2, ensure_ascii=False)
if not options['no_video']:
for timeline in timelines:
cmd = [
'xvfb-run', '-a',
'melt', timeline,
'-consumer', 'avformat:%s' % timeline.replace('.kdenlive', '.mp4')
]
subprocess.call(cmd)

View file

@ -14,7 +14,9 @@ def random_choice(seq, items, pop=False):
n = n_ = len(items) - 1 n = n_ = len(items) - 1
#print('len', n) #print('len', n)
if n == 0: if n == 0:
return items[0] if pop:
return items.pop(n)
return items[n]
r = seq() r = seq()
base = 10 base = 10
while n > 10: while n > 10:
@ -50,9 +52,12 @@ def compose(clips, target=150, base=1024):
'A4': [], 'A4': [],
} }
} }
all_clips = clips.copy()
seq = random(base) seq = random(base)
while target - length > 10 and clips: while target - length > 10 and clips:
clip = random_choice(seq, clips, True) clip = random_choice(seq, clips, True)
if not clips:
clips = [c for c in all_clips if c != clip]
if length + clip['duration'] > target: if length + clip['duration'] > target:
break break
length += clip['duration'] length += clip['duration']
@ -112,6 +117,7 @@ def compose(clips, target=150, base=1024):
def render(root, scene, prefix=''): def render(root, scene, prefix=''):
fps = 24 fps = 24
files = []
for timeline, data in scene.items(): for timeline, data in scene.items():
print(timeline) print(timeline)
project = KDEnliveProject(root) project = KDEnliveProject(root)
@ -121,6 +127,8 @@ def render(root, scene, prefix=''):
print(track) print(track)
for clip in clips: for clip in clips:
project.append_clip(track, clip) project.append_clip(track, clip)
path = os.path.join(root, prefix + "%s.kdenlive" % timeline)
with open(os.path.join(root, prefix + "%s.kdenlive" % timeline), 'w') as fd: with open(path, 'w') as fd:
fd.write(project.to_xml()) fd.write(project.to_xml())
files.append(path)
return files

View file

@ -5,6 +5,7 @@ import lxml.etree
import uuid import uuid
import os import os
_CACHE = {}
_IDS = defaultdict(int) _IDS = defaultdict(int)
def get_propery(element, name): def get_propery(element, name):
@ -12,6 +13,7 @@ def get_propery(element, name):
class KDEnliveProject: class KDEnliveProject:
def to_xml(self): def to_xml(self):
@ -316,7 +318,10 @@ class KDEnliveProject:
return prefix + self.get_counter(prefix) return prefix + self.get_counter(prefix)
def get_chain(self, file, kdenlive_id=None): def get_chain(self, file, kdenlive_id=None):
out = subprocess.check_output(['melt', file, '-consumer', 'xml']) if file in _CACHE:
out = _CACHE[file]
else:
out = _CACHE[file] = subprocess.check_output(['melt', file, '-consumer', 'xml'])
chain = lxml.etree.fromstring(out).xpath('producer')[0] chain = lxml.etree.fromstring(out).xpath('producer')[0]
chain.tag = 'chain' chain.tag = 'chain'
chain.attrib['id'] = self.get_id('chain') chain.attrib['id'] = self.get_id('chain')