Pull to refresh

Fake'аем Chatroulette в Linux — гибче, чем в Windows

Reading time11 min
Views9K
Все вы знаете о сервисах, подобных CR, которых в интернете нынче развелось достаточно. Основное поведение пользователей этих сервисов, мягко говоря, удручает. Нет, конечно, оно очень выгодно производителям клавиатур и мышек, которые разрушаются от активного кликания/нажимания кнопочки next, но, imho, любому нормальному homo sapiens оно должно взрывать мозг и вызывать творческий зуд в нём и руках, требующий действий по разрушению тотальной симметрии и однообразия в поведении смотропоказывающихся. Кроме того, это ж целых 76800 пикселей рекламной площади. В общем, надо что-то с этим делать. И в этом тексте рассказ о том, с чего можно эти дела (дела, направленные на запуск произвольных видеопотоков в чатрулетки) в Linux начать. Кроме этого из него вы узнаете: (1) как можно использовать dd для буферизации, (2) как при помощи ffmpeg grab'ить произвольную область экрана или видео-изображения, (3) об отличиях vloopback и avld, (4) о эффекте от закрепления процессов за разными нитями на Atom, (5) о использовании Xvfb для видео-монтажа, (6) об одном социальном эксперименте, (7) ну, и ещё что-нибудь да узнаете.



1. Linux

Вообще, конечно, вы можете скачать какую-нибудь утилиту вроде той, что выставлена на сайте manycam.com, и получить доступ в Windows к кое-каким возможностям. Но… Возможности эти хоть и разнообразны, но ограничены волей авторов этой программы и авторов плагинов к ней. Плагины эти писать не так уж и просто. И чем для данных задач хорош Linux и unixway, как философия обработки информации, так это тем, что вы можете достаточно просто и гибко сцеплять всякие фильтры разной степени fun'овости вместе и в итоге получать интересный результат. Свободы больше, поэтому всё ниже происходящее разворачивается в Linux. Но, конечно, и пользователи Windows должны подключиться к борьбе за разнообразие всяких чатрулеток, хотя бы при помощи той же ManyCam.com.

2. avld и vloopback

Первое, что следует сделать — это наладить видео-интерфейс с flashplayer'ом, через который и работают все эти чатрулетки. Flashplayer в Linux понимает видео-устройства подсистемы video4linux(2), поэтому нужно организовать такое виртуальное устройство. Сделать это можно при помощи специальных драйверов. В дикой природе их существует множество, но лично мне заставить работать удалось только avld и vloopback. Более или менее вменяемо они работают даже на ядре версии 2.6.33.4. Другой плюс в том, что эти драйверы (насколько мне известно) включены в репозитории Ubuntu, и в том, что (точно) они есть в AUR Arch Linux'а, наверняка они есть и в Gentoo — поэтому их достаточно просто корректно установить в систему: не нужно заниматься самосбором. Я не буду тратить время на описание того, как эти пакеты устанавливать, а сразу перейду к ответу на вопрос: а почему речь идёт о двух драйверах?

Ответ такой. Для большинства сценариев fun'а вам будет достаточно avld — он очень прост в использовании и надёжен, как валенок зимой, но у него есть существенный недостаток: avld (пока) не поддерживает множество видео-устройств, виртуальное v4l-устройство создаётся только одно во время загрузки драйвера, чего бывает недостаточно. vloopback позволяет создавать множество устройств (videopipe'ов), но при этом способен крепко подвесить flashplayer вместе с браузером, и пользоваться им нужно по достаточно шаманскому сценарию. Конечно, вы можете решить, наплевав на сложности, использовать только vloopback, но у него есть и ещё один серьёзный недостаток: он выдаёт видео-поток на той скорости, на которой читающий этот видео-поток процесс способен его принять, fps никак не контролируется. Даже если процесс видео-поток генерирующий, выдаёт кадры очень редко, просто в этом случае vloopback будет выдавать один и тот же кадр какое-то время. Поэтому firefox через flashplayer при работе с vloopback-устройством превращается в 100%-ную cpu-свинку. Поэтому, если вы развлекаетесь c vloopback на ноутбуке, имеет смысл перевести процессор в powersave режим, иначе система будет без особой пользы греться.

avld же задавать fps позволяет, через что cpu-прожорливость flashplayer ограничивается, и появляется дополнительная возможность контроля за видео.

Итак, вы установили драйверы, что с ними делать дальше?

1.1. avld

Во-первых, нужно загрузить драйвер. Делать это лучше командой

modprobe avld width=320 height=240 fps=30


После чего у вас в системе должно появиться устройство /dev/videoN, где число N зависит от количества уже существующих v4l-устройств в системе. Теоретически, согласно стандарту на дистрибутивы Linux, к этому устройству должны получить доступ на чтение и запись пользователи группы video, так что не забудьте себя в неё добавить.

Должно быть понятно, что за циферки указаны в параметрах модуля, и в документации на avld написано, что эти параметры можно менять в runtime, если в /dev/videoN записать новую конфигурацию:

echo 'width=640 height=320 fps=15' > /dev/videoN


но у меня не получалось менять настройки таким способом. Однако, поменять их можно, если просто перезагрузить модуль.

После загрузки модуля с нужными параметрами (а для flashplayer 320x240 25fps, хорошо подходят; с другими размерами) вы сразу же можете запустить браузер, зайти на какой-нибудь chatroulette.com, ткнуть область flash-плагина правой кнопкой мышки и в настройках выбрать появившуюся камеру (название её будет начинаться словами 'Dummy video device').

После включения камеры вы должны увидеть чёрный квадрат почти собственного производства. Для наполнения его красками нужно последовательно записывать raw-картинки, то есть, просто последовательности значений, кодирующих цвета пикселей, в устройство /dev/videoN. Сделать это можно так:

ffmpeg -an -i some_video.avi -f rawvideo -s 320x240 -pix_fmt bgr24 - | dd obs=$((320 * 240 * 3)) of=/dev/videoN


То есть, берётся некий видео-файл, из него извлекается видео-поток (-an говорит ffmpeg не обращать внимания на аудио-дорожки), декодируется в последовательность raw-картинок нужного размера с нужным форматом цветовой информации о пикселе, и записывается целиком, блоком размером (320 * 240 * 3) байтов, в avld.

Если поток от ffmpeg направить сразу же в /dev/videoN, то ничего не выйдет, потому как avld считает, что каждый кадр ему целиком предоставляется отдельным вызовом write с соответствующим файловым дескриптором, а ffmpeg пишет свой output небольшими порциями, в несколько килобайт, соответственно, avld будет думать, что он получает кадр целиком, но при этом получать только небольшой кусочек, и из-за этого выдавать наружу некую кашу. Чтобы это исправить выше и используется dd, опция obs говорит которому, какими блоками следует выдавать в выходной файл данные. То есть, тут dd используется как буфер для накопления полной информации о кадре, а потом выплёвывания её как неразрывного блока в avld.

Собственно, всё с avld. Вы можете записывать в /dev/videoN всё, что угодно. Полезно ещё то, что avld запоминает последний кадр и выдаёт его приложению, потребляющему видео-поток от этого v4l-устройства. Поэтому, можно записать в /dev/videoN одну картинку, и будет она представать перед не очень ясным взором обитателей чатрулеток.

Кстати, да. MEncoder записывает результаты декодирования видео в raw-формат как раз покадрово, что позволяет использовать его без dd.

1.2. vloopback

Интерфейс у этой штуки намного более сложный в сравнении с avld. Причина в том, что vloopback задумывался не как fake-видеокамера, а именно как устройство вроде pipe (которая | в bash) для realtime-обработки видео. В связи с этим, у этой штуки достаточно навороченный набор опций, и довольно сложный программный интерфейс, который может потребовать использования специальных утилит для настройки параметров этих самых videopipe'ов, которые, например, умеют масштабировать видео (прямо внутри ядра, да… Linux бывает странным). Но если цель получить fun, а не разобраться во всех тонкостях vloopback, то можно действовать по-простому.

Сначала, конечно, нужно загрузить модуль в ядро:

modprobe vloopback pipes=M

где параметр pipes может быть использован, чтобы запросить у vloopback создание соответствующего количества каналов. После загрузки vloopback сообщит о том, где в /dev будут размещены имена для входов и выходов соответствующих каналов. Посмотреть эту информацию можно так:

$ dmesg | grep vloop
[vloopback_init] : video4linux loopback driver v1.4-trunk
[vloopback_init] : Loopback 0 registered, input: video0, output: video1
[vloopback_init] : Loopback 0 , Using 2 buffers
[vloopback_init] : Loopback 1 registered, input: video2, output: video3
[vloopback_init] : Loopback 1 , Using 2 buffers


На каждый канал приходится по два имени в /dev, притворяется v4l-устройством, естественно, output канала, а данные для этого устройства записываются в input. Но протокол записи в канал vloopback хоть и прост, но нетривиален, как в случае с avld, и для записи последовательности кадров в канал придётся воспользоваться утилитой с суровым названием mjpegtools_yuv_to_v4l. В репозиториях и AUR Arch Linux этого пакета нет, поэтому лично мне пришлось собрать эту утилиту из исходников, что достаточно просто: (1) распаковать исходники www.filewatcher.com/m/mjpegtools_yuv_to_v4l-0.2.tgz.11065.0.0.html, (2) запустить make.

Теперь, всё готово к отправке видео-потока в vloopback-канал. Однако, vloopback требует нежного с собой обращения, поэтому, чтобы ничего не зависло, нужно соблюдать некоторые правила. Во-первых, всегда нужно сначала запускать видео-поток в vloopback, затем запускать приложение, которое будет читать данные из видео-устройства. Чтобы остановить работу, нужно сначала закрыть приложение читающее, а затем записывающее данные в vloopback-канал. Короче, как в стеке.

Кроме этого, vloopback требует настройки геометрии и формата представления пиксела, это можно сделать при помощи mplayer. Итак, сначала видео-поток в vloopback-канал:

ffmpeg -an -i some_file.avi -f yuv4mpegpipe -s 320x240 -pix_fmt yuv420p - | mjpegtools_yuv_to_v4l /dev/video0


При этом браузер с flashplugin'ом запущен быть не должен. Перед тем, как открывать в нём какую-нибудь разновидность чатрулетки, нужно настроить/проверить output-конец видеоканала. Это можно сделать при помощи mplayer.

mplayer tv:// -tv 'driver=v4l:width=320:height=240:device=/dev/video1'


После завершения mplayer, можно запустить браузер с какой-нибудь чатрулеткой и выбрать новорождённую виртуальную камеру. ПОМНИТЕ: чтобы ничего не зависло, нужно сначала закрыть браузер (или отключить flashplugin), и только потом остановить запись кадров в канал.

2. Контент.

Итак, виртуальные камеры, воспринимаемые flashplugin'ом, теперь известно как делать. Но чем их наполнять — вот в чём вопрос. Вообще, когда я это всё затеял, у меня было острое желание проверить: то ли у меня рожа кривая, то ли в этих чатрулетах люди за тем и сидят, чтобы постоянно тыкать на кнопку next.

Поэтому, первое, что мне захотелось сделать — это стать 'человеком посредине' между двумя пользователями, то есть транслировать видео-поток первого второму и, естественно, наоборот. Залезть за этим видео-потоком внутрь flashplugin, наверное, можно, через предзагружаемые библиотеки, но это долго и сложно. Проще взять готовую картинку с экрана. ffmpeg поможет с этим (для avld):

ffmpeg -f x11grab -s 320x240 -r 15 -i :0.0+x_offset+y_offset -f rawvideo -pix_fmt bgr24 - | dd obs=$((320 * 240 * 3)) of=/dev/videoN


Параметр -r задаёт fps — частоту взятия кадров с экрана. И подобрав верные параметры x_offset и y_offset пару раз можно добиться искомой перекрёстной трансляции и испортить тем самым себе настроение, потому что сразу же бросится в глаза, то, что народ реально сидит и тупо жмёт кнопочку next, вне зависимости от того, кого видит перед собой (что и порождает гипотезу о том, что все эти чатрулетки — происки производителей мышек и клавиатур, надеющихся на более быстрый износ некоторых кнопочек). Возможно, такое поведение является проявлением социального аналога второго закона Ньютона, когда тело в отсутствии сил (то если, в условиях симметричности окружающей среды) движется прямолинейно и равномерно.

Но тут тогда возникает другой вопрос: как же привлечь внимание человеков (желательно, внимание девушек)? Вообще, что позитивно, хорошей степенью привлекательности обладают трансляции рабочего стола (для тех, кто ещё не совсем в теме, начало команды):

ffmpeg -f x11grab -s 1680x1050 -r 15 -i :0.0 ...


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

mplayer -nosound tv://


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

3. Xvfb

Чтобы в виртуальном framebuffer можно было рисовать, это буфер, сначала, естественно, нужно создать и запустить:

Xvfb :1 -screen 1 640x480x32


этим создаётся виртуальный дисплей 1 с новым экраном 1, разрешением и глубиной цвета должно быть очевидно с какими (мастер Йода). Ну и всё. Дальнейшее так же очевидно. Вы можете отправить видео-поток вашего рабочего стола на этот виртуальный дисплей:

export DISPLAY=:1.1; ffmpeg -f x11grab -s 1680x1050 -r 15 -i :0.0 -f yuv4mpegpipe -pix_fmt yuv444p -s 640x480 - | ffplay -f yuv4mpegpipe -


ffplay при инициализации увидит переменную окружения DISPLAY и поймёт, на каком X-сервере ему рисоваться (я использую здесь yuv4mpegpipe, чтобы писать поменьше ключиков на принимающей стороне pipe'ы, но понятное дело, что конвертирование цвета в yuv444, а потом из него для отрисовки картинки добавляет нагрузки на процессор, эффективнее использовать -f rawvideo, но тогда везде придётся прописывать формат пикселя и размер кадра). Далее, вы можете наложить свой видео-образ на это безобразие:

mplayer -nosound tv:// -tv 'width=160:height=120' -display :1.1 -geometry +$((640 - 160 - 10))+$((320 - 120 - 10))


ну и отправить видеопток в виртуальную видеокамеру:

ffmpeg -f x11grab -s 640x480 -r 15 -i :1.1 -f rawvideo -s 320x240 ...


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

4. Crop

Но большинство подобных роликов, которые возможно достать в интернете…

(кстати, вот простой способ как в firefox'е выдёргивать видео со всякого flash-медия. Сейчас flashplayer-10.0.42.5 работает с видео-контентом так: он начинает качать ролик через кэш браузера, и пока ролик буфферизируется, файл соответствующий лежит в кэше firefox'а, но когда буферизация заканчивается, файл удаляется, просто он остаётся открытым, и flashplugin может его читать. Но, мы ж с вами Linux'оиды, естественно, для сохранения этого файлика у себя на диске нужно сделать на него жёсткую ссылку. Поэтому, если хотите сохранить видео, то открываете страницу с ним, потом идёте в свойства и чистите кэш браузера, будет удалено всё, кроме искомого видео, делаете на него жёсткую ссылку командой ln, ну и всё — файлик ваш.

Так вот, большинство роликов сомнительного содержания в интернете обвешаны всякими разными логотипами и бегущими строчками, от которых нужно избавляться дабы не разрушать иллюзию у смотрящих. Избавляться от них, естественно, нужно вырезанием чистого видеоматериала из всей картинки. Для этого подойдёт видео-фильтр ffmpeg — crop (урожай по-нашенскому). Но этот фильтр работает сурово и если написать нечто вроде:

ffmpeg -an -i some_video.avi -vf crop=32:32:400:300 -f rawvideo -s 320x240 ...


то вас обругают за то, что квадратик с координатами (левый_верхний — правый_нижний) (32,32) — (432,332) не попадает в кадр размером 320x240, то есть, ffmpeg сначала масштабирует кадр, а потом пытается к нему применить фильтр crop. Конечно, можно запустить bc -l и высчитать всё, что нужно, чтобы в итоге получить чистую картинку подходящего размера, но это утомительно, вместо этого можно воспользоваться конвейером:

ffmpeg -an -i some_video.avi -vf crop=32:32:400:300 -f yuv4mpegpipe - | ffmpeg -f yuv4mpegpipe -i - -f rawvideo -s 320x240 -pix_fmt ...


Ну и вот, на этом можно всем сказать: спасибо за внимание, счастливого видео-творчества на просторах чатрулеток. Но я ещё пографоманствую, ибо давно не писал на Хабре.

5. Пользователям Atom.

Вообще, для всех этих развлечений производительности какого-нибудь не самого мощного Athlon II X2 хватает с лихвой. Можно в это время ещё посмотреть парочку фильмов (одновременно) в разрешении p720. Но вот уже одно-ядерный Atom тянет это плохо, и хочется хоть как-то выжать из него дополнительные fps.

И тут, не смотря на всю симметричность его аппаратных нитей, может помочь установка афинности разным группам процессов. Вероятно, это связано с тем, что планировщик не делает различий между аппаратными нитями, считая их полностью равноправными сущностями, и свободно перекидывает процессы между ними. НО, ведь, TLB-то у этих нитей должны быть разными. И при перекидывании процесса, происходят вынужденные переключения этих самых TLB. Если firefox перемешивается в своём выполнении с ffmpeg, то, ведь, для переключения с одного на другой в рамках архитектуры x86 нужно полностью сбросить TLB и заново его загрузить новыми данными.

Поэтому, производительность чуточку повышается, если прибить при помощи

taskset -c 1 firefox


firefox ко второй нити, а все процессы, связанные с обработкой всякого видео к нити первой нити (с номером 0). Два-три кадра в секунду вполне можно таким образом выиграть.

6. Аудио.

А вот соорудить виртуальный микрофон из ALSA у меня не получилось. И это при том, что у ALSA есть родной loopback-драйвер, который называется aloop. И он действительно работает так, как и предполагается: всё, что в один из его каналов записывается, можно прочитать из соответствующего другого канала. jack-сервер с ним отлично работает, и можно всяко разно перебрасывать звук между разными приложениями. Но вот соорудить из этого aloop то, что выглядело бы как виртуальный микрофон у меня не вышло. Но, наверное, это возможно, просто мне терпения и времени не хватило для того, чтобы разобраться в этих деревянных конфигах ALSA.

А так, это бы открыло путь и к аудио-рекламе на просторах чат-рулеток. Если у кого выйдет с этим, напишите статью на Хабре, обещаю за это наплюсовать в карму :)

7. Ну всё.

Надеюсь, не было скучно и занудно. Have fun, и всё такое.

Tags:
Hubs:
Total votes 66: ↑50 and ↓16+34
Comments26

Articles