Запись видео с экрана Mac OS X средствами open-source

    Иногда надо записать демо работы программы, но под руками нет подходящих инструментов. Более того, бесплатных утилит для этих целей вообще не найти, а платные еще и не факт, что справятся как надо. Как поправили меня в коментариях, обычная версия QuickTime Player отлично пишет видео. Дальше рекомендуется читать только любителям open-source и необычных решений.
    В моем случае возникла необходимость записать работу игры на симуляторе iPhone и Android. Программист внутри меня сразу предложил написать кучу кода, как под iOS/Android, так и под сам Мак, дампить кадры через OpenGL и пр. Остановив эти позывы, я таки решил найти готовые решения, а затем и оформить тут статью, как памятку.


    Прелюдия


    Поиск по форумам показал, что люди с подобными задачами делятся на две категории: те, кто покупает специализированные программы с возможностью захвата (QuickTime Pro, etc.) и те, кто пользуется взломанными/триальными/бета версиями этих же программ. Копнув чуть глубже, я узнал, что в мире Linux/Unix подобной проблемы нет вообще с момента добавления к ffmpeg модуля x11grab. Модуль этот перехватывает буфер X приложений и затем через ffmpeg видео сжимается в промежуточный формат (qtrle, raw, x264 lossless и пр.). В Mac тоже есть X сервер, но через него выводят информацию только программы, портированные с Linux, но не адаптированные под Cocoa. Это и стало отправной точкой моих экспериментов.

    Инструменты: ffmpeg + x11grab + Xvfb


    image
    В MacPorts в ffmpeg модуль x11grab в принципе отсутствует. Собрать его целиком из исходников с первого раза не вышло, потому я решился пропатчить файл порта для ffmpeg-devel:
    /opt/local/var/macports/sources/rsync.macports.org/release/tarballs/ports/multimedia/ffmpeg-devel/Portfile
    Туда в конфигурацию nonfree я добавил строки --enable-x11grab и --enable-shared, для активации x11grab.
    Забегая наперед скажу, что в этом методе нашелся изъян, потому я не выкладываю Portfile с правками, а описываю его тут только для ознакомления.

    Когда X программа отображается в сессии (дисплее) :0.0 по-умолчанию, запись видео дает небольшую частоту кадров, в основном из-за размера экрана (2560x1440 у iMac), а скорее всего еще и из-за отрисовки графики, потому я решил перенаправлять программы в виртуальный дисплей с небольшим разрешением. Это делается через проект Xvfb, который без проблем установился из портов.
    Запускается он довольно просто через терминал (размер с запасом):
       Xvfb :1 -screen 0 1024x800x15 -shmem

    Так же просто подключается к этому виртуальному дисплею ffmpeg:
       ffmpeg -r 30 -s 1024x768 -f x11grab -i :1.0+0,20 -vcodec qtrle target.mov

    На этом этапе меня ждала ошибка с переполнением Shared Memory, которая зачем-то в OS X установлена в неприличное значение в 4mb. Временное увеличение ее размера описывается и в рекомендациях Apple для серверов, и в других источниках:
       sudo sysctl -w kern.sysv.shmmax=67108864
       sudo sysctl -w kern.sysv.shmall=67108864


    Запись сессии VirtualBox


    Следующим этапом я решил вывести через X сервер что-то полезное. Первой мыслью было собрать X-версию VirtualBox, а уже там в виртуальной машине показывать буквально что-угодно, но VirtualBox для маков давно уже мигрировал на Cocoa, потому это был тупик. Второй здравой мыслью было подключиться по RDP к виртуальной машине и записывать сессию rdesktop, благо он работает именно под X. Активация RDP под VirtualBox довольно простая, но требует установки Extension Pack с официального сайта.
    Подключение rdesktop с выводом через экран :0.1
       DISPLAY=:1.0 rdesktop -xl localhost

    После этих действий ffmpeg начинает довольно успешно писать видео в .mov файл. В моем случае это был удачно подвернувшийся под руку Android x86:


    К сожалению, видео получается довольно дерганное, сказывается сжатие rdp, потому анимацию так снимать не очень хорошо.

    Следующим шагом я решил перейти от RDP к VNC. В VirtualBox встроили VNC сервер, но не в публичные билды, а в собранные из портов или исходников. Никаких манипуляций с портами делать не пришлось, после сборки порта virtualbox я получил версию 4.1.14, с которой вполне можно работать.

    Неприятным моментом оказалось лишь то, что VNC не доступен через интерфейс, а только при запуске в headless режиме:
       VBoxHeadless -startvm 'Android x86' -v on --vnc
    Управлять таким режимом приходится либо через второй сеанс VNC, либо снова через RDP, что не очень удобно, но в целом терпимо. Для захвата VNC потока использовался vncviewer, перенаправленный на виртуальный X дисплей:
       vncviewer localhost -ViewOnly -display :1.0 -PreferredEncoding raw -FullColor

    Результатом всех этих изысков стало 5-минутное видео c честными 30 fps в разрешении 1024х768:

    (заранее извиняюсь за качество контента, я все-таки не профессиональный игрок)

    Если присмотреться, то временами заметны паузы на несколько секунд. К сожалению, эту проблему так и не получилось победить, да и сам подход вышел довольно громоздким. Для простейшей демонстрации игры в Android этого в общем достаточно, потому я переключился на следующую задачу — съемку видео симулятора iPhone.

    Захват VNC для всего экрана


    image
    В OS X встроен удаленный доступ, который работает одновременно под двум протоколам — ARD и VNC. До выхода Lion 10.7 можно было включить Screen Sharing в системных настройках и подключиться к текущей сессии любым VNC клиентом. Начиная с 10.7 начались серьезные изменения: были выброшены все типы сжатия, кроме ZRLE, подключиться могут далеко не все клиенты, да и после подключения мы видим серый экран входа в систему, а уже лишь после ввода пароля пользователя подключаемся к сессии. Это отлично для администраторов, но для моей задачи наоборот создавало только препятствия. Программа vncviewer (он же RealVNC) в последних версиях уже умеет подключаться к OS X, но не умеет вводить пароль пользователя, потому этот путь тоже оказался тупиковым.
    В качестве альтернативы я взял бесплатный VNC сервер от TestPlant (от же osxvnc и он же Vine). Версия 3.0 с sourceforge устарела, потому надо собирать новую из исходников или брать с сайта TestPlant.

    Несущественный баг этого сервера в том, что изредка клиент отпадает с ошибкой «unknown message type 131». Лечится перезапуском сервера.

    С уже налаженной связкой ffmpeg+x11grab+Xvfb и vncviewer получилось снять полноэкранное видео текущей сессии OS X, где был запущен симулятор iPhone:


    Размер виртуального буфера я выбрал заведомо меньше разрешения экрана, чтобы снимать верхний левый угол. Результат вышел вполне достойным, но к сожалению, с низким FPS — анимация в игре откровенно тормозила. Более того, паузы, которые были довольно редкими при схемке из VirtualBox стали гораздо более выраженными.
    На этом этапе я провел несколько экспериментов, пересобирал VNC сервер и клиент из исходников, ставил минимальное разрешение экрана, но так и не добился хорошего результата. Уже через несколько часов стало понятно, что сам сервер отдает кадры с некоторой задержкой. После копания в коде выяснилось, что сервер намеренно делает паузу между обновлениями экрана:
            /* OK, now, to save bandwidth, wait a little while for more updates to come along. */
            /* REDSTONE - Lets send it right away if no rfbDeferUpdateTime */
            if (rfbDeferUpdateTime > 0 && !cl->immediateUpdate && !cl->needNewScreenSize) {
                pthread_mutex_unlock(&cl->updateMutex);
                usleep(rfbDeferUpdateTime * 1000);
                pthread_mutex_lock(&cl->updateMutex);
            }
    

    Оказалось, что переменная rfbDeferUpdateTime имеет начально значение 40 мс, но она вполне управляема и задается через коммандную строку. В самом Vine Server для этого есть отдельное поле:

    Я поставил значение с запасом в 15, что дает максимальную частоту кадров в 66 fps. После этого прекратились лаги, но так и остались заметные паузы в видео. Теоретически, из такого видеоряда их можно повырезать и собрать что-то приемлемое, но хотелось более универсальное решение.

    Туз в рукаве: vnc2flv


    Теперь у меня был видеопоток в формате vnc отличного качества, оставалось только записать его в файл. Я снова подавил исконно программистское желание написать собственный дампер и нашел в недрах интернета проект vnc2swf, а затем и его наследника vnc2flv. Скептическое отношение к грабберу на Питоне прошло сразу же после первых результатов — программа записывает видеопоток в lossless качестве и разрешении WQHD с 15+ fps! Запускаю я ее без извратов с Xvfb, напрямую подключая к VNC серверу:
       flvrec.py -r 30 127.0.0.1

    Для повышения fps достаточно уменьшить разрешение до 1280x720. Что интересно, при этом можно перезапустить Vine VNC, он подхватит текущее разрешение экрана, а затем можно спокойно переключиться на родное разрешение и включать запись.
    Установка vnc2flv очень проста и описана на сайте, особых подводных камней тут нет.
    Готовое видео можно обработать в любимом видео-редакторе, обрезать лишнее и сконвертировать в нужный формат. Я пользуюсь VirtualDub, запущенным под wine, но это уже дело привычки.


    Вот результат всей этой эпопеи:

    Видео достаточно четкое, без рывков и лагов. Анимация записана нормально. Как по мне, вполне можно использовать для записи буквально чего-угодно с экрана Mac OS. Не хватает буквально только курсора, но это можно и так пережить.

    Послесловие: тупиковые ветви


    Перечислю тут тупики и грабли, которые встретил, на случай если кто-то будет искать свой собственный метод.

    VLC Player — начиная с OS X 10.7 не умеет записывать видео с экрана
    CaptureMe — вылетает, пишет пустое видео
    SIMBL плагин для iPhone Simulator — требует модификации версии симулятора в коде и пересборки, не пишет видео iPad, в целом не заработал у меня вообще
    osxvnc 3.0 c SourceForge — краш на 10.7
    RealVNC Server — требует лицензионный ключ
    VirtualBox, режим записи видео — умер 3 года назад, не поддерживается и не работает
    ffmpeg+x11grab — перспективно и гибко, но дает неизлечимые паузы в видео. Привожу ссылку на блог, из которого подчерпнул эту идею.
    Apple HTTP Live Streaming — не содержит инструментов для стриминга
    Поделиться публикацией

    Похожие публикации

    Комментарии 11

      +6
      QuckTime прекрасно пишет видео с экрана.
        0
        Хе-хе. Был уверен, что только Pro версия пишет.
        Ну что ж, будем считать потраченное время инвестицией в собственные знания и необычные решения :)
          +1
          Более того, если не нужны специфические вещи вроде подсветки указателя и вывода нажатых клавиш на экран, то весь монтаж прекрасно проводится в Аймуви. (:
            0
            А как обстоят дела с фулскрин 3д играми, записью по таймеру, видео с 60фпс, записями без окошка плеера на экране?

            Но, посыпая голову пеплом, соглашусь, для поставленной задачи мне бы действительно вполне хватило QuickTime.
              0
              Поигрался еще немного, обнаружил такие данные о QuickTime записях:
              — частота 60 fps (если мощности процессора хватает, при большом разрешении не хватает)
              — кодек Motion JPEG 2000 (иногда есть артефакты, агресивно конвертирует цвета, картинка становится блеклой)
              — сильно тормозит при записи фул-скрина или вообще чего-то сравнимого с Full HD
              — окошка при съемке не видно
              — курсор спрятать нельзя, только подсветить клики
              — настроек почти никаких, фрейм выбора не сохраняется
        +3
          +3
          Топик можно закрывать :)
          0
          Есть еще бесплатный Jing для OSX — использовал только версию для Windows — работает без нареканий
            0
            Боюсь, проприетарный кодек от TechSmith и 5 минут ограничения — не очень хорошо для записи игр. Надо будет проверить.
            0
            Что за игра на симуляторе, hexxagon?

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

          Самое читаемое