Source code for vidpy.composition

import os
from subprocess import call, check_output
import uuid
from xml.etree.ElementTree import Element, tostring, fromstring
from . import config
from .clip import Clip
from .utils import timestamp, check_melt


[docs]class Composition(object): '''A composition made of a list of clips. Args: clips (list): A list of Clip objects bgcolor (str): The background color of the composition, in hex singletrack (bool): Boolean that determines if clips play all at once (default) or sequentially duration (float): Duration of the composition in seconds. fps (int): Frames per second of output width (int): Width of output in pixels height (int): Height of output in pixels ''' def __init__(self, clips, bgcolor='#000000', singletrack=False, duration=None, fps=None, width=None, height=None): self.clips = clips self.bg = bgcolor self.singletrack = singletrack self.duration = timestamp(duration) self.fps = fps self.width = width self.height = height def autoset_duration(self, xml): duration = self.duration if not duration: duration = self.duration = xml.find('tractor').get('out') xml.find('tractor').set('out', str(duration)) xml.find('producer').set('out', str(duration)) xml.find('producer').remove(xml.find('./producer/property[@name="length"]')) xml.find('./playlist/entry').set('out', str(duration)) return xml def set_meta(self, xml): profile = xml.find('profile') if self.fps: profile.set('frame_rate_num', str(self.fps)) if self.width and self.height: profile.set('width', str(self.width)) profile.set('display_aspect_num', str(self.width)) profile.set('height', str(self.height)) profile.set('display_aspect_den', str(self.height)) return xml
[docs] def xml(self): '''Renders the composition as XML and sets the current duration, width, height and fps. Returns: str: an mlt xml representation of the composition ''' xml = check_output(self.args() + ['-consumer', 'xml']) xml = fromstring(xml) xml = self.autoset_duration(xml) xml = self.set_meta(xml) return tostring(xml)
[docs] def save_xml(self, filename=None): '''Saves the composition as a mlt xml file. Args: filename (str): path to save to Returns: str: path to the saved file ''' if filename is None: filename = str(uuid.uuid4()) + '.xml' with open(filename, 'wb') as outfile: outfile.write(self.xml()) return filename
[docs] def preview(self): ''' Previews the composition using melt's default viewer.''' check_melt() xmlfile = self.save_xml() call([config.MELT_BINARY, xmlfile, 'out="{}"'.format(self.duration)]) os.remove(xmlfile)
[docs] def save(self, filename, **kwargs): '''Save the composition as a video file. Args: filename (str): the file to save to (any video type is accepted) **kwargs: additional parameters to pass to ffmpeg Returns: filename (str): the path to the saved file ''' check_melt() xmlfile = self.save_xml() args = [ config.MELT_BINARY, xmlfile, 'out="{}"'.format(self.duration), '-consumer', 'avformat:{}'.format(filename) ] extra_params = ['{}="{}"'.format(key, val) for key, val in kwargs.items()] args += extra_params call(args) os.remove(xmlfile) return filename
[docs] def args(self): '''Generate mlt command line arguments Returns: str: mlt command line arguments ''' args = [config.MELT_BINARY] # add the the background track args += ['-track', 'color:{}'.format(self.bg), 'out=0'] # add a track for all clips in singletrack if self.singletrack: args += ['-track'] # add args and transitions for all clips for i, c in enumerate(self.clips): c.track_number = i + 1 args += c.args(self.singletrack) args += c.transition_args(i+1) # add mask clips for i, c in enumerate(self.clips): if c.mask: args += c.mask.args() # add matte transitions for mask clips mask_track_number = len(self.clips) for i, c in enumerate(self.clips): if c.mask: args += ['-transition', 'matte', 'a_track={}'.format(c.track_number), 'b_track={}'.format(mask_track_number)] mask_track_number += 1 # add composite transitions for all tracks if self.singletrack: args += ['-transition', 'composite', 'distort=0', 'a_track=0', 'b_track=1'] else: for i, c in enumerate(self.clips): args += ['-transition', 'composite', 'distort=0', 'a_track=0', 'b_track={}'.format(i+1)] args += ['-transition', 'mix', 'a_track=0', 'b_track={}'.format(i+1)] return args
def __str__(self): return ' '.join(self.args())