Python使用subprocess.Popen运行ffmpeg时卡死

本文共有2563个字,关键词:

问题:使用rq队列通过subprocess调用ffmpeg进行视频格式转换,但队列消费,subprocess创建进程后,ffmpeg不运行,未生成转换后文件。但当我不使用队列,直接手动运行脚本使用subprocess调用ffmpeg时却能运行,是什么原因?

解决:需要禁用从标准输入(stdin)读取数据

方法:

cmd = [
        "ffmpeg",
        "-nostdin",         # 不要从标准输入读取
        "-loglevel", "error",  # 只输出错误信息
        "-i", input_file,
        "-c:v", "libx264",  # 使用H.264编码
        "-preset", "ultrafast",  # 使用最快的预设,加快转换速度
        "-c:a", "aac",      # 使用AAC音频编码
        "-strict", "-2",    # 允许使用实验性编码器
        "-y",               # 覆盖输出文件
        output_file
    ]
    print(f'转换命令: {" ".join(cmd)}')
    try:
        print(f'开始执行转换命令,输出文件: {output_file}')
        # 使用Popen以非阻塞方式执行转换命令
        process = subprocess.Popen(
            cmd,
            stdin=subprocess.DEVNULL,  # 重定向标准输入,防止ffmpeg等待交互
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        
        # 等待进程完成,带超时
        try:
            stdout, stderr = process.communicate(timeout=3600)  # 1小时超时
        except subprocess.TimeoutExpired:
            process.kill()
            process.communicate()  # 清理输出
            raise subprocess.TimeoutExpired(cmd, 3600)
        
        if process.returncode != 0:
            print(f'转换命令执行失败,返回码: {process.returncode}, 错误信息: {stderr}')
            raise Exception(f"视频转换失败: {stderr}")
        
        print(f'转换命令执行成功,输出文件大小: {os.path.getsize(output_file) if os.path.exists(output_file) else "文件不存在"}')
        return output_file
    except subprocess.TimeoutExpired:
        # 清理临时文件
        if os.path.exists(output_file):
            os.unlink(output_file)
        print(f'视频转换超时,命令: {" ".join(cmd)}')
        raise Exception("视频转换超时")
    except Exception as e:
        # 清理临时文件
        if os.path.exists(output_file):
            os.unlink(output_file)
        print(f'转换过程发生异常: {str(e)}')
        raise Exception(f"视频转换失败: {str(e)}")

作用详解:

默认情况下,ffmpeg 会监听标准输入(例如键盘输入),以便用户可以:

  • qESC 键提前终止转码;
  • 按其他键(如 +-s 等)进行运行时控制(如调整日志级别、暂停等)。

但在某些使用场景中,这种行为可能带来问题,例如:

  • 脚本或后台任务 中运行 ffmpeg 时,标准输入可能被重定向或不可用;
  • ffmpeg 作为子进程被其他程序调用时,父进程的标准输入可能会意外干扰 ffmpeg
  • 在容器化环境(如 Docker)或 CI/CD 流水线中,stdin 可能未连接,导致 ffmpeg 报错或挂起。

使用 -nostdin 后,ffmpeg完全忽略 stdin,不会尝试从中读取任何字符,从而避免上述问题。

版权声明:本文为作者原创,如需转载须联系作者本人同意,未经作者本人同意不得擅自转载。
添加新评论
暂无评论