ffmpeg音頻文件轉換之使用stdin/stdout或BytesIO對象輸入輸出


最近在搞小程序錄音,然后使用百度接口做語音識別。

小程序目前僅支持mp3和aac編碼格式。雖然百度接口提供的m4a格式支持能直接識別小程序的錄音文件,但由於自己還有其他一系列需求(比如直接讀取數據,根據需要進行其他處理等),我還是希望能把m4a文件轉換成pcm編碼的文件。

后端使用ffmpeg命令如下:

# 基於文件操作
ffmpeg -n -i input-1576685164r111.m4a -acodec pcm_s16le -f wav -ac 1 -ar 8000 output-8k-mono.wav

但是如果你用Python從網上下載一個文件,(比如我把文件存在百度對象存儲,BOS),你可能更傾向於使用BytesIO這種內存文件。

這時ffmpeg基於文件的轉換操作需要你建立一個臨時文件,轉換后再將其刪除,這需要你在文件系統上進行操作,效率低而且比較麻煩。

是時候了解ffmpeg基於stdin、stdout的操作了:

# 僅輸入使用pipe
cat input-1576685164r111.m4a | ffmpeg -n -i pipe: -acodec pcm_s16le -f wav -ac 1 -ar 8000 output-8k-mono.wav
# 或全使用pipe
cat input-1576685164r111.m4a | ffmpeg -n -i pipe: -acodec pcm_s16le -f wav -ac 1 -ar 8000 pipe:

使用python和BytesIO怎么操作呢?好了,我寫好了:

#!/usr/bin/env python3
# coding: utf-8
#
# Created by dylanchu on 2019/12/20

from io import BytesIO
from subprocess import Popen, PIPE


def m4a2wav_bytes_io(bytes_io_file):
    bytes_io_file.seek(0)
    content = bytes_io_file.getvalue()
    cmd = ['ffmpeg', '-n', '-i', 'pipe:', '-acodec', 'pcm_s16le', '-f', 'wav', '-ac', '1', '-ar', '8000', 'pipe:']
    p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, bufsize=-1)
    out, _ = p.communicate(input=content)
    p.stdin.close()
    return BytesIO(out) if out.startswith(b'RIFF\xff\xff\xff') else None

_省去的是error message,即ffmpeg其他的信息輸出。

這幾個參考鏈接零零碎碎提供了一些幫助:

https://stackoverflow.com/questions/20321116/can-i-pipe-a-io-bytesio-stream-to-subprocess-popen-in-python
https://stackoverflow.com/questions/49013020/scipy-io-wavfile-read-the-stdout-from-ffmpeg
https://segmentfault.com/a/1190000016652277?utm_source=tag-newest
如果你想前端使用js直接轉換格式,而不是后端轉換:
https://segmentfault.com/a/1190000018200927
https://segmentfault.com/a/1190000018215367


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM