带有管道和大文件的 Python 子进程

Posted

技术标签:

【中文标题】带有管道和大文件的 Python 子进程【英文标题】:Python's subprocessing with pipes and large files 【发布时间】:2011-01-22 11:16:21 【问题描述】:

我正在尝试使用 python + ffmpeg + oggenc 将任何音频文件转换为 ogg。该程序几乎可以正常工作。但是对于大文件(我认为 > ~6mb),ffmpeg 进程开始在 pipe_wait 处休眠。我不知道它在等待哪个管道。

如果我终止 ffmpeg 进程,则 oggenc 进程会继续,我会得到一个生成的 ogg 文件,其中包含大约 2:40 的所有声音。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from subprocess import Popen, PIPE
from sys import argv

ffmpeg = Popen([
    "ffmpeg",
    "-i", argv[1],
    "-vcodec", "null",
    "-acodec", "pcm_s16le",
    "-ac", "2",
    "-ab", "44100",
    "-f", "wav",
    "-"
],stdout = PIPE,stderr = PIPE)

oggenc = Popen([
    "oggenc",
    "-", "--raw",
    "-q", "4",
    "-o", argv[2]
],stdin = ffmpeg.stdout,stderr = PIPE)

oggenc.communicate()
ffmpeg.communicate()

编辑:

我想我可以补充一下,这非常有效:

#!/bin/bash

ffmpeg -i "$1" -vcodec null -acodec pcm_s16le -ac 2 -ab 44100 -f wav - | oggenc - --raw -q 4 -o "$2"

【问题讨论】:

检查我的答案更新以获取您的“>/dev/null”等效项。 【参考方案1】:

你对两个管道的stderr 通道究竟做了什么?

编码器/解码器通常会产生大量标准错误输出,作为状态更新;此输出通过管道传输到您的进程,并且缓冲区将变满。也许您应该在(我认为没用的).communicate 调用之前添加一些虚拟的ffmpeg.stderr.read() 调用,或者更好的是,完全删除stderr=PIPE 参数。

更新

对于 >/dev/null 等效项,请执行以下操作:

nulfp = open(os.devnull, "w")
…
… = subprocess.Popen(…, stderr=nulfp.fileno())

显然,您可以对所有要忽略的stderrs 重复使用相同的nulfp

【讨论】:

我使用 stderr 管道的原因是因为我不希望它向终端写入任何内容。我尝试在 ffmpeg 上使用“-loglevel quiet”来查看它是否有效,但所有内容都直接停止了。首先,我认为是 .communicate 终止了程序,但事实证明:ffmpeg 不喜欢“-loglevel quiet”,所以它自行终止了。当我删除 stderr=PIPE 参数时一切正常,感谢您的帮助!现在我只需要弄清楚如何不显示 sdterr 数据... 只是做了同样的事情,但没有 .fileno(),使用它有什么优点/缺点吗? 都是一样的,没有优缺点。当你给它一个文件对象时,子进程模块将在内部获取.fileno() 感谢您的提示!供将来参考:仍然需要做null = open(os.devnull,'w')【参考方案2】:

很难看出谁需要通过管道,呃我的意思是你应该使用像 NetBeans 中的调试器来帮助收集更多线索。管道可能不是最好的方法,也许使用临时文件会简化事情。

【讨论】:

嗯,临时文件是我的第一个想法,但它会花费几乎两倍的时间,首先 ffmpeg 将文件转换为原始音频,然后 oggenc 将其转换为 ogg/vorbis。使用管道,他们可以同时进行,从而节省时间。 ……管道将更好地利用多核(如果可用)。

以上是关于带有管道和大文件的 Python 子进程的主要内容,如果未能解决你的问题,请参考以下文章

带有管道的子进程调用[重复]

使用带有 python3 的子进程模块管道两个命令时遇到问题

可以python子进程Popen接受多个stdin流吗?

启动包含管道命令的子进程时找不到文件错误

如何使用带有字节而不是文件的python子进程

子进程打开文件和管道awk命令[重复]