python执行ffmpeg

作者: geekerzhou | 来源:发表于2017-04-18 11:39 被阅读421次

python执行ffmpeg命令

  1. 能拿到ffmpeg正常输出
  2. ffmpeg抛出异常时可以拿到异常信息
  3. 返回ffmpeg处理进度

以下代码依赖的pexpect,progressbar需要安装下

import pexpect
import subprocess
import progressbar
import logging

def exec_progress(command, video_duration_seconds):
    """
    执行ffmpeg命令,并根据ffmpeg输出中的"time=xxx"匹配进度, ffmpeg执行失败时抛出FfmpegException
    :param command: ffmpeg命令
    :param video_duration_seconds: 视频总时长
    """
    thread = pexpect.spawn(command)
    cpl = thread.compile_pattern_list([pexpect.EOF,
                                       "frame=.*time=([\d:\.]*)(.*)",
                                       '(.+)'])

    progress = progressbar.ProgressBar(max_value=video_duration_seconds).start()

    output_list = []
    while True:
        i = thread.expect_list(cpl, timeout=None)
        if i == 0:
            progress.finish()
            break
        elif i == 1:
            seconds = duration_to_seconds(thread.match.group(1))
            progress.update(seconds)
        elif i == 2:
            logging.debug(thread.match.group(0))
            output_list.append(thread.match.group(0))
            pass

    thread.close()
    if thread.exitstatus:
        raise FfmpegException(thread.exitstatus, command, "\n".join(output_list))


def exec_output(command):
    """
    执行ffmpeg命令并返回所有输出,如果执行失败,抛出FfmpegException
    :param command: ffmpeg命令
    :return: ffmpeg标准输出
    """
    try:
        process = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
        return process

    except subprocess.CalledProcessError as err:
        raise FfmpegException(err.returncode, err.cmd, err.output)

# 这个方法应该单独抽到别的模块        
def duration_to_seconds(duration):
    time_arr = duration[0:duration.find(".")].split(":")
    if len(time_arr) == 3:
        return int(time_arr[0]) * 3600 + int(time_arr[1]) * 60 + int(time_arr[2])
    logging.error("unrecognized duration %s", duration)
    return 0

class FfmpegException(Exception):
    """
    使用ffmpeg报错时抛出
    """

    def __init__(self, returncode, cmd, output=None):
        self.returncode = returncode
        self.cmd = cmd
        self.output = output

    def __str__(self):
        return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)

简单说明下

  1. exec_progress执行耗时较长需要实时拿到处理进度的场景,如压缩,裁剪等
  2. exec_output执行耗时较短直接拿到输出结果的场景,如获取视频信息等

相关文章

网友评论

  • 3908d6bf439d:是也乎,( ̄▽ ̄)
    正好在折腾类似的任务, 其实:

    单纯的转换任务用 ffmpy 更加简洁
    问题在需要介入的任务,
    比如:

    ffmpeg -i 'udp://127.0.0.1:9009' -vcodec copy output.mp4

    从一个视频流保存为视频时,
    需要从另外的条件人工或是自动停止 ffmpeg
    这时, 就不知道怎么通过 subprocess/expect 发送安全结束的指令给运行中的 ffmpeg 了

    兄弟你是否知道?

    geekerzhou:这种只能用expect了,不过怎么拿到线程是个问题,python新手哈,现搜现写的:smile:

本文标题:python执行ffmpeg

本文链接:https://www.haomeiwen.com/subject/hyyfzttx.html