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

tho*_*len 6 python subprocess ffmpeg

我可以ffmpeg通过这样做将 mp4 转换为 wav,使用,:

ffmpeg -vn test.wav  -i test.mp4 
Run Code Online (Sandbox Code Playgroud)

subprocess只要我的输入和输出是文件路径,我也可以使用它来做同样的事情。

但是如果我想ffmpeg直接在字节或“类文件”对象上使用io.BytesIO()怎么办?

这是一个尝试:

ffmpeg -vn test.wav  -i test.mp4 
Run Code Online (Sandbox Code Playgroud)

给我:

---------------------------------------------------------------------------
UnsupportedOperation                      Traceback (most recent call last)
<ipython-input-84-0ddce839ebc9> in <module>
      5 with open('test.mp4', 'rb') as stream:
      6     command = ['ffmpeg', '-i']
----> 7     proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=b)
...
   1486                 # Assuming file-like object
-> 1487                 c2pwrite = stdout.fileno()
   1488 
   1489             if stderr is None:

UnsupportedOperation: fileno
Run Code Online (Sandbox Code Playgroud)

当然,我可以使用临时文件来收集我的字节,但我希望能够避免写入磁盘(因为这一步只是转换管道中的一个链接)。

小智 7

基于@thorwhalen 的回答,这是从字节到字节的工作方式。您可能错过了@thorwhalen,这是与进程交互时发送和获取数据的实际管道到管道方式。发送字节时,标准输入应该在进程可以从中读取之前关闭。

def from_bytes_to_bytes(
        input_bytes: bytes,
        action: str = "-f wav -acodec pcm_s16le -ac 1 -ar 44100")-> bytes or None:
    command = f"ffmpeg -y -i /dev/stdin -f nut {action} -"
    ffmpeg_cmd = subprocess.Popen(
        shlex.split(command),
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        shell=False
    )
    b = b''
    # write bytes to processe's stdin and close the pipe to pass
    # data to piped process
    ffmpeg_cmd.stdin.write(input_bytes)
    ffmpeg_cmd.stdin.close()
    while True:
        output = ffmpeg_cmd.stdout.read()
        if len(output) > 0:
            b += output
        else:
            error_msg = ffmpeg_cmd.poll()
            if error_msg is not None:
                break
    return b
Run Code Online (Sandbox Code Playgroud)