Loading

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

posted @ 2019-12-20 02:54  dylanchu  阅读(2946)  评论(0编辑  收藏  举报