Наложение текста FFmpeg добавляет значения датчиков в видеопоток

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

Каков правильный или «лучший» или «правильный» способ сделать это?

Поскольку это нужно делать в прямом эфире, используйте несколько фильтров drawtext, считывающих отдельные (обновленные) текстовые файлы, с фильтром, настроенным на повторную загрузку этих файлов.
Зачем делать это на сложном пути «Я еще не тестировал этот метод», но вы можете использовать .m3u8файлы, скажем, два изображения, которые заставят ffmpegпостоянно загружать эти изображения, поэтому вы можете изменить/заменить/обновить эти файлы изображений и ffpmegзагрузить их быстро

Ответы (1)

Этот вопрос немного похож на вопрос « Я пытаюсь добавить гитарные табы в музыкальное видео». Знаете ли вы какое-нибудь программное обеспечение для этого?

Во-первых, в каком формате ваши данные, какой протокол используется с ваших датчиков? Я думаю, здесь какое-то программное обеспечение с закрытым исходным кодом и проприетарный протокол для датчиков? Очевидно, вам нужно программное обеспечение, которое может читать этот формат данных/протокол. Если вы создаете собственную систему с микроконтроллерами, постарайтесь найти удобный и открытый протокол для данных. Очень сложно найти открытые протоколы с необходимой функциональностью.

На данный момент, я думаю, вы нашли любой подходящий протокол. Например, JSON с произвольными полями. Теперь попробуйте найти/написать софт, который будет его использовать.

Один из возможных способов: написать веб-приложение, которое будет отображать видеопоток в вашем браузере, подгружать данные с датчиков и отображать забавный оверлей. Затем просто захватите видео с экрана и транслируйте на YouTube или любой другой сервис. Это "грязный" способ, но он сработает.

Другой способ: написать собственный фильтр в ffmpeg. Вы можете использовать ass-renderer для справки, как добавить текст на изображение. Просто добавьте данные о показаниях ваших датчиков, и ваша задача будет выполнена.


Написание быстрых и грязных видеофильтров

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

Для начала вспомним, что изображения состоят из строк и столбцов точек, которые называются пикселями. Каждая точка состоит из 3 или 4 компонентов, обычно красного, зеленого и синего сигналов, иногда присутствует альфа-канал. Следовательно, чтобы изменить 1 точку изображения, нам нужно изменить 3-4 компонента (обычно это 3-4 байта). Итак, чтобы изменить все изображение, нам нужно изменить все строки и столбцы, в каждом из 3-4 элементов и как-то модифицируя их, сохранить обратно. Например, если у нас есть картинка размером 256х192 пикселя в формате RGB24, то в ней будет 49152 пикселя и 147456 цветовых составляющих (байт).

Поэтому нам нужно просто прочитать куски по 147456 байт, как-то модифицировать их и записать обратно! Это все! Никаких сложных библиотек или алгоритмов не требуется! Где взять эти байты? А получить их мы можем с замечательной утилитой ffmpeg и ее не менее прекрасным режимом rawvideo, выхлоп которого мы отдадим на stdout и получим в stdin ваше приложение!

Напишем простейшее приложение, которое немного изменит изображение:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main () {

// allocate variables and buffer

uint8_t *pixels = malloc (147456);
uint8_t *pix;
int q;

while (1) {

// read frame
if (fread (pixels, 1,147456, stdin) <= 0) {break;}

// process image
pix = pixels;
for (q = 0; q <49152; q ++) {
*pix++ = *pix * 2; // multiple red to 2
*pix++ = *pix + 120; // shift green channel
*pix++ = *pix + q / 10; // lines in blue channel
}

// write frame back
fwrite (pixels, 1,147456, stdout);
}

return EXIT_SUCCESS;
}

Да, это все! Конечно, здесь все константы жестко запрограммированы, никогда так не делайте в реальных проектах!

Теперь запустите это и загрузите видео сюда:

ffmpeg -i video.mp4 -s 256x192 -f rawvideo -pix_fmt rgb24 - | ./a.out | ffmpeg -s 256x192 -f rawvideo -pix_fmt rgb24 -i - -y out.mp4

И получаем следующий результат:

введите описание изображения здесь 2.gif

Проанализируем, какие параметры в этой строке участвовали:

ffmpeg -i video.mp4 -s 256x192 -f rawvideo -pix_fmt rgb24 -

Здесь читаем из файла video.mp4, меняем размер картинки на 256x192(если у вас видео уже размером 256х192, то можно этого не делать), далее указываем, что его нужно преобразовать в rgb24цветовое пространство (если его еще нет в нем, то какой ибо может потратить довольно много ресурсов), а результат нам нужен в виде несжатого видео rawvideo, результат мы записываем в формате -, т.е. в формате stdout.

| ./a.out |

А это наше приложение. Вертикальные «трубки» означают, что он будет брать данные из предыдущего приложения и передавать их следующему.

ffmpeg -s 256x192 -f rawvideo -pix_fmt rgb24 -i - -y out.mp4

Здесь мы указываем, что на вход этого ffmpeg будет несжатое видео по rawvideoформату, размеру 256x192и rgb24цветовому пространству. Также может понадобиться указать fps, так как при таком преобразовании он теряется. Вывод будем записывать в out.mp4, и даже если такой файл уже существует, за -yэто отвечает параметр

Вот очень простой пример смены изображения, но вы можете накладывать текст, другие картинки и все что угодно. Конечно, лучше написать полноценное приложение или хотя бы пропатчить уже существующий фильтр до нужного состояния, это будет более правильное решение. Но если вам нужно работающее решение, при этом вы не хотите писать много кода, то это решение для вас.

Я могу использовать JSON или XML для передачи данных датчика... или любой другой формат. У меня проблема только в том, как передать данные в ffmpeg..
нашел здесь пример: s55ma.radioamater.si/2017/08/04/…
Здесь вы должны писать свой текст в файл каждый... кадр! Да, это может сработать, но для меня это довольно грязно. Я не люблю такие файлы tmp и трату процессора. Итак, я предлагаю написать для него простой фильтр.
Протестировали с Java. Сделали простой процесс Thread, который записывает некоторые значения в файл. Когда файл закрывается, я выполняю метод Files.move с StandardCopyOption.ATOMIC_MOVE.. Я знаю, что это грязно, но у меня нет большого опыта в том, как сделать какой-либо плагин (если у вас есть хорошая ссылка (ссылка), пожалуйста, помогите мне .. Другой вариант - использовать студию OBS, но я должен проверить, можно ли выполнить из командной строки (терминала) (без графического интерфейса)..
У вас есть опыт работы с C или C++? Вы можете написать собственный фильтр на каналах, например ffmpeg -i _SOURCE_ -f rawvideo -pix_fmt rgb32 - | ./your_app | ffmpeg -f rawvideo -pix_fmt rgb32 -i - rtmp://broadcast.to.server/. Это будет передавать кадры в ваше приложение через стандартный ввод, затем вы можете рисовать на нем и передавать растровые изображения в стандартный вывод, где новый экземпляр ffmpeg будет кодировать их и сохранять в файл/трансляцию.
Хотелось бы попробовать, но сначала нужно увидеть какой-нибудь пример или блог об этом. (Выполнили какой-то проект также на C/C++ (в прошлом)).. ;)
Сегодня-завтра напишу один
Спасибо! пожалуйста, сообщите мне, чтобы я мог проверить ваш код. На данный момент единственный способ, который у меня есть, - это использовать FFmpeg с drawtext из файла, который обновляется из java. Или использовать студию OBS ( obsproject.com/download ), но нужно проверить, если Я могу запустить его из окна терминала (без графического интерфейса).
Я создал пример на C, он очень простой.