moviepy.tools — MoviePy 1.0.1 documentation

# Source code for moviepy.tools

    """
    Misc. useful functions that can be used at many places in the program.
    """

    import subprocess as sp
    import sys
    import warnings
    import re
    import proglog

    import os
    from .compat import DEVNULL

    def sys_write_flush(s):
        """ Writes and flushes without delay a text in the console """
        # Reason for not using `print` is that in some consoles "print"
        # commands get delayed, while stdout.flush are instantaneous,
        # so this method is better at providing feedback.
        # See https://github.com/Zulko/moviepy/pull/485
        sys.stdout.write(s)
        sys.stdout.flush()

    def verbose_print(verbose, s):
        """ Only prints s (with sys_write_flush) if verbose is True."""
        if verbose:
            sys_write_flush(s)

    def subprocess_call(cmd, logger='bar', errorprint=True):
        """ Executes the given subprocess command.

        Set logger to None or a custom Proglog logger to avoid printings.
        """
        logger = proglog.default_bar_logger(logger)
        logger(message='Moviepy - Running:\n>>> "+ " ".join(cmd)')

        popen_params = {"stdout": DEVNULL,
                        "stderr": sp.PIPE,
                        "stdin": DEVNULL}

        if os.name == "nt":
            popen_params["creationflags"] = 0x08000000

        proc = sp.Popen(cmd, **popen_params)

        out, err = proc.communicate() # proc.wait()
        proc.stderr.close()

        if proc.returncode:
            if errorprint:
                logger(message='Moviepy - Command returned an error')
            raise IOError(err.decode('utf8'))
        else:
            logger(message='Moviepy - Command successful')

        del proc

    def is_string(obj):
        """ Returns true if s is string or string-like object,
        compatible with Python 2 and Python 3."""
        try:
            return isinstance(obj, basestring)
        except NameError:
            return isinstance(obj, str)

    def cvsecs(time):
        """ Will convert any time into seconds.
        Here are the accepted formats:

        >>> cvsecs(15.4) -> 15.4 # seconds
        >>> cvsecs( (1,21.5) ) -> 81.5 # (min,sec)
        >>> cvsecs( (1,1,2) ) -> 3662 # (hr, min, sec)
        >>> cvsecs('01:01:33.5') -> 3693.5  #(hr,min,sec)
        >>> cvsecs('01:01:33.045') -> 3693.045
        >>> cvsecs('01:01:33,5') #coma works too
        """

        if is_string(time):
            if (',' not in time) and ('.' not in time):
                time = time + '.0'
            expr = r"(\d+):(\d+):(\d+)[,|.](\d+)"
            finds = re.findall(expr, time)[0]
            nums = list( map(float, finds) )
            return ( 3600*int(finds[0])
                    + 60*int(finds[1])
                    + int(finds[2])
                    + nums[3]/(10**len(finds[3])))

        elif isinstance(time, tuple):
            if len(time)== 3:
                hr, mn, sec = time
            elif len(time)== 2:
                hr, mn, sec = 0, time[0], time[1]
            return 3600*hr + 60*mn + sec

        else:
            return time

    def deprecated_version_of(f, oldname, newname=None):
        """ Indicates that a function is deprecated and has a new name.

        `f` is the new function, `oldname` the name of the deprecated
        function, `newname` the name of `f`, which can be automatically
        found.

        Returns
        ========

        f_deprecated
          A function that does the same thing as f, but with a docstring
          and a printed message on call which say that the function is
          deprecated and that you should use f instead.

        Examples
        =========

        >>> # The badly named method 'to_file' is replaced by 'write_file'
        >>> class Clip:
        >>>    def write_file(self, some args):
        >>>        # blablabla
        >>>
        >>> Clip.to_file = deprecated_version_of(Clip.write_file, 'to_file')
        """

        if newname is None: newname = f.__name__

        warning= ("The function ``%s`` is deprecated and is kept temporarily "
                  "for backwards compatibility.\nPlease use the new name, "
                  "``%s``, instead.")%(oldname, newname)

        def fdepr(*a, **kw):
            warnings.warn("MoviePy: " + warning, PendingDeprecationWarning)
            return f(*a, **kw)
        fdepr.__doc__ = warning

        return fdepr

    # non-exhaustive dictionnary to store default informations.
    # any addition is most welcome.
    # Note that 'gif' is complicated to place. From a VideoFileClip point of view,
    # it is a video, but from a HTML5 point of view, it is an image.

    extensions_dict = { "mp4":  {'type':'video', 'codec':['libx264','libmpeg4', 'aac']},
                        'ogv':  {'type':'video', 'codec':['libtheora']},
                        'webm': {'type':'video', 'codec':['libvpx']},
                        'avi':  {'type':'video'},
                        'mov':  {'type':'video'},

                        'ogg':  {'type':'audio', 'codec':['libvorbis']},
                        'mp3':  {'type':'audio', 'codec':['libmp3lame']},
                        'wav':  {'type':'audio', 'codec':['pcm_s16le', 'pcm_s24le', 'pcm_s32le']},
                        'm4a':  {'type':'audio', 'codec':['libfdk_aac']}
                      }

    for ext in ["jpg", "jpeg", "png", "bmp", "tiff"]:
        extensions_dict[ext] = {'type':'image'}

    def find_extension(codec):
        for ext,infos in extensions_dict.items():
            if ('codec' in infos) and codec in infos['codec']:
                return ext
        raise ValueError