Видеофайлы и ZoneMinder

Замечательная штука, этот ZoneMinder (описание на русском можно почитать тут: www.openkazan.info/node/1360) С помощью одной-двух обычных вебкамер (а так же аналоговых с платой видеозахвата и IP-камер) позволяет организовать видеонаблюдение (с детектированием движения, зонами охраны, просмотром реал-тайм через интернет через любой браузер, даже через iPhone можно, проверено). Вот только когда дело доходит до просмотра всех событий за день-неделю-месяц становится ну очень утомительно: каждое событие (т.е. зарегистрированное движение) записывается отдельно и просматривать его надо отдельно. Видео тоже можно создать стандартными средствами, но опять же по одному для каждого события. А у меня, например, с каждой камеры их по 1000-2000 штук в день. Напряжно очень.
Впрочем, проблема легко решилась bash-скриптом и кроном.

В интернетах не сразу, но нагуглился скрипт, который выполнял поиск по дате изменения файлов, работающий в 3 этапа:

  1. Поиск и копирование всех файлов изменившихся с %date%,
  2. Переименование картинок нужный формат
  3. Кодирование видео-файла на основе найденных картинок.

Ссылку я к сожалению уже потерял…
Слабыми и неуклюжими местами показалась отсутствие гибкости в выборе временных диапазонов, точнее ограничения в них команды find. Ну и ненужное копированиие и переименование в два этапа.
Да и зачем пользоваться find, если пути известны, а данные о файлах с картинками лежат в базе MySQL, а она очень приятно (вкупе с awk) работает в консоли.
Короче родилось вот такое решение:
~/bin/mkvideo:

#!/bin/bash
# камера по-умолчанию, если запущен без параметров
cam_default=Office1
#дата по-умолчанию - вчера
workdate_default=`date -d yesterday`
workdate=$1
cam=$2
if [ "Z"$1 = "Z" ]; then
       workdate=$workdate_default
fi
if [ "Z"$2 = "Z" ]; then
       cam=$cam_default
fi
# путь до ZM
inpath=/var/cache/zoneminder/events/${cam}
# Где хранить картинки (временно)
jpgpath=~/jpg
# Куда складывать видеофайлы
videopath=~/video
mydate=`date -d "${workdate}" +%Y-%m-%d`
filename=${cam}-${mydate}.avi
zmdatabase=zm
echo workdate is ${mydate}
mkdir -p ${jpgpath} 2>/dev/null
mkdir -p ${videopath} 2>/dev/null
# Выборка нужных файлов из базы данных
# по вкусу (если есть пароль) подкрутить парамерты mysql -u user --password=password
files=`mysql ${zmdatabase} -s -e \
"select eventid,right(concat('00',frameid),3) from Frames where date(timestamp)='${mydate}' order by eventid,frameid" \ 
| awk '{print($1"/"$2"-capture.jpg");}'`
i=0
for f in ${files}
do
    # проверка на размер файла, ZM иногда пишет картинки с нулевым размером
    # а ffmpeg потом спотыкается
    if [ `ls -l ${inpath}/${f} | awk '{print $5}'` -gt 0 ]; then
       i=$((i+1))
       p=$(printf %.8d $i)
       cp -p  ${inpath}/$f ${jpgpath}/$p.jpg
    fi
done
rm ${videopath}/${filename} 2>/dev/null
# Кодируем видео из картинок
ffmpeg -r 100 -an -i ${jpgpath}/%08d.jpg -vcodec h263p -b 1500k ${videopath}/${filename}
#Удаляем старые файлы
rm ${jpgpath}/*.jpg 2>/dev/null

Качество сжатия и фпс ессно подкрутить по вкусу. Запускать с параметрами

$ ./mkvideo date cam

дата может быть today, yesterday, 2010-12-01
название камеры с учетом регистра как задано в ZoneMinder
Если камера одна, прописать ей по-умолчанию в начале скрипта и в крон пихать без параметров сразу после 00:00 по местному времени, будет создаваться видеофайл всех событий за вчерашний день.
Путем изменения запроса к MySQL можно легко собирать видео за определенный час, неделю, месяц (это правда долго)