Как преобразовать pydub AudioSegment для потоковой передачи без промежуточного аудиофайла?

Я работаю над программным обеспечением для потоковой передачи звука из источника через HTTP с использованием веб-сервиса Flask. Я могу получить звуковые кадры через sounddevice и направить их в браузер через маршрут Flask с yield и правильным MIME-типом, но необработанный аудиоформат довольно громоздкий для удаленной потоковой передачи и не самый лучший, когда речь идет о совместимости с клиентом.

Я бы хотел использовать pydub для преобразования необработанных аудиокадров в такой формат, как mp3 или ogg, но мне это непонятно ни из документацию или из исходный код как добиться преобразования формата "на лету" без сброса вывода в файл через .export().

Скелет моего кода пока выглядит примерно так:

### audio.py

import queue
import sounddevice as sd
from pydub.audio_segment import AudioSegment


def input_stream(device, sample_width=2, sample_rate=44100,
        channels=1, latency=0, blocksize=2048, timeout=5.0):
    audio_queue = queue.Queue()

    def audio_callback(indata, frames, time_duration, status):
        audio = AudioSegment(indata, sample_width=sample_width,
                channels=channels, frame_rate=sample_rate)

        # Some pydub magic should happen here to convert the raw frame to mp3/ogg

        audio_queue.put(audio.raw_data)


    with sd.InputStream(samplerate=sample_rate, device=device,
                        channels=channels, callback=audio_callback,
                        latency=latency, blocksize=blocksize):
        while not recording_terminated():
            yield audio_queue.get(block=True, timeout=timeout)


### web.py

from flask import route, request, Response

from audio import input_stream


@route('/sound/stream', methods=['GET'])
def get_sound_feed():
    device = request.args.get('device')
    return Response(input_stream(device), mimetype='audio/ogg')

Как преобразовать необработанный объект AudioSegment в audio_callback в сжатый mp3/ogg, подходящий для потоковой передачи в Интернете? Я знаю, что можно создать сегмент из mp3 через AudioSegment.from_file или выгрузить его в mp3-файл через .export(), но на самом деле это не вариант, поскольку такие операции ввода-вывода приведут к существенной задержке. Я думаю, что может быть теоретически возможно взломать .export(), чтобы заставить его выгружаться в сокет или файловый дескриптор fifo, но мне это кажется немного хакерским обходным путем, плюс я не уверен, что это достаточно, чтобы файловый дескриптор предоставил метод .write(), иначе он сломается из-за того, что требуются другие методы (например, seek).


person BlackLight    schedule 21.07.2019    source источник
comment
Я столкнулся с этим вопросом в 2014 году: stackoverflow.com/questions/25469161/. Последний комментарий, кажется, подтверждает мое подозрение, что экспорт «на лету» (не в файл) невозможен в pydub. Я не уверен, был ли достигнут какой-либо прогресс за это время или какой-то пользователь уже сделал форк для его поддержки. Если это не так, я могу попробовать и отправить PR в pydub.   -  person BlackLight    schedule 23.07.2019
comment
вы нашли как это сделать? Я пытаюсь сохранить файл в BytesIO, чтобы удалить аспект сохранения.   -  person    schedule 23.11.2019


Ответы (1)


Я не знаю, можете ли вы запретить pydub сохранять файл на диск, но вы можете просто получить файл в конце преобразования, не открывая его повторно. На самом деле функция .export() возвращает файловый объект в конце выполнения.

convert_file = audio_file.export(format="flac")

Я сделал это, и я мог обработать файл convert_file, как если бы я использовал функцию open(). (Я конвертирую во flac для своего собственного проекта, но вы можете сделать любой формат)
Я обнаружил, что если вы не укажете имя файла, функция .export() даже не запишет файл на диск без каких-либо ошибок.
Я надеюсь, что вы можете найти обходной путь для вашей проблемы.

person Noomaok    schedule 02.08.2019