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, '')