Python的子进程与管道及大文件

7 投票
2 回答
3073 浏览
提问于 2025-04-15 19:53

我正在尝试使用 Python、ffmpeg 和 oggenc 将任何音频文件转换为 ogg 格式。这个程序几乎可以正常工作。但是对于大文件(我觉得大于大约 6MB),ffmpeg 进程在 pipe_wait 时开始挂起。我不知道它在等待哪个管道。

如果我结束 ffmpeg 进程,oggenc 进程会继续运行,我会得到一个大约 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"

2 个回答

0

要搞清楚谁需要传递数据有点棘手,呃,我是说你应该使用像NetBeans这样的调试工具来帮助你收集更多线索。使用管道可能不是最好的方法,也许用一个临时文件会让事情变得简单一些。

5

你到底是怎么处理这两个管道的 stderr 通道的呢?

编码器和解码器通常会产生很多 stderr 输出,作为状态更新;这些输出会被传送到你的程序中,导致缓冲区变满。也许你应该在 (我觉得没什么用的) .communicate 调用之前,添加一些无用的 ffmpeg.stderr.read() 调用,或者更好的是,完全去掉 stderr=PIPE 的参数。

更新

如果你想要和 >/dev/null 一样的效果,可以这样做:

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

显然,你可以重复使用同一个 nulfp 来处理所有你想忽略的 stderr

撰写回答