Всемогущий FFmpeg: скриншаринг в WebRTC

image-loader.svg

Когда мы пишем статьи о своем сервере в комментариях очень часто находится читатель, который говорит:

«И зачем такой огород городить? Все это одной FFmpeg командой делается!»

Вот, например, тот же скриншаринг. Всего одной FFmpeg командой можно записать происходящее на экране в файл. А дальше? Если например нужно транслировать скриншаринг на сайт? Будем записывать в файлы, загружать их на Web-сервер и запускать на сайте? Для какого-то статичного контента может быть и подойдет, но вот для «живой» трансляции вряд ли.

Вот на этом этапе и становится недостаточно только «одной команды» (хотя, забегая вперед, скажу, что одной командой мы все же обошлись), нужно еще какое-то промежуточное звено, которое позволит превратить скриншаринг захваченный FFmpeg-ом в WebRTC трансляцию.

Задача очень простая — нужно транслировать происходящее на экране компьютера на сайт, где поток будет воспроизводиться по технологии WebRTC. Захватить нужно как видео, так и звук.

image-loader.svg

Рассмотрим два варианта решения с помощью FFmpeg, под Linux и под Windows.

Когда лучшее враг хорошего

Здесь я решил сделать небольшое признание. При написании этой статьи мне впервые пришлось столкнуться с работой FFmpeg. Пришлось изучать мануалы и достаточно долго гуглить. В итоге, я нагуглил сочетание ключей программы FFmpeg для скриншаринга со звуком, на основании документации добавил ключи для передачи скриншаринга в поток на WCS сервере, успешно протестировал публикацию через FFMpeg и воспроизведение по WebRTC в среде Windows и Linux и начал писать эту статью-инструкцию.

На этапе тестирования команда для FFmpeg скриншаринга показалась мне достаточно хаотичной. Поэтому, работая над текстом статьи я решил ее «причесать» — собрал все что относится к захвату и кодированию видео в начале команды, потом собрал ключи для захвата и кодирования звука и завершил команду ключами для передачи данных на сервер и формирования потока.

Внимание! НЕ используйте эту команду!

ffmpeg.exe -f gdigrab -i desktop -draw_mouse 1 -rtbufsize 100M -framerate 30 -probesize 10M -c:v libx264 -r 30 -preset ultrafast -tune zerolatency -crf 25 -pix_fmt yuv420p -f dshow -i audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{F585B65B-4690-4433-8109-F16C6389C066}" -acodec aac -f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream

Перед публикацией статьи в блоге я проверил получившуюся команду и, к своему разочарованию, получил полное отсутствие в потоке и аудио, и видео составляющих.

image-loader.svg

Пришлось вернуться к мануалам и Google.

Я вновь и вновь проверял ключи, с которыми запускается FFmpeg. Я даже нашел альтернативный способ захвата системного звука для Windows (о чем обязательно расскажу далее). Я тестировал с разными драйверами в Windows и разными версиями рабочих столов в Ubuntu, но все мои действия приводили к одному:

На WCS сервере формировался пустой поток.

В одном из мануалов мне попалась фраза, которая прочно засела в моей голове: «Не смешивайте ключи для аудио и видео!». Вот я старательно и раскладывал ключи по полочкам. Сначала связанное с аудио, потом связанное с видео, потом передача в поток.

В какой-то момент, я запустил исходную команду, которая на первый взгляд выглядела хаотичным набором ключей. И, о чудо! В плеере был поток скриншаринга со звуком. Тогда я внимательно присмотрелся к ключам, и, наконец-то, понял свою ошибку. Нельзя смешивать ключи для аудио и видео и ключи для разных действий!

Опытным путем мне удалось выяснить, что структура команды должна быть такой:

ключи для захвата аудио + ключи для захвата видео + ключи для кодирования аудио + ключи для кодирования видео + ключи для отправки данных в поток на сервере

К сожалению, FFmpeg не поддерживает каких-либо служебных ключей для разделения секций команды, поэтому неопытному пользователю бывает сложно сориентироваться. Далее по тексту, в описаниях ключей я уточню, какие ключи к какому действию относятся.

FFmpeg скриншаринг под Windows

Рассмотрим запуск скриншаринга в поток с помощью FFmpeg. В командной строке Windows запустите на выполнение следующую команду:

ffmpeg.exe -f gdigrab -rtbufsize 100M -framerate 30 -probesize 10M -draw_mouse 1 -i desktop -c:v libx264 -r 30 -preset ultrafast -tune zerolatency -crf 25 -pix_fmt yuv420p -f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream

где:

//захват видео составляющей скриншаринга

-f gdigrab — драйвер захвата экрана Windows;

-rtbufsize 100M — буфер под видео. Трансляция с экрана должна идти быстро и гладко, чтобы не было пропусков кадров. Поэтому лучше сначала записывать видео в оперативную память, а затем FFmpeg сам передаст его в поток.

-framerate 30 — частота кадров при захвате экрана;

-probesize 10M — количество кадров необходимое FFmpeg для идентификации потока;

-draw_mouse 1 — захватывать движения мыши;

-i desktop — говорим FFmpeg записывать весь экран;

//кодирование видео составляющей скриншаринга

-c: v libx264 — сжимать будем в формат MP4 кодеком x264;

-r 30 — кодек запишет видео с частотой 30 кадров в секунду;

-preset ultrafast — говорим кодеку, чтобы долго не раздумывал и кодировал видеопоток, как можно быстрее (при записи экрана это актуально);

-tune zerolatency — опция кодека x264 для ускорения кодирования;

-crf 25 — качество записываемого видео (большее значение — хуже видео, меньшее — лучше);

-pix_fmt yuv420p — цветовой формат результирующего видео;

//формирование потока и передача его WCS

-f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream — запись в поток с именем «rtmp_stream» и передача его на сервер demo.flashphoner.com.

Итак. Захватываем экран в поток

5514c76ab7d68a9517859049385c32fa.PNG

и ловим его на стороне WCS. (Здесь и далее я использую плеер из примера «Media Devices», потому что он позволяет на скриншоте показать наличие или отсутствие аудио потока.)

7ddd18a0b4a972187c14725f7f95f951.PNG

Получаем поток скриншаринга. Правда без звука. На скриншоте видно, что в разделе «Audio stats» все по нулям.

Теперь предлагаю разобраться с захватом звука.

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

ffmpeg -list_devices true -f dshow -i dummy

Получаем примерно такую картину:

340d6ef83a180ec685206ee313f854d7.PNG

В результате выполнения команды выводится список устройств, которые могут записывать или выводить звук. Это будут колонки, микрофоны и веб-камеры. В этом списке найдите имя аудиоустройства, то есть ваших динамиков, с которых вы хотите записывать звук. На скриншоте аудиоустройство, с которого я собираюсь захватывать звук, называется «Stereo Mix (Realtek ® Audio)». Stereo Mix — одно из устройств записи звука. Это виртуальное (программное) устройство, которое позволяет смешивать источники звука, воспроизводимые внутри операционной системы и получаемые с микрофона.

Чтобы захватить звук в исходную команду для скриншаринга нужно добавить ключи:

-f dshow -i audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{8A4D10E5-8DB9-4B92-8C29-4BA2E60C1DDE}" ... -acodec aac

где:

//захват аудио составляющей скриншаринга

-f dshow — драйвер захвата звука Windows;

-i audio= — параметр «audio» в этом случае ставим равным альтернативному имени нашего «Stereo Mix (Realtek ® Audio)»;

//захват видео составляющей скриншаринга

//кодирование аудио составляющей скриншаринга

-acodec aac — сжимать аудио будем кодеком aac;

//кодирование видео составляющей скриншаринга

//формирование потока и передача его WCS

Запускаем:

ffmpeg.exe -f dshow -i audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{8A4D10E5-8DB9-4B92-8C29-4BA2E60C1DDE}" -rtbufsize 100M -f gdigrab -framerate 30 -probesize 10M -draw_mouse 1 -i desktop -acodec aac -c:v libx264 -r 30 -preset ultrafast -tune zerolatency -crf 25 -pix_fmt yuv420p -f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream

И наслаждаемся:

b9ad186127823275c871b9068c7a127f.PNG

Существует еще альтернативный метод. Он будет полезен, если у вас на компьютере нет устройства «Stereo Mix» или драйвер вашей звуковой карты его, по каким-то причинам, не поддерживает.

Для реализации альтернативного метода нам понадобится небольшая утилита «VB-Audio Virtual Cable» (На момент написания этой статьи распространяется бесплатно).

VB-CABLE — это виртуальное аудиоустройство, работающее как виртуальный аудиокабель. Весь звук, поступающий на вход CABLE, просто пересылается на выход CABLE.

Скачиваем программу VB-CABLE и устанавливаем. Установка не представляет собой ничего примечательного.

Запускаем установочный файл от имени администратора:

image-loader.svg

И нажимаем кнопку «Install Driver»

image-loader.svg

После установки нужно переключить устройство по умолчанию для воспроизведения и записи аудио на установленный виртуальный кабель.

image-loader.svg

Теперь, звуки, воспроизводимые в программах, будут перенаправляться на виртуальное устройство Cable Output, которое будет работать как обычный микрофон и, соответственно, позволит захватить воспроизводимое аудио. Однако, при этом есть один недостаток: во время этого вы не будете слышать то, что записываете (т.е. звук вместо динамиков или наушников будет направляться на виртуальное устройство записи).

Теперь снова определяем доступные устройства для захвата аудио

ffmpeg -list_devices true -f dshow -i dummy

Видим, что в списке устройств появилось устройство «CABLE Output (VB-Audio Virtual Cable)»

image-loader.svg

Запускаем захват скриншаринга с использованием этого устройства. Обращаемся к нему так же по альтернативному имени:

ffmpeg.exe -f dshow -i audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{F585B65B-4690-4433-8109-F16C6389C066}" -rtbufsize 100M -f gdigrab -framerate 30 -probesize 10M -draw_mouse 1 -i desktop -acodec aac -c:v libx264 -r 30 -preset ultrafast -tune zerolatency -crf 25 -pix_fmt yuv420p -f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream

8779234c911b5004c64a228aa4c9125f.PNG

FFmpeg скриншаринг под Linux

В этом примере мы запускаем скриншаринг на ОС Ubuntu Desktop 20.04 LTS.

Начнем с определения доступных для захвата аудиоустройств. Выполните в консоли следующую команду:

pacmd list-sources

Вывод будет примерно таким как на скриншоте. Для дальнейшей работы нас интересует устройство, которое в Ubuntu называется «Monitor of Built-in Audio Analog Stereo». Это виртуальное устройство, которое, как и его кузен «Windows Stereo Mix», позволяет смешивать системные звуки и звуковой поток, получаемый с микрофона. Для дальнейшей работы нам понадобится значение индекса этого устройства.

image-loader.svg

Запускаем скриншаринг в поток с помощью FFmpeg:

ffmpeg -f pulse -ac 2 -i 0 -f x11grab -rtbufsize 100M -s 1200x720 -framerate 30 -probesize 10M -draw_mouse 1 -i :0.0 -acodec aac -c:v libx264 -r 30 -preset ultrafast -tune zerolatency -crf 25 -pix_fmt yuv420p -f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream

где:

//захват аудио составляющей скриншаринга

-f pulse — драйвер захвата звука Linux;

-ac 2 — режим аудио «стерео» (-ac 1 — режим аудио «моно»);

-i 0 — указываем индекс устройства для захвата аудио. Как мы ранее выяснили, для «Monitor of Built-in Audio Analog Stereo» это »0» ;

//захват видео составляющей скриншаринга

-f x11grab — опция необходима, если вы захватываете экран Linux;

-rtbufsize 100M — буфер под видео;

-s 1200×720 — размеры захватываемой на экране области. В px;

-framerate 30 — частота кадров при захвате экрана;

-probesize 10M — количество кадров необходимое FFmpeg для идентификации потока;

-draw_mouse 1 — захват движений мышки;

-i:0.0 — координаты «первой точки» захватываемой области экрана;

//кодирование аудио составляющей скриншаринга

-acodec aac — сжимать аудио будем кодеком aac;

//кодирование видео составляющей скриншаринга

-c: v libx264 — сжимать видео будем в формат MP4 кодеком x264;

-r 30 — кодек запишет видео с частотой 30 кадров в секунду;

-preset ultrafast — кодировать поток как можно быстрее (при записи экрана это актуально);

-tune zerolatency — опция кодека x264 для ускорения кодирования;

-crf 25 — качество записываемого видео (большее значение — хуже видео, меньшее — лучше);

-pix_fmt yuv420p — цветовой формат результирующего видео;

//формирование потока и передача его WCS

-f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream — запись в поток с именем «rtmp_stream» и передача его на сервер demo.flashphoner.com.

Проверяем.

Запускаем воспроизведение ролика в плеере, в консоли Ubuntu запускаем FFmpeg команду, которую разобрали выше:

image-loader.svg

На стороне WCS сервера открываем любой удобный плеер и запускаем воспроизведение захваченного потока скриншаринга по WebRTC (имя потока rtmp_stream).

e97e930d7849791a775c17a3c501dc14.PNG

Сравнение команд FFmpeg для Windows и Linux

Сравнительная таблица ключей FFmpeg для скриншаринга с захватом системного звука и передачи данных в поток на WCS

Windows

Linux

Драйвер захвата звука

-f dshow

-f pulse

Указание устройства для захвата звука

-i audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{8A4D10E5-8DB9-4B92-8C29-4BA2E60C1DDE}"

-i 0

Драйвер захвата экрана

-f gdigrab

-f x11grab

Буфер под видео

-rtbufsize 100M

-rtbufsize 100M

Размеры захватываемой на экране области

-i desktop

-i:0.0 -s 1200×720

Частота кадров при захвате экрана

-framerate 30

-framerate 30

Количество кадров необходимое FFmpeg для идентификации поток

-probesize 10M

-probesize 10M

Захватывать движения мыши

-draw_mouse 1

-draw_mouse 1

Кодек для сжатия аудио

-acodec aac

-acodec aac

Кодек для сжатия видео

-c: v libx264

-c: v libx264

Частота кадров итогового видео

-r 30

-r 30

Опция для ускорения кодирования

-preset ultrafast

-preset ultrafast

Опция кодека x264 для ускорения кодирования

-tune zerolatency

-tune zerolatency

Качество записываемого видео

-crf 25

-crf 25

Цветовой формат результирующего видео

-pix_fmt yuv420p

-pix_fmt yuv420p

Запись в поток на сервер demo.flashphoner.com

-f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream

-f flv rtmp://demo.flashphoner.com:1935/live/rtmp_stream

Итог

Сегодня мы в подробностях разобрали тонкости скриншаринга со звуком при помощи FFmpeg для операционных систем Windows и Linux. В дальнейшем, с потоком скриншаринга, который был захвачен на сервере можно производить любые действия, поддерживаемые WCS. Он может быть записан, воспроизведен, ретранслирован, транскодирован или добавлен к микшеру.

Удачного стриминга!

Ссылки

Наш демо сервер

WCS на Amazon EC2 — Быстрое развертывание WCS на базе Amazon

WCS на DigitalOcean — Быстрое развертывание WCS на базе DigitalOcean

WCS в Docker — Запуск WCS как Docker контейнера

Документация по быстрому развертыванию и тестированию WCS сервера

Документация по захвату и транляции видеопотока на сервер при помощи FFmpeg

© Habrahabr.ru