add render command
This commit is contained in:
parent
950287a2f7
commit
debe1837a7
5 changed files with 698 additions and 0 deletions
23
.editorconfig
Normal file
23
.editorconfig
Normal file
|
@ -0,0 +1,23 @@
|
|||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.py]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.sass]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.scss]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.html]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.js]
|
||||
indent_style = space
|
||||
indent_size = 4
|
28
management/commands/render.py
Normal file
28
management/commands/render.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
|
||||
from ...render import compose, render
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'generate symlinks to clips and clips.json'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
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('--offset', action='store', dest='offset', default="1024", help='inital offset in pi')
|
||||
|
||||
def handle(self, **options):
|
||||
prefix = options['prefix']
|
||||
target = int(options['duration'])
|
||||
base = int(options['offset'])
|
||||
|
||||
with open(os.path.join(prefix, "clips.json")) as fd:
|
||||
clips = json.load(fd)
|
||||
scene = compose(clips, target=target, base=base)
|
||||
render(prefix, scene)
|
||||
with open(os.path.join(prefix, 'scene-%s.json' % base), 'w') as fd:
|
||||
json.dump(scene, fd, indent=2, ensure_ascii=False)
|
20
pi.py
Normal file
20
pi.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from mpmath import mp
|
||||
mp.dps = 10000
|
||||
PI = str(mp.pi).replace('.', '')
|
||||
|
||||
class random(object):
|
||||
PI = str(mp.pi).replace('.', '')
|
||||
|
||||
def __init__(self, offset=0):
|
||||
self.position = offset
|
||||
self.numbers = list(map(int, self.PI[offset:]))
|
||||
|
||||
def __call__(self):
|
||||
if not self.numbers:
|
||||
offset = mp.dps
|
||||
mp.dps += 1000
|
||||
self.PI = str(mp.pi).replace('.', '')
|
||||
self.numbers = list(map(int, self.PI[offset:]))
|
||||
self.position += 1
|
||||
return self.numbers.pop(0)
|
||||
|
126
render.py
Normal file
126
render.py
Normal file
|
@ -0,0 +1,126 @@
|
|||
#!/usr/bin/python3
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import ox
|
||||
from pi import random
|
||||
from render_kdenlive import KDEnliveProject
|
||||
|
||||
|
||||
def random_choice(seq, items, pop=False):
|
||||
n = n_ = len(items) - 1
|
||||
#print('len', n)
|
||||
if n == 0:
|
||||
return items[0]
|
||||
r = seq()
|
||||
base = 10
|
||||
while n > 10:
|
||||
n /= 10
|
||||
#print(r)
|
||||
r += seq()
|
||||
base += 10
|
||||
r = int(n_ * r / base)
|
||||
#print('result', r, items)
|
||||
if pop:
|
||||
return items.pop(r)
|
||||
return items[r]
|
||||
|
||||
def chance(seq, chance):
|
||||
return (seq() / 10) >= chance
|
||||
|
||||
|
||||
def compose(clips, target=150, base=1024):
|
||||
length = 0
|
||||
scene = {
|
||||
'front': {
|
||||
'V1': [],
|
||||
'V2': [],
|
||||
},
|
||||
'back': {
|
||||
'V1': [],
|
||||
'V2': [],
|
||||
},
|
||||
'audio': {
|
||||
'A1': [],
|
||||
'A2': [],
|
||||
'A3': [],
|
||||
'A4': [],
|
||||
}
|
||||
}
|
||||
seq = random(base)
|
||||
while target - length > 10 and clips:
|
||||
clip = random_choice(seq, clips, True)
|
||||
if length + clip['duration'] > target:
|
||||
break
|
||||
length += clip['duration']
|
||||
|
||||
scene['front']['V1'].append({
|
||||
'duration': clip['duration'],
|
||||
'src': clip['foreground'],
|
||||
"filter": {
|
||||
'transparency': seq() / 10,
|
||||
}
|
||||
})
|
||||
|
||||
transparency = seq() / 10
|
||||
# coin flip which site is visible (50% chance)
|
||||
if chance(seq, 0.5):
|
||||
transparency_front = transparency
|
||||
transparency_back = 0
|
||||
else:
|
||||
transparency_back = transparency
|
||||
transparency_front = 0
|
||||
scene['front']['V2'].append({
|
||||
'duration': clip['duration'],
|
||||
'src': clip['background'],
|
||||
"filter": {
|
||||
'transparency': transparency_front
|
||||
}
|
||||
})
|
||||
scene['back']['V1'].append({
|
||||
'duration': clip['duration'],
|
||||
'src': clip['background'],
|
||||
"filter": {
|
||||
'transparency': transparency_back
|
||||
}
|
||||
})
|
||||
scene['back']['V2'].append({
|
||||
'duration': clip['duration'],
|
||||
'src': clip['original'],
|
||||
"filter": {
|
||||
'transparency': seq() / 10,
|
||||
}
|
||||
})
|
||||
# 50 % chance to blur original from 0 to 30
|
||||
if chance(seq, 0.5):
|
||||
blur = seq() * 3
|
||||
scene['back']['V2'][-1]['filter']['blur'] = blur
|
||||
scene['audio']['A1'].append({
|
||||
'duration': clip['duration'],
|
||||
'src': clip['original'],
|
||||
})
|
||||
scene['audio']['A2'].append({
|
||||
'duration': clip['duration'],
|
||||
'src': clip['foreground'],
|
||||
})
|
||||
return scene
|
||||
|
||||
|
||||
def render(root, scene):
|
||||
fps = 24
|
||||
for timeline, data in scene.items():
|
||||
print(timeline)
|
||||
project = KDEnliveProject(root)
|
||||
|
||||
tracks = []
|
||||
for track, clips in data.items():
|
||||
print(track)
|
||||
for clip in clips:
|
||||
project.append_clip(track, clip)
|
||||
|
||||
with open(os.path.join(prefix, "%s.kdenlive" % timeline), 'w') as fd:
|
||||
fd.write(project.to_xml())
|
||||
|
501
render_kdenlive.py
Normal file
501
render_kdenlive.py
Normal file
|
@ -0,0 +1,501 @@
|
|||
#!/usr/bin/python3
|
||||
from collections import defaultdict
|
||||
import subprocess
|
||||
import lxml.etree
|
||||
import uuid
|
||||
import os
|
||||
|
||||
_IDS = defaultdict(int)
|
||||
|
||||
def get_propery(element, name):
|
||||
return element.xpath('property[@name="%s"]' % name)[0].text
|
||||
|
||||
|
||||
|
||||
class KDEnliveProject:
|
||||
|
||||
def to_xml(self):
|
||||
track = self._main_tractor.xpath(".//track")[0]
|
||||
duration = max(self._duration.values())
|
||||
track.attrib["in"] = self._sequence.attrib["in"] = self._main_tractor.attrib["in"] = "0"
|
||||
track.attrib["out"] = self._sequence.attrib["out"] = self._main_tractor.attrib["out"] = str(duration - 1)
|
||||
self._tree.remove(self._sequence)
|
||||
self._tree.append(self._sequence)
|
||||
self._tree.remove(self._main_bin)
|
||||
self._tree.append(self._main_bin)
|
||||
self._tree.remove(self._main_tractor)
|
||||
self._tree.append(self._main_tractor)
|
||||
|
||||
xml = lxml.etree.tostring(self._tree, pretty_print=True).decode()
|
||||
xml = xml.replace('><', '>\n<')
|
||||
return "<?xml version='1.0' encoding='utf-8'?>\n" + xml
|
||||
|
||||
def __init__(
|
||||
self, root,
|
||||
width="1920", height="1080",
|
||||
display_aspect_num="16", display_aspect_den="9",
|
||||
frame_rate_num="24", frame_rate_den="1"
|
||||
):
|
||||
self._duration = defaultdict(int)
|
||||
self._counters = defaultdict(int)
|
||||
self._uuid = '{%s}' % str(uuid.uuid1())
|
||||
self._width = int(width)
|
||||
self._height = int(height)
|
||||
self._fps = int(frame_rate_num) / int(frame_rate_den)
|
||||
|
||||
self._tree = self.get_element("mlt", attrib={
|
||||
"LC_NUMERIC": "C",
|
||||
"producer": "main_bin",
|
||||
"version": "7.18.0",
|
||||
"root": root
|
||||
}, children=[
|
||||
self.get_element("profile", attrib={
|
||||
"frame_rate_num": str(frame_rate_num),
|
||||
"frame_rate_den": str(frame_rate_den),
|
||||
"display_aspect_den": str(display_aspect_den),
|
||||
"display_aspect_num": str(display_aspect_num),
|
||||
"colorspace": "601",
|
||||
"progressive": "1",
|
||||
"description": "%sx%s %0.2ffps" % (self._width, self._height, self._fps),
|
||||
"width": str(width),
|
||||
"height": str(height),
|
||||
"sample_aspect_num": "1",
|
||||
"sample_aspect_den": "1"
|
||||
}),
|
||||
p0 := self.get_element("producer", attrib={
|
||||
"in": "0",
|
||||
"out": "2147483647"
|
||||
}, children=[
|
||||
["length", "2147483647"],
|
||||
["eof", "continue"],
|
||||
["resource", "black"],
|
||||
["aspect_ratio", "1"],
|
||||
["mlt_service", "color"],
|
||||
["kdenlive:playlistid", "black_track"],
|
||||
["mlt_image_format", "rgba"],
|
||||
["set.test_audio", "0"],
|
||||
]),
|
||||
a2 := self.get_element("playlist", children=[
|
||||
["kdenlive:audio_track", "1"],
|
||||
]),
|
||||
a2e := self.get_element("playlist", children=[
|
||||
["kdenlive:audio_track", "1"],
|
||||
]),
|
||||
t0 := self.get_element("tractor", children=[
|
||||
["kdenlive:audio_track", "1"],
|
||||
["kdenlive:trackheight", "69"],
|
||||
["kdenlive:timeline_active", "1"],
|
||||
["kdenlive:collapsed", "0"],
|
||||
["kdenlive:thumbs_format", None],
|
||||
["kdenlive:audio_rec", None],
|
||||
self.get_element("track", attrib={"hide": "video", "producer": a2.attrib["id"]}),
|
||||
self.get_element("track", attrib={"hide": "video", "producer": a2e.attrib["id"]}),
|
||||
self.get_element("filter", [
|
||||
["window", "75"],
|
||||
["max_gain", "20dB"],
|
||||
["mlt_service", "volume"],
|
||||
["internal_added", "237"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
self.get_element("filter", [
|
||||
["channel", "-1"],
|
||||
["mlt_service", "panner"],
|
||||
["internal_added", "237"],
|
||||
["start", "0.5"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
self.get_element("filter", [
|
||||
["iec_scale", "0"],
|
||||
["mlt_service", "audiolevel"],
|
||||
["dbpeak", "1"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
]),
|
||||
a1 := self.get_element("playlist", children=[
|
||||
["kdenlive:audio_track", "1"],
|
||||
]),
|
||||
a1e := self.get_element("playlist", children=[
|
||||
["kdenlive:audio_track", "1"],
|
||||
]),
|
||||
t1 := self.get_element("tractor", children=[
|
||||
["kdenlive:audio_track", "1"],
|
||||
["kdenlive:trackheight", "69"],
|
||||
["kdenlive:timeline_active", "1"],
|
||||
["kdenlive:collapsed", "0"],
|
||||
["kdenlive:thumbs_format", None],
|
||||
["kdenlive:audio_rec", None],
|
||||
self.get_element("track", attrib={"hide": "video", "producer": a1.attrib["id"]}),
|
||||
self.get_element("track", attrib={"hide": "video", "producer": a1e.attrib["id"]}),
|
||||
self.get_element("filter", [
|
||||
["window", "75"],
|
||||
["max_gain", "20dB"],
|
||||
["mlt_service", "volume"],
|
||||
["internal_added", "237"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
self.get_element("filter", [
|
||||
["channel", "-1"],
|
||||
["mlt_service", "panner"],
|
||||
["internal_added", "237"],
|
||||
["start", "0.5"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
self.get_element("filter", [
|
||||
["iec_scale", "0"],
|
||||
["mlt_service", "audiolevel"],
|
||||
["dbpeak", "1"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
]),
|
||||
v2 := self.get_element("playlist", children=[
|
||||
]),
|
||||
v2e := self.get_element("playlist", children=[
|
||||
]),
|
||||
t2 := self.get_element("tractor", attrib={
|
||||
"in": "00:00:00.000",
|
||||
"out": "00:00:25.333"
|
||||
}, children=[
|
||||
["kdenlive:trackheight", "69"],
|
||||
["kdenlive:timeline_active", "1"],
|
||||
["kdenlive:collapsed", "0"],
|
||||
["kdenlive:thumbs_format", None],
|
||||
["kdenlive:audio_rec", None],
|
||||
["kdenlive:locked_track", None],
|
||||
self.get_element("track", attrib={"hide": "audio", "producer": v2.attrib["id"]}),
|
||||
self.get_element("track", attrib={"hide": "audio", "producer": v2e.attrib["id"]}),
|
||||
]),
|
||||
v1 := self.get_element("playlist", children=[
|
||||
]),
|
||||
v1e := self.get_element("playlist", children=[
|
||||
]),
|
||||
t3 := self.get_element("tractor", attrib={
|
||||
"in": "00:00:00.000"
|
||||
}, children=[
|
||||
["kdenlive:trackheight", "69"],
|
||||
["kdenlive:timeline_active", "1"],
|
||||
["kdenlive:collapsed", "0"],
|
||||
["kdenlive:thumbs_format", None],
|
||||
["kdenlive:audio_rec", None],
|
||||
["kdenlive:locked_track", None],
|
||||
self.get_element("track", attrib={"hide": "audio", "producer": v1.attrib["id"]}),
|
||||
self.get_element("track", attrib={"hide": "audio", "producer": v1e.attrib["id"]}),
|
||||
]),
|
||||
sequence := self.get_element("tractor", [
|
||||
["kdenlive:uuid", self._uuid],
|
||||
["kdenlive:clipname", "Sequence 1"],
|
||||
["kdenlive:sequenceproperties.hasAudio", "1"],
|
||||
["kdenlive:sequenceproperties.hasVideo", "1"],
|
||||
["kdenlive:sequenceproperties.activeTrack", "2"],
|
||||
["kdenlive:sequenceproperties.tracksCount", "4"],
|
||||
["kdenlive:sequenceproperties.documentuuid", self._uuid],
|
||||
["kdenlive:duration", "00:00:25:09"],
|
||||
["kdenlive:maxduration", "872"],
|
||||
["kdenlive:producer_type", "17"],
|
||||
["kdenlive:id", self.get_counter("kdenlive:id")],
|
||||
["kdenlive:clip_type", "0"],
|
||||
["kdenlive:folderid", "2"],
|
||||
["kdenlive:sequenceproperties.audioChannels", "2"],
|
||||
["kdenlive:sequenceproperties.audioTarget", "1"],
|
||||
["kdenlive:sequenceproperties.tracks", "4"],
|
||||
["kdenlive:sequenceproperties.verticalzoom", "1"],
|
||||
["kdenlive:sequenceproperties.videoTarget", "2"],
|
||||
["kdenlive:sequenceproperties.zonein", "0"],
|
||||
["kdenlive:sequenceproperties.zoneout", "75"],
|
||||
["kdenlive:sequenceproperties.zoom", "8"],
|
||||
["kdenlive:sequenceproperties.groups", "[]"],
|
||||
["kdenlive:sequenceproperties.guides", "[]"],
|
||||
["kdenlive:sequenceproperties.position", "0"],
|
||||
["kdenlive:sequenceproperties.scrollPos", "0"],
|
||||
["kdenlive:sequenceproperties.disablepreview", "0"],
|
||||
|
||||
self.get_element("track", attrib={"producer": p0.attrib["id"]}),
|
||||
self.get_element("track", attrib={"producer": t0.attrib["id"]}),
|
||||
self.get_element("track", attrib={"producer": t1.attrib["id"]}),
|
||||
self.get_element("track", attrib={"producer": t2.attrib["id"]}),
|
||||
self.get_element("track", attrib={"producer": t3.attrib["id"]}),
|
||||
self.get_element("transition", [
|
||||
["a_track", "0"],
|
||||
["b_track", "1"],
|
||||
["mlt_service", "mix"],
|
||||
["kdenlive_id", "mix"],
|
||||
["internal_added", "237"],
|
||||
["always_active", "1"],
|
||||
["accepts_blanks", "1"],
|
||||
["sum", "1"],
|
||||
]),
|
||||
self.get_element("transition", [
|
||||
["a_track", "0"],
|
||||
["b_track", "2"],
|
||||
["mlt_service", "mix"],
|
||||
["kdenlive_id", "mix"],
|
||||
["internal_added", "237"],
|
||||
["always_active", "1"],
|
||||
["accepts_blanks", "1"],
|
||||
["sum", "1"],
|
||||
]),
|
||||
self.get_element("transition", [
|
||||
["a_track", "0"],
|
||||
["b_track", "3"],
|
||||
["compositing", "0"],
|
||||
["distort", "0"],
|
||||
["rotate_center", "0"],
|
||||
["mlt_service", "qtblend"],
|
||||
["kdenlive_id", "qtblend"],
|
||||
["internal_added", "237"],
|
||||
["always_active", "1"],
|
||||
["accepts_blanks", "1"],
|
||||
["sum", "1"],
|
||||
]),
|
||||
self.get_element("transition", [
|
||||
["a_track", "0"],
|
||||
["b_track", "4"],
|
||||
["compositing", "0"],
|
||||
["distort", "0"],
|
||||
["rotate_center", "0"],
|
||||
["mlt_service", "qtblend"],
|
||||
["kdenlive_id", "qtblend"],
|
||||
["internal_added", "237"],
|
||||
["always_active", "1"],
|
||||
["accepts_blanks", "1"],
|
||||
["sum", "1"],
|
||||
]),
|
||||
self.get_element("filter", [
|
||||
["window", "75"],
|
||||
["max_gain", "20dB"],
|
||||
["mlt_service", "volume"],
|
||||
["internal_added", "237"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
self.get_element("filter", [
|
||||
["channel", "-1"],
|
||||
["mlt_service", "panner"],
|
||||
["internal_added", "237"],
|
||||
["start", "0.5"],
|
||||
["disable", "1"],
|
||||
]),
|
||||
], {
|
||||
"id": self._uuid
|
||||
}),
|
||||
main_bin := self.get_element("playlist", [
|
||||
["kdenlive:folder.-1.2", "Sequences"],
|
||||
["kdenlive:sequenceFolder", "2"],
|
||||
["kdenlive:docproperties.kdenliveversion", "23.08.0"],
|
||||
self.get_element("property", attrib={"name": "kdenlive:docproperties.previewextension"}),
|
||||
self.get_element("property", attrib={"name": "kdenlive:docproperties.previewparameters"}),
|
||||
["kdenlive:docproperties.seekOffset", "30000"],
|
||||
["kdenlive:docproperties.uuid", self._uuid],
|
||||
["kdenlive:docproperties.version", "1.1"],
|
||||
["kdenlive:expandedFolders", None],
|
||||
["kdenlive:binZoom", "4"],
|
||||
self.get_element("property", attrib={"name": "kdenlive:documentnotes"}),
|
||||
["kdenlive:docproperties.opensequences", self._uuid],
|
||||
["kdenlive:docproperties.activetimeline", self._uuid],
|
||||
["xml_retain", "1"],
|
||||
self.get_element("entry", attrib={"producer": self._uuid, "in": "0", "out": "0"}),
|
||||
], {
|
||||
"id": "main_bin"
|
||||
}),
|
||||
t4 := self.get_element("tractor", [
|
||||
["kdenlive:projectTractor", "1"],
|
||||
self.get_element("track", attrib={"producer": self._uuid}),
|
||||
])
|
||||
])
|
||||
self._sequence = sequence
|
||||
self._main_bin = main_bin
|
||||
self._main_tractor = t4
|
||||
self._v1 = v1
|
||||
self._v2 = v2
|
||||
self._a1 = a1
|
||||
self._a2 = a2
|
||||
|
||||
def get_counter(self, prefix):
|
||||
self._counters[prefix] += 1
|
||||
return str(self._counters[prefix] - 1)
|
||||
|
||||
def get_id(self, prefix):
|
||||
return prefix + self.get_counter(prefix)
|
||||
|
||||
def get_chain(self, file, kdenlive_id=None):
|
||||
out = subprocess.check_output(['melt', file, '-consumer', 'xml'])
|
||||
chain = lxml.etree.fromstring(out).xpath('producer')[0]
|
||||
chain.tag = 'chain'
|
||||
chain.attrib['id'] = self.get_id('chain')
|
||||
# TBD
|
||||
if kdenlive_id is None:
|
||||
kdenlive_id = self.get_counter("kdenlive:id")
|
||||
for name, value in [
|
||||
("kdenlive:file_size", os.path.getsize(file)),
|
||||
("kdenlive:clipname", None),
|
||||
("kdenlive:clip_type", "0"),
|
||||
("kdenlive:folderid", "-1"),
|
||||
("kdenlive:id", kdenlive_id),
|
||||
("set.test_audio", "1"),
|
||||
("set.test_image", "0"),
|
||||
("xml", "was here"),
|
||||
]:
|
||||
chain.append(
|
||||
self.get_element(
|
||||
"property",
|
||||
attrib={"name": name},
|
||||
text=str(value) if value is not None else None
|
||||
)
|
||||
)
|
||||
mlt_service = chain.xpath('property[@name="mlt_service"]')[0]
|
||||
mlt_service.text = "avformat-novalidate"
|
||||
return chain
|
||||
|
||||
def get_element(self, tag, children=[], attrib={}, text=None):
|
||||
element = lxml.etree.Element(tag)
|
||||
if tag not in (
|
||||
"blank",
|
||||
"entry",
|
||||
"mlt",
|
||||
"profile",
|
||||
"property",
|
||||
"track",
|
||||
) and "id" not in attrib:
|
||||
element.attrib['id'] = self.get_id(tag)
|
||||
if attrib:
|
||||
for key, value in attrib.items():
|
||||
element.attrib[key] = value
|
||||
for child in children:
|
||||
if isinstance(child, list) and len(child) == 2:
|
||||
v = child[1]
|
||||
if v is not None:
|
||||
v = str(v)
|
||||
child = self.get_element("property", attrib={"name": child[0]}, text=v)
|
||||
if isinstance(child, dict):
|
||||
child = self.get_element(**child)
|
||||
elif isinstance(child, list):
|
||||
child = self.get_element(*child)
|
||||
element.append(child)
|
||||
if text is not None:
|
||||
element.text = text
|
||||
return element
|
||||
|
||||
def get_filter(self, name, value):
|
||||
if name == "transparency":
|
||||
return [self.get_element("filter", [
|
||||
["version", "0.9"],
|
||||
["mlt_service", "frei0r.transparency"],
|
||||
["kdenlive_id", "frei0r.transparency"],
|
||||
["0", "00:00:00.000=%s" % value],
|
||||
["kdenlive:collapsed", "0"],
|
||||
])]
|
||||
if name == "blur":
|
||||
return [self.get_element("filter", [
|
||||
["mlt_service", "avfilter.avgblur"],
|
||||
["kdenlive_id", "avfilter.avgblur"],
|
||||
["av.sizeX", value],
|
||||
["av.sizeY", value],
|
||||
["planes", "7"],
|
||||
["kdenlive:collapsed", "0"],
|
||||
])]
|
||||
if name == "mask":
|
||||
mask = [
|
||||
self.get_element("filter", [
|
||||
["mlt_service", "frei0r.saturat0r"],
|
||||
["kdenlive_id", "frei0r.saturat0r"],
|
||||
["Saturation", "00:00:00.000=0.001"],
|
||||
]),
|
||||
self.get_element("filter", [
|
||||
["mlt_service", "frei0r.select0r"],
|
||||
["kdenlive_id", "frei0r.select0r"],
|
||||
["Color to select", "00:00:00.000=0x000000ff"],
|
||||
["Invert selection", "1"],
|
||||
["Selection subspace", "0"],
|
||||
["Subspace shape", "0.5"],
|
||||
["Edge mode", "0.9"],
|
||||
["Delta R / A / Hue", "00:00:00.000=0.381"],
|
||||
["Delta G / B / Chroma", "00:00:00.000=0.772"],
|
||||
["Delta B / I / I", "00:00:00.000=0.522"],
|
||||
["Slope", "00:00:00.000=0.515"],
|
||||
["Operation", "0.5"],
|
||||
])
|
||||
]
|
||||
return mask
|
||||
else:
|
||||
return [
|
||||
self.get_element("filter", [
|
||||
["mlt_service", name],
|
||||
["kdenlive_id", name],
|
||||
] + value)
|
||||
]
|
||||
|
||||
|
||||
def properties(self, *props):
|
||||
return [
|
||||
self.get_element("property", attrib={"name": name}, text=str(value) if value is not None else value)
|
||||
for name, value in props
|
||||
]
|
||||
|
||||
|
||||
def append_clip(self, track_id, clip):
|
||||
path = clip['src']
|
||||
filters = clip.get("filter", {})
|
||||
frames = int(self._fps * clip['duration'])
|
||||
self._duration[track_id] += frames
|
||||
print(path, filters)
|
||||
chain = self.get_chain(path)
|
||||
id = get_propery(chain, "kdenlive:id")
|
||||
if track_id == "V1":
|
||||
track = self._v1
|
||||
elif track_id == "V2":
|
||||
track = self._v2
|
||||
elif track_id == "A1":
|
||||
track = self._a1
|
||||
elif track_id == "A2":
|
||||
track = self._a2
|
||||
else:
|
||||
print('!!', track_id)
|
||||
|
||||
if track_id[0] == 'A':
|
||||
has_audio = False
|
||||
for prop in chain.xpath('property'):
|
||||
if prop.attrib['name'].endswith('stream.type') and prop.text == "audio":
|
||||
has_audio = True
|
||||
idx = self._tree.index(track) - 1
|
||||
self._tree.insert(idx, chain)
|
||||
filters_ = []
|
||||
if track_id == 'V':
|
||||
filters_.append({
|
||||
self.get_element("filter", [
|
||||
["mlt_service", "qtblend"],
|
||||
["kdenlive_id", "qtblend"],
|
||||
["rotate_center", "1"],
|
||||
["rect", "00:00:00.000=0 0 %s %s 1.000000" % (self._width, self.height)],
|
||||
["rotation", "00:00:00.000=0"],
|
||||
["compositing", "0"],
|
||||
["distort", "0"],
|
||||
["kdenlive:collapsed", "0"],
|
||||
["disable", "0"],
|
||||
])
|
||||
})
|
||||
|
||||
for ft in filters.items():
|
||||
filters_ += self.get_filter(*ft)
|
||||
if track_id[0] == 'A' and not has_audio:
|
||||
track.append(
|
||||
self.get_element("blank", attrib={
|
||||
"length": str(frames),
|
||||
})
|
||||
)
|
||||
else:
|
||||
track.append(
|
||||
self.get_element("entry", attrib={
|
||||
"producer": chain.attrib["id"],
|
||||
"in": chain.attrib["in"],
|
||||
"out": str(frames),
|
||||
}, children=[
|
||||
["kdenlive:id", id],
|
||||
] + filters_),
|
||||
)
|
||||
chain = self.get_chain(path, id)
|
||||
self._tree.append(chain)
|
||||
self._main_bin.append(
|
||||
self.get_element("entry", attrib={
|
||||
"producer": chain.attrib["id"],
|
||||
"in": chain.attrib["in"],
|
||||
"out": chain.attrib["out"],
|
||||
}),
|
||||
)
|
Loading…
Reference in a new issue