diff --git a/ffmpegwrapper/codec.py b/ffmpegwrapper/codec.py index e5119f7..51d53a7 100644 --- a/ffmpegwrapper/codec.py +++ b/ffmpegwrapper/codec.py @@ -40,8 +40,7 @@ class VideoCodec(Codec): return self def aspect(self, x, y): - filter = self._format_parameter(x, y) - self.add_option('-aspect', filter) + self.add_parameter('-aspect', x, y) return self def bitrate_tolerance(self, tolerance): diff --git a/ffmpegwrapper/ffmpeg.py b/ffmpegwrapper/ffmpeg.py index d32a60c..7f8afdb 100644 --- a/ffmpegwrapper/ffmpeg.py +++ b/ffmpegwrapper/ffmpeg.py @@ -141,7 +141,7 @@ class FFmpeg(OptionStore): OptionStore.__init__(self, *args) def add_option(self, key, value): - self._list.insert(0, Option({key: value})) + self.container_list.insert(0, Option(key, value)) def run(self): """Executes the command of this object. Return a diff --git a/ffmpegwrapper/filter.py b/ffmpegwrapper/filter.py index d291a50..47bb18f 100644 --- a/ffmpegwrapper/filter.py +++ b/ffmpegwrapper/filter.py @@ -31,8 +31,7 @@ class VideoFilter(FilterStore): """ def blackframe(self, amount, threshold): - filter = self._format_parameter(amount, threshold) - self.add_option('blackframe', filter) + self.add_parameter('blackframe', amount, threshold) return self def copy(self): @@ -40,35 +39,30 @@ class VideoFilter(FilterStore): return self def crop(self, out_w, out_h=None, x=None, y=None): - filter = self._format_parameter(out_w, out_h, x, y) - self.add_option('crop', filter) + self.add_parameter('crop', out_w, out_h, x, y) return self def cropdetect(self, limit=None, round=None, reset=None): - filter = self._format_parameter(limit, round, reset) - self.add_option('cropdetect', filter) + self.add_parameter('cropdetect', limit, round, reset) return self def drawbox(self, x, y, width, height, color): - filter = self._format_parameter(x, y, width, height, color) - self.add_option('drawbox', filter) + self.add_parameter('drawbox', x, y, width, height, color) return self def drawtext(self, **kwargs): - filter = self._format_keyword_parameter(**kwargs) - self.add_option('drawtext', filter) + self.add_parameter('drawtext', **kwargs) return self def fade(self, type, start, number): - filter = self._format_parameter(type, start, number) - self.add_option('fade', filter) + self.add_parameter('fade', type, start, number) return self def fieldorder(self, type): if str(type) not in ['0', '1', 'bff', 'tff']: raise ValueError('Invalid Option for fieldorder. ' 'Read FFmpeg manual!') - self.add_option('fieldorder', type) + self.add_parameter('fieldorder', type) return self def fifo(self): @@ -76,18 +70,15 @@ class VideoFilter(FilterStore): return self def format(self, *args): - filter = self._format_parameter(*args) - self.add_option('format', filter) + self.add_parameter('format', *args) return self def freior(self, name, *args): - filter = self._format_parameter(name, *args) - self.add_option('frei0r', filter) + self.add_parameter('frei0r', name, *args) return self def gradfun(self, strength='', radius=''): - filter = self._format_parameter(strength, radius) - self.add_option('gradfun', filter) + self.add_parameter('gradfun', strength, radius) return self def hflip(self): @@ -96,14 +87,12 @@ class VideoFilter(FilterStore): def hqdn3d(self, luma_sp=None, chroma_sp=None, luma_tmp=None, chroma_tmp=None): - filter = self._format_parameter( + self.add_parameter('hqdn3d', luma_sp, chroma_sp, luma_tmp, chroma_tmp) - self.add_option('hqdn3d', filter) return self def mp(self, **kwargs): - filter = self._format_keyword_parameter(**kwargs) - self.add_option('mp', filter) + self.add_parameter('mp', **kwargs) return self def negate(self): @@ -111,8 +100,7 @@ class VideoFilter(FilterStore): return self def noformat(self, *args): - filter = self._format_parameter(*args) - self.add_option('noformat', filter) + self.add_parameter('noformat', *args) return self def null(self): @@ -120,55 +108,49 @@ class VideoFilter(FilterStore): return self def overlay(self, x, y): - filter = self._format_parameter(x, y) - self.add_option('overlay', filter) + self.add_parameter('overlay', x, y) return self def pad(self, width, height, x, y, color): - filter = self._format_parameter(width, height, x, y, color) - self.add_option('pad', filter) + self.add_parameter('pad', width, height, x, y, color) return self def scale(self, width=-1, height=-1): - filter = self._format_parameter(width, height) - self.add_option('scale', filter) + self.add_parameter('scale', width, height) return self def select(self, expression): - self.add_option('select', expression) + self.add_parameter('select', expression) return self def setdar(self, x, y): - filter = self._format_parameter(x, y) - self.add_option('setdar', filter) + self.add_parameter('setdar', x, y) return self def setpts(self, expression): - self.add_option('setpts', expression) + self.add_parameter('setpts', expression) return self def setsar(self, x, y): - filter = self._format_parameter(x, y) - self.add_option('setsar', filter) + self.add_parameter('setsar', x, y) return self def slicify(self, height=16): - self.add_option("slicify", height) + self.add_parameter('slicify', height) return self def transpose(self, type): if str(type) not in ['0', '1','2', '3']: raise ValueError('Invalid Option for transpose. ' 'Read FFmpeg manual') - self.add_option('transpose', type) + self.add_parameter('transpose', type) return self def unsharp(self, *args): if len(args) > 6: message = 'unsharp() takes exactly 6 positional arguments' raise TypeError(message) - filter = self._format_parameter(*args) - self.add_option('unsharp', filter) + self.add_parameter('unsharp', *args) return self def vflip(self): @@ -176,8 +158,7 @@ class VideoFilter(FilterStore): return self def yadif(self, mode=0, parity=-1): - filter = self._format_parameter(mode, parity) - self.add_option('yadif', filter) + self.add_parameter('yadif', mode, parity) return self def __iter__(self): diff --git a/ffmpegwrapper/options.py b/ffmpegwrapper/options.py index fb7dcad..04261ee 100644 --- a/ffmpegwrapper/options.py +++ b/ffmpegwrapper/options.py @@ -1,91 +1,73 @@ # -*- coding: utf-8 -*- +from itertools import chain +from collections import MutableSequence, namedtuple -class Option(dict): - - def __init__(self, *args, **kwargs): - dict.__init__(self, *args, **kwargs) - - def __getitem__(self, key): - if key in self: - return dict.__getitem__(self, key) - - def __iter__(self): - for option, value in self.items(): - yield option - if value: - yield value - - def iteritems(self): - for option, value in self.items(): - yield (option, value) - - def __repr__(self): - return "<{cls} {opts}>".format(opts=list(self), - cls=self.__class__.__name__) +try: + from itertools import ifilter +except ImportError: + ifilter = filter -class OptionStore(object): +def format_parameter(*args, **kwargs): + parameter_list = [] + for key, value in kwargs.items(): + try: + if not value: + parameter_list.append(key) + else: + parameter_list.append("=".join([key, value])) + except TypeError: + values = ':'.join(kwargs[key]) + parameter_list.append("=".join([key, values])) + for value in args: + if value is not None: + parameter_list.append(str(value)) + result = ':'.join(parameter_list) + if kwargs: + return '"%s"' % result + return result - def __init__(self, *args): - self._list = list(args) - def __add__(self, other): - self.append(other) +Option = namedtuple('Option', ['name', 'value']) - def append(self, item): - self._list.append(item) - def insert(self, item): - self._list.insert(item) +class OptionStore(MutableSequence): - def pop(self): - return self._list.pop() - - def remove(self, item): - self._list.remove() - - def count(self, items): - return self._list.count() - - def index(self, item): - return self._list.index(item) + def __init__(self, *containers): + self.container_list = list(containers) def add_option(self, key, value): - self._list.append(Option({key: value})) + self.container_list.append(Option(key, value)) - @property - def option_containers(self): - return self._list + def add_parameter(self, name, *args, **kwargs): + parameter = format_parameter(*args, **kwargs) + self.add_option(name, parameter) - def __iter__(self): - for option in self._list: - for item in option: - yield item + def insert(self, index, value): + self.container_list.insert(index, value) def iteritems(self): - for option in self._list: - for item in option.iteritems(): - yield item + return iter(self.container_list) - def _format_parameter(self, *args): - parameter = filter(lambda x: x is not None, args) - return ':'.join(map(str, parameter)) + def __iter__(self): + return ifilter(None, chain.from_iterable(self.container_list)) - def _format_keyword_parameter(self, **kwargs): - parameter_list = [] - print(kwargs) - for key, value in kwargs.items(): - try: - if not value: - parameter_list.append(key) - else: - parameter_list.append("=".join([key, value])) - except TypeError: - values = ':'.join(kwargs[key]) - parameter_list.append("=".join([key, values])) - return '"' + ':'.join(parameter_list) + '"' + def __len__(self): + return self.container_list.__len__() + + def __setitem__(self, index, value): + self.container_list.__setitem__(index, value) + + def __getitem__(self, index): + return self.container_list.__getitem__(index) + + def __delitem__(self, index): + self.container_list.__delitem__(index) + + def __contains__(self, other): + return self.container_list.__contains__(other) def __repr__(self): - return "<{cls} {opts}>".format(opts=list(self), - cls=self.__class__.__name__) + return "<{cls} {opts}>".format( + opts=list(self), cls=self.__class__.__name__) diff --git a/test.py b/test.py index ca9d14d..fc19721 100644 --- a/test.py +++ b/test.py @@ -14,26 +14,26 @@ class FFmpegTestCase(unittest.TestCase): self.assertEqual(list(input), ['-i', '/old']) self.assertEqual(input.file, '/old') - option = Option({'-vf': 'x11grab'}) + option = Option('-vf', 'x11grab') input.append(option) self.assertEqual(list(input), ['-vf', 'x11grab', '-i', '/old']) self.assertEqual(input.pop(), option) input.add_option('-vf', 'x11grab') - self.assertEqual(input.option_containers, [option]) + self.assertEqual(input.container_list, [option]) def test_output_interface(self): output = Output('/new') self.assertEqual(list(output), ['/new']) self.assertEqual(output.file, '/new') - option = Option({'-vcodec': 'libx264'}) + option = Option('-vcodec', 'libx264') output.append(option) self.assertEqual(list(output), ['-vcodec', 'libx264', '/new']) self.assertEqual(output.pop(), option) output.add_option('-vcodec', 'libx264') - self.assertEqual(output.option_containers, [option]) + self.assertEqual(output.container_list, [option]) def test_codec_interface(self): codec = VideoCodec('libx264')