Появилась необходимость в записи рабочего стола, ip-камеры и графика скорости на портах в реальном времени, единственным источником звука будет камера. На помощь пришел ffmpeg, а также несколько инструментов таких как snmpwalk, gnuplot. Все это буду делать на Ubuntu 20.04. Будьте внимательны в 16 Ubuntu ffmpeg старый, его нужно обновить вручную:
sudo add-apt-repository ppa:jonathonf/ffmpeg-4
sudo apt-get update
sudo apt-get install ffmpeg
Изначально хотелось сделать запуск записи при включении компьютера, но ffmpeg отказывался запускаться, выдавая ошибку (тикет), поэтому я решил сделать запуск через ярлык.
Цель записи выявить ошибку при взаимодействии пользователя с каким-то сложным ПО, где необходимо проследить как именно выполняется алгоритм работы.
Хочу заметить, что запись будет происходить внутри локальной сети, камера и компьютер подключены к маршрутизатору напрямую.
Камера
Используется IP-камера Beward B12CR с прошивкой 3.1.0.1.5.18.166.
Для записи будет задействован альтернативный поток со следующими настройками:
График
Для создания графика будем обращаться к этой инструкции. У нас должны появиться следующие скрипты – getDataFromMikrotik.sh, runGnuplot.sh, createGraph.p. Все скрипты будут лежать в папке /home/user/record/
Папка для записи
Для создания папки я решил выделить код в отдельный скрипт createPath.sh:
#!/bin/bash
user=test
rm -f /home/$user/record/path
mkdir /home/$user/$(date +%d-%m-%y)-record/
mkdir /home/$user/$(date +%d-%m-%y)-record/$(date +%H-%M)
echo /home/$user/$(date +%d-%m-%y)-record/$(date +%H-%M) >> /home/$user/record/path
user=test – имя пользователя в системе Ubuntu. Скрипт проверяет наличие файла path, если он есть, то удаляет его. Затем создается папка с именем в формате “28-06-2023-record”, а внутри этой папки создается другая папка с именем в формате “11-59”. Получившийся путь /home/test/28-06-2023-record/11-59 записывает в файл /home/test/record/path. Этот путь будут использовать другие скрипты, чтобы класть туда свои новые файлы.
Запись
Для начала установим необходимые пакеты:
sudo apt install ffmpeg snmp gnuplot
Создадим скрипт startRec.sh, который будет начинать запись:
#!/bin/bash
started=$(ps aux | grep '[g]etDataFromMikrotik.sh' | awk '{print $2}')
if [[ -n $started ]]
then
echo "alredy started"
exit
fi
echo "starting"
bash /home/user/record/createPath.sh >> /home/user/record/createPath.log
path=$(cat /home/user/record/path)
width=$(xrandr | grep primary | cut -f 4 -d " " | cut -f 1 -d "+" | cut -f 1 -d "x")
height=$(xrandr | grep primary | cut -f 4 -d " " | cut -f 1 -d "+" | cut -f 2 -d "x")
if [ $(($height-360)) -ge 480 ]
then
heightGraph=480
else
heightGraph=$(($height-360))
fi
bash /home/user/record/getDataFromMikrotik.sh >> $path/getDataFromMikrotik.log 2>&1 < /dev/null &
bash /home/user/record/runGnuplot.sh >> $path/runGnuplot.log 2>&1 < /dev/null &
ffmpeg \
-video_size $width\x$height-f x11grab -r 5 -i :0.0 \
-rtsp_transport tcp -i "rtsp://admin:password@192.168.1.199:554/av0_1" \
-f image2 -loop 1 -i $path/graph.png \
-filter_complex "[0:v]pad=iw+640:ih[desk]; \
[desk][1:v]overlay=$width:0[deskcam]; \
[2:v]scale=640:$heightGraph[graph]; \
[deskcam][graph]overlay=$width:360[all]; \
[all]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf:text='%{pts\:gmtime\:$(($(date +%s)+18000))\:%d-%m-%Y %T}':fontcolor=white@0.8:x=7:y=7:borderw=2:bordercolor=black[v]" \
-map "[v]" \
-map 1:a \
-c:v libx264 -pix_fmt yuv420p -crf 40 -preset ultrafast \
-c:a copy \
$path/merged.mkv >> $path/merged.log 2>&1 < /dev/null &
Сначала мы проверяем запущена ли уже запись, если да, то показываем "already started", если нет, то показываем "starting" и запускаем запись. Проверка осуществляется с помощью ps aux, он проверяет запущен ли процесс getDataFromMikrotik.sh.
Затем создается путь с помощью скрипта createPath.sh, логи которого записываются в файл с таким же именем, но с расширением log. Переменная path присваивает созданный путь.
После этого узнаем разрешение экрана командой xrandr, фильтруем вывод, разбираем его на ширину и высоту.
Размер видео с камеры 640×360, размер изображения графика 640×480. При высоте экрана 1080 пикселей видео с камеры и график полностью помещаются при своих стандартных высотах, но если размер экрана будет, например, 720 пикселей, то график обрежется снизу, так как 360+480=840, 840-720=120 пикселей обрезалось. Поэтому мы проверяем сколько осталось пикселей по высоте, если осталось меньше 480, тогда heightGraph будет остаток по высоте (сожмем график по высоте), если больше 480, то heightGraph будет всегда 480, чтобы не растягивать. Для меня важно, чтобы помещалось видео с камеры.
Вот так будет выглядеть график при разрешении 1280×720:
Далее запускается скрипт getDataFromMikrotik.sh, он берет данные с маршрутизатора и записывает их в data.txt, попутно пишется одноименный лог файл.
Следом выполняется runGnuplot.sh, который запускает gnuplot с файлом createGraph.p внутри. Все это с задержкой в 1 секунду. Тоже пишется лог файл. Есть погрешности в задержке, для меня не критично.
И, наконец, ffmpeg:
-video_size $width\x$height-f x11grab -r 5 -i :0.0 \ – с помощью x11grab делаем запись рабочего стола с входящей частотой 5 fps.
-rtsp_transport tcp -i “rtsp://admin:password@192.168.1.199:554/av0_1” -r 5 \ – запись с камеры. admin – имя пользователя, password – пароль, 192.168.1.199:554 – ip-адрес камеры и порт (порт должен быть проброшен), av0_1 – альтернативный поток (av0_0 – основной поток).
-f image2 -loop 1 -i $path/graph.png \ – берем график и по мере обновления добавляем в общее видео.
-filter_complex “[0:v]pad=iw+640:ih[desk]; \ – создает на видео с рабочим столом черный фон (desk) с шириной, увеличенной на 640 пикселей, и сохраняет его размеры.
[desk][1:v]overlay=$width:0[deskcam]; \ – накладывает видео поток с индексом 1 (1:v – видео с камеры) на черный фон рабочего стола (desk), смещая его на $width пикселей вправо. Результат сохраняется в deskcam.
[2:v]scale=640:$heightGraph[graph]; \ – изменяет размер видео потока с индексом 2 (2:v – график) до ширины 640 пикселей и высоты $heightGraph пикселей. Результат сохраняется в graph.
[deskcam][graph]overlay=$width:360[all]; \ – накладывает видео поток graph на deskcam, смещая его на $width пикселей вправо и на 360 пикселей вниз (высота видео с камеры). Результат сохраняется в all.
[all]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf:text=’%{pts\:gmtime\:$(($(date +%s)+18000))\:%d-%m-%Y %T}’:fontcolor=white@0.8:x=7:y=7:borderw=2:bordercolor=black[v]” \ – добавляет текст на видео поток all. Текст содержит текущую дату и время в формате “день-месяц-год час:минута:секунда”, смещенное на 5 часов вперед. Текст отображается белым цветом с прозрачностью 0.8, с толщиной обводки 2 пикселя и черной обводкой. Результат сохраняется в v.
-map “[v]” \ – выбирает результат из filter_complex в качестве видео потока для кодирования.
-map 1:a \ – выбирает аудио поток с индексом 1 (1:a) для кодирования.
-c:v libx264 -pix_fmt yuv420p -crf 40 -preset ultrafast \ – устанавливает кодек видео (libx264), формат пикселей (yuv420p), качество видео (crf 40, где более высокое значение означает более низкое качество), и скорость кодирования (ultrafast, самая быстрая скорость).
-c:a copy \ – копирует аудио поток без изменений.
$path/merged.mkv – указывает путь и имя файла, в который будет сохранен результат.
>> $path/merged.log 2>&1 < /dev/null & – перенаправляет вывод команды в файл merged.log, игнорирует ввод данных (/dev/null), и запускает процесс в фоновом режиме (&).
После запуска записи структура папок будет выглядеть так:
Остановка записи
Создадим скрипт stopRec.sh:
#!/bin/bash
kill $(ps aux | grep '[g]etDataFromMikrotik.sh' | awk '{print $2}')
kill $(ps aux | grep '[f]fmpeg -video_size' | awk '{print $2}')
kill $(ps aux | grep '[r]unGnuplot.sh' | awk '{print $2}')
Итог
Преимущество скрипта записи startRec.sh в том, что можно выключить компьютер, убить процесс, зависнуть и т.д, но запись будет всегда сохранена, так как видео сразу пишется на диск.