Мне успешно удалось использовать ffmpeg в python для преобразования формата некоторых аудиофайлов, например, так:
command = "ffmpeg -i audio.wav -vn -acodec pcm_s16le output.wav"
subprocess.call(command, shell=True)
Однако я хочу сделать это в памяти и избежать сохранения входных и выходных файлов. на диск.
Я нашел следующий код, чтобы сделать такую вещь ( Передача файла, подобного Python, как объект в ffmpeg через подпроцесс ):
command = ['ffmpeg', '-y', '-i', '-', '-f', 'wav', '-']
process = subprocess.Popen(command, stdin=subprocess.PIPE)
wav, errordata = process.communicate(file)
Но я изо всех сил пытаюсь использовать это в моем контексте.
Я получаю файл на сервере как часть запроса multipart / form-data.
@server.route("/api/getText", methods=["POST"])
def api():
if "multipart/form-data" not in request.content_type:
return Response("invalid content type: {}".format(request.content_type))
# check file format
file = request.files['file']
if file:
print('**found file', file.filename)
Теперь у меня есть файл в виде объекта FileStorage (https://tedboy.github.io/flask/generated/generated/werkzeug.FileStorage.html). У этого объекта есть поток, доступ к которому можно получить с помощью метода read. Поэтому я подумал, что смогу использовать это в качестве входных данных для ffmpeg следующим образом:
f = file.read()
command = ['ffmpeg', '-y', '-i', '-', '-f', 'wav', '-']
process = subprocess.Popen(command, stdin=subprocess.PIPE)
wav, errordata = process.communicate(f)
Однако это приводит к следующей ошибке:
AssertionError: Given audio file must be a filename string or a file-like object
Я также попробовал другой подход, который Я нашел в Интернете, используя io.BytesIO, для которого я больше не могу найти источник:
memfile = io.BytesIO() # create file-object
memfile.write(file.read()) # write in file-object
memfile.seek(0) # move to beginning so it will read from beginning
И затем повторяю попытку:
command = ['ffmpeg', '-y', '-i', '-', '-f', 'wav', '-']
process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
wav, errordata = process.communicate(memfile)
Это приводит меня к следующей ошибке :
TypeError: a bytes-like object is required, not '_io.BytesIO'
Кто-нибудь знает, как это сделать?
Обновление
Первое сообщение об ошибке на самом деле не является сообщением об ошибке брошенный ffmpeg. Как правильно указал v25 в своем ответе, первый подход также возвращает объект байтов и также является допустимым решением.
Сообщение об ошибке, выданное библиотекой (speech_recognition) при попытке работать с измененным файлом. В маловероятном случае, если кто-то столкнется с той же проблемой, здесь решение:
Возражения, возвращаемые функцией ffmpeg (переменная wav), должны быть преобразованы в файлоподобный объект, как следует из сообщения об ошибке. Это легко сделать следующим образом:
memfileOutput = io.BytesIO (wav)