Вопрос или проблема
Я использую подпроцесс Python и каналы для преобразования MP3-аудио в mulaw. Основная проблема заключается в том, что я получаю задержку около 0,5 секунды в первом выводе. Входные данные передаются через канал в виде заголовка ID3 размером 45 байт и фреймов MP3 размером 480 байт (каждый – это “кусок” в коде). Похоже, что необходимо подождать около 40+ фреймов/кусков, прежде чем будет сгенерирован какой-либо вывод mulaw. После этого вывод mulaw генерируется практически с каждым входным фреймом/куском.
# Это запускает один процесс ffmpeg и использует каналы для записи и чтения из процесса.
# Текущая проблема в том, что ему нужно много фреймов MP3, прежде чем он вернет звук.
def convert_chunks(self, chunks: Iterable[bytes]) -> Iterable[bytes]:
# Запустить постоянный подпроцесс ffmpeg
ffmpeg_process = subprocess.Popen(
[
'ffmpeg',
# Ни одна из этих опций, похоже, не помогает с задержкой. Одна из них вызывает обрезку первых нескольких секунд.
# '-fflags', '+nobuffer', # Отключить внутреннее буферизирование
# '-flags', 'low_delay', # Включить обработку с низкой задержкой
# '-flush_packets', '1', # Немедленно сбрасывать пакеты
# '-max_delay', '0', # Устранить дополнительную задержку
'-f',
'mp3', # Формат ввода - MP3
'-i',
'pipe:0', # Чтение ввода из stdin
'-f',
'mulaw', # Формат вывода - mu-law
'-ar',
'8000', # Установить частоту дискретизации на 8000 Гц
'-ac',
'1', # Установить аудиоканалы на моно
'pipe:1',
], # Записать вывод в stdout,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
# stderr=subprocess.DEVNULL # Упрощение подавления вывода ffmpeg
)
# это важно, чтобы избежать блокировки чтения из stdout ffmpeg
os.set_blocking(ffmpeg_process.stdout.fileno(), False)
# input('Нажмите Enter, чтобы продолжить...')
closed = False
try:
for chunk in chunks:
ffmpeg_process.stdin.write(chunk)
ffmpeg_process.stdin.flush()
audio = ffmpeg_process.stdout.read()
if audio:
yield audio
# мы действительно хотим заблокироваться на последнем чтении
os.set_blocking(ffmpeg_process.stdout.fileno(), True)
ffmpeg_process.stdin.close()
closed = True
audio = ffmpeg_process.stdout.read()
if audio:
yield audio
except Exception as ex:
print(f'исключение convert_chunks: {ex}')
finally:
if not closed:
ffmpeg_process.stdin.close()
ffmpeg_process.wait()
Очевидно, есть другие моменты, на которые я могу обратить внимание (включая код Python и, возможно, выполнить некоторые трассировки процесса), но, возможно, кто-то знает, является ли это фундаментальным ограничением того, как быстро я могу получить выход mulaw?
Ответ или решение
Вопрос о задержке вывода при использовании FFMPEG для преобразования аудио из формата MP3 в формат mu-law является актуальным для многих разработчиков, работающих с обработкой аудиоданных с использованием Python. Проблема, описанная вами, заключается в том, что FFMPEG требует определённого количества входных MP3 фреймов для генерации аудиовыхода, что приводит к заметной задержке при первом выводе.
Основные причины задержки
-
Буферизация данных: FFMPEG, как правило, работает с потоками данных, которые необходимо предварительно буферизовать для оптимизации обработки. Однако такая буферизация может приводить к задержкам, когда программа ожидает накопления достаточного количества данных для начала вывода. Это особенно заметно, когда первые несколько фреймов менее эффективны по объёму.
-
Кодека и форматы: Переход от MP3 к mu-law может требовать времени на декодирование и повторное кодирование. Формат MP3 является сжатым форматом, и его декодирование требует обработки, прежде чем данные будут доступны в нужном формате.
-
Настройки FFMPEG: Хотя вы пробовали ряд флагов, таких как
-fflags +nobuffer
,-flags low_delay
и других, результаты могут варьироваться в зависимости от конкретной ситуации. Выбор неправильных флагов может привести не только к увеличению задержки, но и к ухудшению качества результата.
Решения и рекомендации
-
Оптимизация параметров FFMPEG: Попробуйте экспериментировать с различными параметрами для управления буферизацией и задержкой, например:
-flush_packets 1
для немедленной отправки пакетов.-max_delay 0
для устранения дополнительных задержек.
Однако, обращайте внимание на то, что слишком агрессивная настройка может привести к искажению или потере данных.
-
Параллельная обработка: Рассмотрите возможность использования дополнительного потока, чтобы писать входные данные в FFMPEG, не ожидая ответа. Это может снизить задержки, связанные с вычислениями.
-
Альтернативные форматы: Если проблема не удается решить стандартными средствами, попробуйте рассмотреть другие аудиоформаты, которые более эффективно обрабатываются FFMPEG, либо использовать другой инструмент, который может соответствовать вашим производственным нагрузкам.
-
Профилирование кода: Используйте утилиты для профилирования кода. Например,
cProfile
илиline_profiler
, чтобы выяснить, на каком этапе возникает задержка. Это может помочь в нахождении узких мест. -
Отладка процесса: Используйте инструменты для трассировки, такие как
strace
, чтобы понять, что происходит на уровне системных вызовов во время исполнения кода. Это может осветить потенциальные времяразделения, которые не очевидны на уровне программы.
Заключение
Задержка в 0.5 секунд при первом выводе может быть связана с несколькими факторами, включая буферизацию, декодирование форматов и настройки FFMPEG. Применяя вышеописанные рекомендации, вы сможете оптимизировать процесс преобразования аудио, тем самым снижающим задержки и улучшая производительность системы в целом. Оставайтесь в курсе обновлений FFMPEG и следите за изменениями в параметрах, которые могут улучшить производительность в будущих версиях.