Node.js — буферизация данных в Ffmpeg

Я использовал Node.js и Ffmpeg для создания анимации. Поскольку я пытался избежать сторонних парсеров avi/mp4, я решил вывести анимацию в виде необработанного файла данных rgb24, а затем использовать какую-то программу для преобразования ее в файл mp4.

Я обнаружил, что Ffmpeg является бесплатным и открытым исходным кодом, который может сделать именно это. Итак, я создал приложение Node.js, которое выделяет Buffer размера 1920 x 1080 x 3 (ширина, умноженная на высоту, умноженная на количество байтов на пиксель), затем я создал библиотеку контекста рендеринга и, наконец, анимировал кадр за кадром и последовательно сохранял каждый кадр в двоичный файл (с использованием модуля fs).

Затем я вызвал Ffmpeg, чтобы преобразовать его в файл mp4, и он работает очень хорошо. Анимации довольно легко сделать, и Ffmpeg делает свою работу правильно.

Однако единственная проблема заключается в том, что он очень медленный и занимает место на жестком диске. Я хочу создавать очень длинные анимации (более часа). Окончательный файл mp4 относительно небольшой, но необработанный видеофайл очень большой. Около девяноста процентов каждого кадра составляют черные пиксели, поэтому Ffmpeg очень хорошо сжимает его, но необработанный файл не может быть сжат и занимает иногда более 100 гигабайт. Кроме того, существует очень ненужная двойная обработка одних и тех же данных. Сначала я обрабатываю его в Node.js, чтобы сохранить данные в файл, а затем Ffmpeg читает его, чтобы преобразовать в mp4. Есть много ненужной работы.

Итак, я ищу способ (и я почти уверен, что это возможно, но я еще не нашел способа сделать это) для вывода необработанных видеоданных (по одному кадру за раз) в процесс Ffmpeg (без сохранение чего-либо на жесткий диск).

Моя цель - сделать следующее:

  1. Откройте процесс Ffmpeg
  2. Рендеринг кадра в Node.js
  3. Вывод необработанного потока байтов в Ffmpeg
  4. Подождите, пока Ffmpeg закодирует его и добавит в файл mp4.
  5. Пусть Ffmpeg подождет, пока мой процесс Node.js отобразит следующий кадр

Есть ли способ достичь этого? Я действительно не вижу причин публиковать код, потому что мой текущий код не имеет ничего общего с вопросом, который я здесь задаю. Я не борюсь с синтаксическими ошибками или проблемами реализации. Нет, вместо этого я просто не знаю, какие параметры передать процессу Ffmpeg, чтобы добиться того, что я уже объяснил.

Я искал в документации, чтобы узнать, какие параметры мне нужно передать процессу Ffmpeg, чтобы он мог читать необработанные данные из стандартного ввода, а не из файла, а также ждать, пока мой процесс Node.js отобразит следующий кадр (чтобы отключить время limit), так как рендеринг кадра может занять более 24 часов. Следовательно, процесс Ffmpeg должен ожидать неограниченное время. Однако я не нашел ничего об этом в документации.

Я знаю, как писать в стандартный ввод из Node.js и подобных технических вещей, так что не нужно объяснять. Единственный вопрос(ы) здесь:

  1. Какие параметры передавать в Ffmpeg?
  2. Нужно ли мне создавать процесс Ffmpeg (используя child_process) с некоторыми специальными параметрами?

Заранее спасибо. Пожалуйста, успокойтесь, это мой первый вопрос! :)


person Community    schedule 06.09.2017    source источник
comment
Это будет в духе ffmpeg -f rawvideo -s 1920x1080 -framerate R -pixel_format rgb24 -i - output.mp4   -  person Gyan    schedule 06.09.2017
comment
@Мульвия. Итак, -i - это ответ? Просто интересно, почему я не нашел его в документах. Спасибо   -  person    schedule 06.09.2017
comment
@эстус. Тебе тоже спасибо.   -  person    schedule 06.09.2017
comment
Как сказано выше, это ffmpeg ... -i - ... для чтения со стандартного ввода. Да, вам нужно создать процесс, по умолчанию child_process использует конвейер для потоков, например let ffmpegProcess = child_process.spawn(...); ffmpegProcess.stdin(...).pipe(...). Если у вас есть проблемы с этим подходом, я бы предложил предоставить stackoverflow.com/help/mcve (репозиторий или что-то в этом роде), это увеличивает шансы получить правильный ответ.   -  person Estus Flask    schedule 06.09.2017
comment
Надеюсь это поможет. Сейчас невозможно проверить, работает ли потоковая передача для ffmpeg в Node.   -  person Estus Flask    schedule 06.09.2017
comment
@эстус. Спасибо еще раз. Я ответил на свой вопрос, а также предоставил пример. Если вам нужна репутация, вы также можете опубликовать ответ.   -  person    schedule 06.09.2017


Ответы (1)


Как предложили @Mulvya и @estus, правильный параметр — -i - (чтобы включить ввод со стандартного ввода):

'use strict';

var cp = require('child_process');

var proc = cp.spawn('ffmpeg', [
  '-hide_banner',
  '-f', 'rawvideo',
  '-pix_fmt', 'rgb24',
  '-s', '2x2',
  '-i', '-',
  '1.png'
]);

proc.stdin.write(Buffer.from([
  255, 0, 0,
  0, 255, 0,
  0, 255, 255,
  255, 0, 255
]));

proc.stdin.end();

proc.stderr.pipe(process.stdout);

Он создает следующее изображение:
result
Он работает и для анимации.

Спасибо, ребята, за помощь!

person Community    schedule 06.09.2017