FFMPEG mp3 в mu-law, вывод задержан – Python subprocess с трубами

Вопрос или проблема

Я использую подпроцесс 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 фреймов для генерации аудиовыхода, что приводит к заметной задержке при первом выводе.

Основные причины задержки

  1. Буферизация данных: FFMPEG, как правило, работает с потоками данных, которые необходимо предварительно буферизовать для оптимизации обработки. Однако такая буферизация может приводить к задержкам, когда программа ожидает накопления достаточного количества данных для начала вывода. Это особенно заметно, когда первые несколько фреймов менее эффективны по объёму.

  2. Кодека и форматы: Переход от MP3 к mu-law может требовать времени на декодирование и повторное кодирование. Формат MP3 является сжатым форматом, и его декодирование требует обработки, прежде чем данные будут доступны в нужном формате.

  3. Настройки FFMPEG: Хотя вы пробовали ряд флагов, таких как -fflags +nobuffer, -flags low_delay и других, результаты могут варьироваться в зависимости от конкретной ситуации. Выбор неправильных флагов может привести не только к увеличению задержки, но и к ухудшению качества результата.

Решения и рекомендации

  1. Оптимизация параметров FFMPEG: Попробуйте экспериментировать с различными параметрами для управления буферизацией и задержкой, например:

    • -flush_packets 1 для немедленной отправки пакетов.
    • -max_delay 0 для устранения дополнительных задержек.

    Однако, обращайте внимание на то, что слишком агрессивная настройка может привести к искажению или потере данных.

  2. Параллельная обработка: Рассмотрите возможность использования дополнительного потока, чтобы писать входные данные в FFMPEG, не ожидая ответа. Это может снизить задержки, связанные с вычислениями.

  3. Альтернативные форматы: Если проблема не удается решить стандартными средствами, попробуйте рассмотреть другие аудиоформаты, которые более эффективно обрабатываются FFMPEG, либо использовать другой инструмент, который может соответствовать вашим производственным нагрузкам.

  4. Профилирование кода: Используйте утилиты для профилирования кода. Например, cProfile или line_profiler, чтобы выяснить, на каком этапе возникает задержка. Это может помочь в нахождении узких мест.

  5. Отладка процесса: Используйте инструменты для трассировки, такие как strace, чтобы понять, что происходит на уровне системных вызовов во время исполнения кода. Это может осветить потенциальные времяразделения, которые не очевидны на уровне программы.

Заключение

Задержка в 0.5 секунд при первом выводе может быть связана с несколькими факторами, включая буферизацию, декодирование форматов и настройки FFMPEG. Применяя вышеописанные рекомендации, вы сможете оптимизировать процесс преобразования аудио, тем самым снижающим задержки и улучшая производительность системы в целом. Оставайтесь в курсе обновлений FFMPEG и следите за изменениями в параметрах, которые могут улучшить производительность в будущих версиях.

Оцените материал
Добавить комментарий

Капча загружается...