簡體   English   中英

Pipe 字節從子進程到 Python 中的類似文件的 object

[英]Pipe bytes from subprocess to file-like object in Python

我想在 Python 中完成以下操作。 I want to call a subprocess ( ffmpeg in this case, using the ffmpy3 wrapper) and directly pipe the process' output on to a file-like object that can be consumed by another function's open() call. 由於音頻和視頻數據可能變得非常大,我明確不想將進程的 output 作為一個整體加載到 memory 中,而只是以緩沖的方式“流式傳輸”它。 這是一些示例代碼。

async def convert_and_process(file: FileIO):
    ff = ffmpy3.FFmpeg(
        inputs={str(file.name): None},
        outputs={'pipe:1': '-y -ac 1 -ar 16000 -acodec pcm_s16le -f wav'}
    )

    stdout: StreamReader = (await ff.run_async(stdout=subprocess.PIPE)).stdout

    with wave.open(help_needed, 'rb') as wf:
        # do stuff with wave file
        pass

run_async的代碼,它只是asyncio.create_subprocess_exec()的簡單包裝。

我的問題基本上只是將run_async()返回的StreamReader轉換為可以被wave.open()使用的類似文件的 object 。 此外,這種方法實際上不會像Popen.wait()Popen.communicate()那樣將所有 output 加載到 memory 中嗎?

我在想os.pipe()可能有用,但我不確定如何。

如果您的示例是您最終目標的真實表示(以塊為單位讀取音頻樣本),那么您只需使用 FFmpeg 及其subprocess.Popen.stdout就可以更輕松地完成它。 如果除了使用wave庫來讀取 memory-mapped.wav 文件之外還有更多內容,請忽略此答案或澄清。

先是一個不要臉的插件,如果你願意嘗試別的庫,我的ffmpegio可以做你想做的。 這是一個例子:

import ffmpegio

#audio stream reader
with ffmpegio.open(file,'ra', blocksize=1024, ac=1, ar=16000, 
                   sample_fmt='s16le') as f:
    for block in f: # block: [1024xchannels] ndarray
        do_your_thing(block)

blocksize參數設置一次檢索的樣本數(在本例中為 1024 個音頻樣本)。

這個庫還很年輕,如果您有任何問題,請在其 GitHub 問題板上報告。

Second, if you prefer to implement it yourself, it's actually fairly straight forward if you know the FFmpeg output stream formats AND you need only one stream (multiple streams could also be done easily under non-Windows, I think). 對於上面的示例,請嘗試以下操作:

ff = ffmpy3.FFmpeg(
        inputs={str(file.name): None},
        outputs={'pipe:1': '-y -ac 1 -ar 16000 -acodec pcm_s16le -f s16le'}
    )
stdout = (await ff.run_async(stdout=subprocess.PIPE)).stdout

nsamples = 1024 # read 1024 samples
itemsize = 2 # bytes, int16x1channel

while True:
    try:
        b = stdout.read(nsamples*itemsize)
        # you may need to check for len(b)=0 as well, not sure atm
    except BrokenPipeError:
        break
    x = np.frombuffer(b, nsamples, np.int16)
    # do stuff with audio samples in x

請注意,我將-f wav更改為-f s16le ,因此只有原始樣本被發送到stdout 然后stdout.read(n)基本上與wave.readframes(n)相同,除了它們的n的含義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM