Skip to content

Написал Бутылкус в рубрику Без рубрики

Преамбула. Как я докатился до FFmpeg+v4l2+libx264

Этот пост является частью ролика, посвящённому захвату видео с помощью веб-камеры, подключенной к Raspberry Pi (v. 2 в моём случае), посредством вызова из Python 3.4 консольной утилиты FFmpeg в связке с кодеком libx264 (он же h264).

Сначала я пытался подкружить Python 3 и OpenCV (SimpleCV), тем более уже два года как существуют официальные вроде как уже связанные версии, но в итоге выяснил, что это чрезмерно раздутое решение и для моей цели это примерно как построить верфь для того, чтобы построить лодку, чтобы переплыть небольшое озерцо, которое можно обойти за 10 минут. Я свято верю и проповедую принцип KISS — Keep It Simple, Stupid! (Сделай это проще, идиот!). Если есть возможность сделать что-то одной командой, то это надлежит сделать именно так и не пытаться строить из себя дохрена крутого программиста и выстраивать код, тешащий ЧСВ, но при этом совершенно бесполезно раздутый с точки зрения ресурсов и без того не супербыстрой Raspberry Pi. Ну и само собой, для решения такой простой задачи, как просто записать в файл картинку с вебкамеры городить десятки строк кода, снижая читабельность и прозрачность работы Татьяны… Ну, вы поняли.

Поэтому я решил поступить как белый человек и воспользоваться инструментами, которые давно зарекомендовали себя как надёжные и простые, не изобретая велосипедов и не клепая костыли на костыли для костылей безногого и безрукого слепоглухонемошизопарализованного двоечника вечерней сельской школы.

Ход моих мыслей можно проследить по такой вот цепочке: задача — варианты решения — время решения — длина кода — применимость к ситуации.

Итак, у нас есть вебкамера. Нам необходимо всего лишь взять с неё видеопоток и, эффективно его пожав, сохранить в файл. Как это сделать? При этом у нас есть скрипт на Python 3.4+ и городить в него ещё один раздутый модуль или даже функцию уже не стоит, поскольку всё уже сделано на стадии проектирования и нам нужно лишь вбить нужную команду

Разумеется, Google предлагает исключительно связку Python+SimpleCV, но из-за описанной выше проблемы с исходниками и pip3 этот вариант сразу ушёл лесом. Ну как сразу… С точки зрения поиска эффективного решения для «умного дома» несколько часов виртуального секса с поиском и попытками заставить это хоть как-то работать — сущие пустяки, особенно для единственного и главного разработчика проекта =)

Поэтому я пошёл по пути наименьшего сопротивления. В мире opensource существует важный и нужный принцип свободы. Это значит, что я волен использовать произвольно выбранные инструменты по произвольному назначению, если сочту это приемлемым для себя. Опаньки, а это уже закрывает последний пункт последовательности решения (применимость)!

Для захвата видео, что вполне очевидно, я решил использовать самую известную, наверное, технологию/библиотеку/приложение — v4l2 (Video for Linux 2). Для накатывания в систему достаточно набрать в консоли Распберри следующее:

sudo apt-get install v4l2ucp v4l-utils

Это установит все нужные пакеты и автоматически подтянет зависимости. Соглашайтесь на установку.

Итак, теперь мы можем работать с потоком… Но чем? Опять городить костыли в код? Нет уж, увольте, тем более давным-давно существует и процветает замечательная утилита FFmpeg, которая позволяет прямо в консоли сотворить больше, чем большинство youtube-блоггеров «профессионально монтируют» в какой-нибудь дохрена платной программе типа Adobe Premiere.

Но вот беда, в Raspbian нет готового пакета! Я не буду вдаваться в подробности, почему такое случилось, лишь намекну — из-за анального давления на всё сообщество Raspberry в плане патентованых кодеков каждый вынужден самостоятельно лепить для себя собственные версии подобных утилит. Даже кодеков для mp3 в оригинальной установке вы не обнаружите. Не говоря уже о всяких видеоформатах. Впрочем, всё решается элементарно — мы соберём нужные нам пакеты самостоятельно.

Поскольку на данный момент стандартом для видеофайлов является libx264 (пока ещё не появилось доступных аппаратных декодеров и энкодеров 265), будем использовать именно его. Опять же, не вдаваясь в подробности и тонкости намекну — секунда ВИДЕО в этом формате занимает меньший объём, чем единственная чудовищно сжатая JPEG картинка сопоставимого размера (1920х1080, к примеру). Как? А так. За волшебством идём курить гугл и механику работы кодека. Матан и опенсурс, господа. Опенсурс и матан. За деньги мозг не купишь, детишки! ;)

Так, стоп… Если мы используем матан, нам нужны большие вычислительные мощности. А это значит, что готовый пакет нам тоже никто не даст, потому что мы работаем в сильно ограниченном по математическим возможностям ARM!

Таким образом, нам нужно самостоятельно собрать из исходных кодов libx264 и FFmpeg. Причём сначала кодек, а затем только утилиту для работы с ним, ибо утилиту мы будем обрабатывать напильником, выключая всё нахрен не нужное и лишнее, не относящееся к задаче.

А чтобы упростить себе накатывание уже придуманной связки в новые малины, новые флешки и вообще быть клёвыми перцами, мы соберём готовые .deb-пакеты. Это можно будет сделать и напрямую по канонам дебианизации, ручками описывая всю структуру пакета, но как разумные люди мы поступим проще — соберём и установим их с помощью checkinstall. Почему? А потому, что в вашей конкретной системе может по умолчанию не быть даже компиляторов =) А указанная утилита сама подтянет зависимости и накатит все нужные компиляторы! Да-да, ничего страшного в консоли по-прежнему не видно, да и не предвидится!

А ещё нам понадобится клиент GIT, чтобы легко было качать исходники нужных нам программ.

Поэтому снова вводим в терминал такое:

sudo apt-get install checkinstall git

Снова соглашаемся на удовлетворение зависимостей.

Итак, мы готовы. Приступим.

Собираем и тестируем FFmpeg & h264 на Raspberry Pi

Теперь мы можем приступить к сборке нужных нам пакетов.

ВНИМАНИЕ!

Убедитесь, что на флешке малины есть достаточно места! Для компиляции (хранения временных файлов в процессе) и последующих записей нам понадобится хотя бы 1.5 ГБ!

Важно: кодеки (любые, в том числе mp3, aac и вообще) надо собирать ДО FFmpeg.

Забиваем в консоль:

git clone git://git.videolan.org/x264

Это скопирует в текущую папку свежую версию кодека. Поскольку мы ещё не уходили из домашней папки (/home/pi), то и искать готовое будем там же.

Результат работы команды на моей машине. Клиент GIT успешно скачал все файлы.

В том, что файлы скачались успешно, убеждаемся командой ls и обнаруживаем новый каталог x264.

Давайте заглянем в него!

 

 

 

Обратите внимание на приветствие. Теперь оно выглядит так:

pi@BuPi2:~/x264 $

Это означает, что мы переместились внутрь нужной папки.

Давайте  уже красноглазить на полную! :-P

Конфигурируем, собираем программу и затем пакуем её в пакет, попутно установив в систему. Команды по порядку:

  1. ./configure --disable-asm --host=arm-unknown-linux-gnueabi
    --enable-static --disable-opencl
  2. make -j4

    Тут картинку вставлять не буду, ничего интересного. Сами всё увидите и вам это понравится ;)

  3. sudo checkinstall

    А вот это самая важная фишка в нашем подходе. Утилита сама сделает make install (как это обычно бывает последним пунктом), только совсем не так, как обычно, а соберёт готовый debian-пакет и установит его. На вопрос о создании базового набора документов ответьте N — нет. Они нам не нужны. Хотя можете и согласиться, а потом курить волшебные, изумительные мануалы =) А заодно задайте пакету какое-нибудь описание, например, «My very fucking first true-linux-way program package!»

Собственно, первый пошёл. Можете сохранить получившийся пакет .deb для будущего использования.

Теперь аналогично накатываем FFmpeg:

  1. вернёмся домой и заберём с гитхаба исходники ffmpeg (обратите внимание, только исходники весят около 200 МБ!)
    cd ~
    git clone https://github.com/FFmpeg/FFmpeg.git
  2. перейдём в полученную папку 
    cd FFmpeg/
  3. Сконфигурируем нашу версию так, чтобы загромождать её лишними и ненужными прибамбасами 
    ./configure --enable-shared --enable-gpl
    --enable-libx264 --enable-version3 --disable-mmx
  4. Соберём программу 
    make -j4
  5. И установим её точно так же, как и кодек, попутно собрав готовый пакет на будущее 
    sudo checkinstall

Если всё прошло гладко, то мы не получим никаких сообщений об ошибках, а финальными сообщениями будет нечто вроде «всё готово, получившийся пакет можно установить с помощью dpkg -i». Но нам это не нужно, пакеты уже в системе, а это просто напоминание.

Далее, чтобы освободить вас от курения мануалов, я рекомендую проверить всю готовую связку простейшим способом — запустив её! :-P

Вот так выглядит запуск ffmpeg.

Вы увидите примерно то же самое.

А вот это уже куда более серьёзная команда, с помощью которой снят именно этот ролик =)

ffmpeg -threads auto -an -t 00:00:20
-video_size 1280x720 -i /dev/video0 -c:v libx264 -preset:v ultrafast output.mkv

Вот и всё! Теперь мы можем встраивать эту или сходную команду в свой собственный код в питон, хоть в перл, хоть в си, хоть в брейнфак, в конце концов. И всё будет работать.

В примере использована камера SJCam в режиме веб-камеры (отсюда и фишай) и Raspberry Pi 2.

И про Татьяну

Собственно, всё просто. Берём и встраиваем команду.

Там, где было такое:

### Глаза Татьяны. Включает камеру и записывает заданное количество секунд.
def camera_capture():
    global capture_online
    capture_online = True
    nowtime = str(round(time.time()))
    
#################################################################
############Здесь должен быть перехват через SimpleCV############
#################################################################

    connection = MYSQL.connect(host=config.dbhost,
database=config.dbbase, user=config.dbuser, password=config.dbpassword)
    cursor = connection.cursor()
    query = "INSERT INTO `pir_data`(`message`,`timestamp`)
VALUES ('{0}','{1}')".format("file.avi", nowtime)
    cursor.execute(query)
    connection.commit()
    cursor.close()
    connection.close()
    time.sleep(5)    #ВРЕМЯ ЗАПИСИ!
    capture_online = False

А теперь стало так. Никаких компьютерных зрений, всего одна команда =) Вот так просто это было сделать.

### Глаза Татьяны. Включает камеру и записывает заданное количество секунд.
def camera_capture():
    global capture_online
    capture_online = True #Пошла запись
    nowtime = str(round(time.time()))
#### 29.07.2017 - даёшь глаза!
    filename = config.recordpath + str(datetime.strftime
(datetime.now(), "%Y%m%d-%H.%M.%S"))+ ".mkv"
#имя файла для записи с полным путём из конфига
    os.system("ffmpeg -threads auto -an -t 00:00:30 -video_size 1280x720 -i
/dev/video0 -c:v libx264 -preset:v superfast {0}"
.format(filename)) #погнали записывать
    connection = MYSQL.connect(host=config.dbhost, 
database=config.dbbase, user=config.dbuser,
password=config.dbpassword)
    cursor = connection.cursor()
    query = "INSERT INTO `pir_data`(`message`,`timestamp`)
VALUES ('{0}','{1}')".format(filename, nowtime)
    cursor.execute(query)
    connection.commit()
    cursor.close()
    connection.close()
    capture_online = False

Вот такие пироги. На этом всё =) Теперь Татьяна умеет регистрировать нарушителей.

Теперь заморочимся обновлением мануалов и продолжим внедрять админку =)

Фичи запиливаются, запиливаются! =)

Вопросы и комменты можно оставлять прямо здесь, ниже в комментах.