def ffprobe(stream: IO[bytes], cmd='ffprobe', **kwargs):
        """Run ffprobe on an input stream and return a JSON representation of the output.

        Code adopted from ffmpeg-python by Karl Kroening (Apache License 2.0).
        Copyright 2017 Karl Kroening

        Raises:
            :class:`ffmpeg.Error`: if ffprobe returns a non-zero exit code,
                an :class:`Error` is returned with a generic error message.
                The stderr output can be retrieved by accessing the
                ``stderr`` property of the exception.
        """
        args = [cmd, '-show_format', '-show_streams', '-of', 'json']
        args += convert_kwargs_to_cmd_line_args(kwargs)
        args += ["-"]

        p = subprocess.Popen(args,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        assert p.stdin
        copyfileobj(p.stdin, stream)
        out, err = p.communicate()
        if p.returncode != 0:
            raise ffmpeg.Error('ffprobe', out, err)
        return json.loads(out.decode('utf-8'))
示例#2
0
def convert_video_progress_bar(source: str, dest: str, manager=None):
    if manager is None:
        manager = enlighten.get_manager()
    name = source.rsplit(os.path.sep,1)[-1]
    if get_bitdepth(source).is_10bit:
        args = CONVERT_COMMAND_10Bits.format(source=source, dest=dest)
    else:
        args = CONVERT_COMMAND.format(source=source, dest=dest)
    proc = expect.spawn(args, encoding='utf-8')
    pbar = None
    try:
        proc.expect(pattern_duration)
        total = sum(map(lambda x: float(x[1])*60**x[0],enumerate(reversed(proc.match.groups()[0].strip().split(':')))))
        cont = 0
        pbar = manager.counter(total=100, desc=name, unit='%',bar_format=BAR_FMT, counter_format=COUNTER_FMT)
        while True:
            proc.expect(pattern_progress)
            progress = sum(map(lambda x: float(x[1])*60**x[0],enumerate(reversed(proc.match.groups()[0].strip().split(':')))))
            percent = progress/total*100
            pbar.update(percent-cont)
            cont = percent
    except expect.EOF:
        pass
    finally:
        if pbar is not None:
            pbar.close()
    proc.expect(expect.EOF)
    res = proc.before
    res += proc.read()
    exitstatus = proc.wait()
    if exitstatus:
        raise ffmpeg.Error('ffmpeg','',res)
示例#3
0
def play(filename, cmd=None, **kwargs):
    proc = play_async(filename, cmd, **kwargs)
    out, err = proc.communicate(None)
    retcode = proc.poll()
    if retcode:
        raise ffmpeg.Error('ffplay', out, err)
    return out, err
示例#4
0
 def __execute_ffmpeg(self):
     p = subprocess.Popen(self.__ffmpeg_cmd,
                          stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
     out, err = p.communicate()
     retcode = p.poll()
     if retcode:
         raise ffmpeg.Error('ffmpeg', out, err)
     return out, err
示例#5
0
def convert_video_progress_bar(source: str, dest: str, manager=None):
    if manager is None:
        manager = enlighten.get_manager()
    stream = ffmpeg.input(source)
    stream = ffmpeg.output(stream, dest, vcodec='libx265', crf='28')
    args = ffmpeg.compile(stream, 'ffmpeg')
    args.insert(1, '-progress pipe:1')
    args = map(lambda x: '"' + x + '"' if '\\' in x or '/' in x else x, args)
    args = list(args)
    name = source.rsplit(os.path.sep, 1)[-1]
    proc = expect.spawn(' '.join(args), encoding='utf-8')
    pbar = None
    try:
        proc.expect(pattern_duration)
        total = sum(
            map(lambda x: float(x[1]) * 60**x[0],
                enumerate(reversed(
                    proc.match.groups()[0].strip().split(':')))))
        cont = 0
        pbar = manager.counter(total=100,
                               desc=name,
                               unit='%',
                               bar_format=BAR_FMT,
                               counter_format=COUNTER_FMT)
        while True:
            proc.expect(pattern_progress)
            progress = sum(
                map(
                    lambda x: float(x[1]) * 60**x[0],
                    enumerate(
                        reversed(proc.match.groups()[0].strip().split(':')))))
            percent = progress / total * 100
            pbar.update(percent - cont)
            cont = percent
    except expect.EOF:
        pass
    finally:
        if pbar is not None:
            pbar.close()
    proc.expect(expect.EOF)
    res = proc.before
    res += proc.read()
    exitstatus = proc.wait()
    if exitstatus:
        raise ffmpeg.Error('ffmpeg', '', res)
示例#6
0
def ffmpeg_probe(path, **kwargs):
    """Run ffprobe on the specified file and return a JSON representation of
    the output.

    Based on the `ffmpeg.probe` provided by `ffmpeg-python`, but allows passing
    along additional options to `ffmpeg`.

    Parameters
    ----------
    path : str
        This parameter can be a path or URL pointing directly to a video file
        or stream.

    Raises
    ------
    ffmpeg.Error
        If `ffprobe` returns a non-zero exit code. The stderr output can be
        retrieved by accessing the `stderr` property of the exception.

    """
    if not is_path_stream(path):
        path = os.path.expanduser(path)

    # Gather all `kwargs` into a list of tokens to send to `ffprobe`.
    additional_args = []
    for key, value in kwargs.items():
        if not key.startswith('-'):
            key = f'-{key}'
        additional_args.extend([key, str(value)])

    args = [
        'ffprobe', *additional_args, '-show_format', '-show_streams', '-of',
        'json', path
    ]

    proc = subprocess.Popen(args,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)

    out, err = proc.communicate()
    if proc.returncode != 0:
        raise ffmpeg.Error('ffprobe', out, err)

    return json.loads(out.decode('utf-8'))
    def gif_conversion(file: IO[bytes], channel_id: str) -> IO[bytes]:
        """Convert Telegram GIF to real GIF, the NT way."""
        gif_file = NamedTemporaryFile(suffix='.gif')
        file.seek(0)

        # Use custom ffprobe command to read from stream
        metadata = ffprobe(file)

        # Set input/output of ffmpeg to stream
        stream = ffmpeg.input("pipe:")
        if channel_id.startswith("blueset.wechat") and metadata.get(
                'width', 0) > 600:
            # Workaround: Compress GIF for slave channel `blueset.wechat`
            # TODO: Move this logic to `blueset.wechat` in the future
            stream = stream.filter("scale", 600, -2)
        # Need to specify file format here as no extension hint presents.
        args = stream.output("pipe:", format="gif").compile()
        file.seek(0)

        # subprocess.Popen would still try to access the file handle instead of
        # using standard IO interface. Not sure if that would work on Windows.
        # Using the most classic buffer and copy via IO interface just to play
        # safe.
        p = subprocess.Popen(args,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        assert p.stdin
        copyfileobj(file, p.stdin)
        p.stdin.close()

        # Raise exception if error occurs, just like ffmpeg-python.
        if p.returncode != 0 and p.stderr:
            err = p.stderr.read().decode()
            print(err, file=sys.stderr)
            raise ffmpeg.Error('ffmpeg', "", err)

        assert p.stdout
        copyfileobj(p.stdout, gif_file)
        file.close()
        gif_file.seek(0)
        return gif_file