pandora_cut/edl/fcp.py

274 lines
9.7 KiB
Python

from ox.utils import ET
from urllib import quote
import os
import uuid
from utils import tostring
def xmlroot(root, key, data):
if isinstance(data, list) or \
isinstance(data, tuple):
e = ET.SubElement(root, key.split(':')[0])
for value in data:
xmlroot(e, key, value)
elif isinstance(data, dict):
for k in data:
if k.startswith('_'):
root.attrib[k[1:]] = data[k]
xmlroot(root, k, data[k])
else:
if key.startswith('_'):
root.attrib[key[1:]] = unicode(data)
else:
e = ET.SubElement(root, key.split(':')[0])
if isinstance(data, bool):
e.text = 'TRUE' if data else 'FALSE'
else:
e.text = unicode(data)
class Project(object):
duration = 0
timebase = 30
ntsc = True
width = 1920
height = 1080
colordepth = 24
samplerate = 48000
audiodepth = 16
_clips = {
'video1': [],
'audio1': [],
'audio2': [],
}
files = {}
_files = []
clip_n = 1
def add_clip(self, clip, position):
clip_in = self.frames(clip['in'])
clip_out = self.frames(clip['out'])
duration = clip_out - clip_in
f, name = self.get_file(clip)
for track, type in ((1, 'video'), (1, 'audio'), (2, 'audio')):
self._clips['%s%s' % (type, track)].append({
'_id': 'clip%s_%s_%s' % (self.clip_n, type, track),
'name': name,
'duration': int(clip['durations'][0] * self.timebase),
'rate': [{
'ntsc': self.ntsc,
'timebase': self.timebase
}],
#clip in/out
'in': clip_in,
'out': clip_out,
#timeline position
'start': position,
'end': position + duration,
'file': [f],
'sourcetrack': [{
'mediatype': type,
'trackindex': track
}],
'comments': [{
'mastercomment1': clip['url'],
'clipcommenta': clip['url'],
}],
})
self.clip_n += 1
return position + duration
def frames(self, seconds):
return int((30000.0/1001 if self.ntsc else self.timebase) * seconds)
def get_file(self, clip):
path = clip['path']
if path in self.files:
f = {'_id': self.files[path]['_id']}
name = self.files[path]['name']
else:
info = {
'width': clip['width'],
'height': clip['height'],
'channels': clip['channels'],
'samplerate': clip['samplerate'],
'duration': self.frames(clip['file_duration']),
}
name = os.path.splitext(path.split('/')[-1])[0]
pathurl = '%s%s' % (self.base, quote(path))
f = self.files[path] = {
'_id': name.replace('.', '_') + '1',
'name': name,
'pathurl': pathurl,
'rate': [{
'timebase': self.timebase,
'ntsc': self.ntsc,
}],
'duration': info['duration'],
'media': [{
'video': [{
'duration': info['duration'],
'samplecharacteristics': [{
'width': info['width'],
'height': info['height'],
}]
}],
'audio': [{
'samplecharacteristics': [{
'samplerate': info['samplerate'],
'depth': 16
}],
'channelcount': info['channels']
}],
}],
}
self._files.append({
'_id': name.replace('.', '_'),
'name': name,
'duration': info['duration'],
'rate': [{
'timebase': self.timebase,
'ntsc': self.ntsc,
}],
'file': [f]
})
return f, name
def __init__(self, clips, base):
self.uuid = str(uuid.uuid1()).upper()
self.clips = clips
self.base = 'file://localhost%s' % quote(base)
self.duration = 0
for clip in self.clips:
self.duration = self.add_clip(clip, self.duration)
def __str__(self):
xmeml = ET.Element("xmeml", {
"version": "5"
})
name = 'Sequence 1'
sequence = ET.SubElement(xmeml, "sequence", {
"id": "%s " % name
})
xmlroot(sequence, 'sequence', {
'uuid': self.uuid,
'updatebehavior': 'add',
'name': name,
'duration': self.duration,
'rate': [{
'ntsc': self.ntsc,
'timebase': self.timebase
}],
'timecode': [{
'rate': [{
'ntsc': self.ntsc,
'timebase': self.timebase
}],
'string': '01:00:00;00',
'frame': self.frames(3600),
'source': 'source',
'displayformat': 'DF'
}],
'in': -1,
'out': -1,
'media': [{
'video': [{
'format': [{
'samplecharacteristics': [{
'width': self.width,
'height': self.height,
'anamorphic': False,
'pixelaspectratio': 'Square',
'fielddominance': 'none',
'rate': [{
'ntsc': self.ntsc,
'timebase': self.timebase
}],
'colordepth': self.colordepth,
'codec': [{
'name': 'Apple ProRes 422',
'appspecificdata': [{
'appname': 'Final Cut Pro',
'appmanufacturer': 'Apple Inc.',
'appversion': '7.0',
'data': [{
'qtcodec': [{
'codecname': 'Apple ProRes 422',
'codectypename': 'Apple ProRes 422',
'codectypecode': 'apcn',
'codecvendorcode': 'appl',
'spatialquality': 1024,
'temporalquality': 0,
'keyframerate': 0,
'datarate': 0,
}]
}]
}]
}]
}],
'appspecificdata': [{
'appname': 'Final Cut Pro',
'appmanufacturer': 'Apple Inc.',
'appversion': '7.0',
'data': [{
'fcpimageprocessing': [{
'useyuv': True,
'usesuperwhite': False,
'rendermode': 'Float10BPP',
}]
}],
}],
}],
'track': [{'clipitem': [clip]} for clip in self._clips['video1']]
}],
'audio': [{
'format': [{
'samplecharacteristics': [{
'depth': self.audiodepth,
'samplerate': self.samplerate,
}],
}],
'outputs': [{
'group': [{
'index': 1,
'numchannels': 2,
'downmix': 0,
'channel:1': {
'channel': [{'index': 1}]
},
'channel:2': {
'channel': [{'index': 2}]
}
}]
}],
'in': -1,
'out': -1,
'track:1': [{'clipitem': [clip]} for clip in self._clips['audio1']]
+ [{
'enabled': True,
'locked': False,
'outputchannelindex': 1,
}]
,
'track:2': [{'clipitem': [clip]} for clip in self._clips['audio2']]
+ [{
'enabled': True,
'locked': False,
'outputchannelindex': 2,
}]
,
}]
}],
'ismasterclip': False
})
b = ET.SubElement(xmeml, "bin")
ET.SubElement(b, "name").text = "Resources"
children = ET.SubElement(b, "children")
for clip in self._files:
xmlroot(children, 'clip', [clip])
return tostring(xmeml, '<!DOCTYPE xmeml>')