Desktop Video Capturing

Общие вопросы, не зависящие от языка реализации.

Модераторы: Duncon, Hawk, Romeo, Eugie

metrosci
Сообщения: 13
Зарегистрирован: 12 авг 2007, 04:17

Здравствуйте!

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

На данный момент мне известны 3 способа захвата картинки с рабочего стола:
1) Классика: GetDC(0); CreateCompatibleBitmap(); BitBlt(). Не годится, т.к. нужно минимум 100ms на захват одного кадра.
2) DirectX: g_pd3dDevice->GetFrontBufferData(); не годится по той же причине... (MSDN: very slow by design...)
3) слегка извращенный метод, но быстрый, хотя и глючный: ставится Hmelov Screen Capture Driver, который эмулирует веб-камеру, в видеопотоке которой и идут кадры рабочего стола. Достаточно подключиться к этому потоку и хватать кадры. Работает невероятно быстро, но грузит проц на 50-100%, т.к. требует окна для Preview, т.е. постоянно идет ненужный рендеринг, на некоторых компах очень криво работает, и не переваривает 16-битный цвет.

При этом существует много программ, которые быстро и безглючно берут кадры со стола: vuCamera, RAdmin,...,...,...

как?

Буду очень признателен за любую помощь, идею, совет. Всем спасибо!
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Radmin использует свой драйвер на основе технологии Video Hook Driver (mirror drivers), т.е. перехватывает отрисовку на уровне ядра OC. Это гораздо экономичнее, т.к. пересылаются только реальные изменения на экране: для не-media приложений картинка практически статична. Наверняка еще и сжатие при передаче видеопотока применяют.

См. также
http://msdn2.microsoft.com/en-us/library/ms797878.aspx
http://msdn2.microsoft.com/en-us/library/ms791672.aspx (src\video Sample display drivers and a mirroring driver)
http://www.demoforge.com/dfmirage.htm (здесь можно скачать бесплатный VHD)
http://serotek.com/mirror-driver-paper.html (другой подход)
metrosci
Сообщения: 13
Зарегистрирован: 12 авг 2007, 04:17

Огромное спасибо! Ответ исчерпывающий. осталось разобраться, как это работает ) Но это уже не проблема. Спасибо!!
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

А чем DirectDraw не устраивает. Я вот щас для интереса решил замерить... Код очень простой, разрешение экрана 1024х768х32, захват кадра за 45-50М тактов, что составляет примерно 18-20 мс.
It's a long way to the top if you wanna rock'n'roll
metrosci
Сообщения: 13
Зарегистрирован: 12 авг 2007, 04:17

somewhere, а как это сделать через DirectDraw? подскажите, пожалуйста. Попытался захватывать через Mirror Drivers - выяснилось, что не работает захват DirectX&OpenGL, а именно это и нужно...
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

Так тебе на каком языке?
С DirectDraw (далее ДД) много ньюансов - скорость передачи зависит в основном от возможностей адаптера и драйверов. На той машине, на которой разрабатывалась демка стоит Radeon X1950XT - соответственно имеет аппаратные преобразования BitBlT и передачу посредством DMA. Скорость захвата скриншотов на нем достигала 50-60 кадров/сек. На работе старушка NVidia Vanta 8M - доступ к видеопамяти (первичной поверхности ДД) очень медленный. Без использования Blt захват всего экрана за 150-200 мс. Примерно такой же результат дает RAdmin подключенный к самому себе на этой тачке, хотя немного быстрее. Если переносить вручную через move из указателя lpSurface быстрее никак все-равно не получается - т.е. здесь скорость ограничивается на аппаратном уровне. Если покопаешься с ДД наверняка найдешь способ передачи только изменившигося куска памяти посредством масок AND или XOR через BitBlT опции. Не говорю что демка оптимальна по быстродействию но всеже работает неплохо. Удивительно то, что запись напрямую в видеопамять почти на всех тестированых тачках быстрее раз в 10. Если что не понятно, спрашивай.
Да, и еще - скачай оснастку для DirectDraw для того языка, на котором пишешь. Демку отправлю по почте, так как здесь не влезает.
It's a long way to the top if you wanna rock'n'roll
metrosci
Сообщения: 13
Зарегистрирован: 12 авг 2007, 04:17

Спасибо за пример! и за разъяснения. Язык не принципиален, разобраться можно в любом.

Я подозревал, что это зависит от железа.. но не на чем было попробовать в тот момент. Но вышеупомянутый Hmelyoff SC driver захватывает экран на скорости 30+ FPS, при этом bitblt работает 100-120 ms. Еще заметил, что bitblt c экрана на контекст любого окна работает очень быстро, раз в 5 быстрее, чем bitblt в битмап (CreateCompatibleBitmap()), видимо там идет операция копирования напрямую из видеопамяти в видеопамять без передачи в оперативку. Попробую DDraw, - может быть будет немного быстрее, и попробую как-то искать фрагменты изменившейся памяти.... Спасибо за подсказку! :)
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

&quot писал(а):Но вышеупомянутый Hmelyoff SC driver захватывает экран на скорости 30+ FPS
Если экран будет постоянно изменятся (полноэкранное видео без оверлеев) я не думаю что будет достигнута такая скорость, т.к. есть подозрения что передаются только изменения экрана, т.к. выше железа не прыгнешь :-)
&quot писал(а):Еще заметил, что bitblt c экрана на контекст любого окна работает очень быстро, раз в 5 быстрее, чем bitblt в битмап
Не в 5, а гораздо больше. Из видеопамять в видеопамять BltFast копирует весь экран за 2-3 мс.
Мне тут пришла в голову одна идея, как примерно передавать не весь экран а только изменившуюся часть. Примерно по той схеме, по которой я реализовывал сравнение двух картинок. Идея такая:

Первоначально считаем что мы уже захватили один кадр.
1. Условно экран разбивается на блоки 8х8 (можно выбрать любой другой размер, главное чтобы их умещалось ровное число, т.е. ширина и высота кратны сторонам блока) - т.е. при 1024х768 получим 128х96 блоков.
2. Выполняем StretchBitBlt (а лучше и быстрее IDirectDraw7.Blt) основной поверхности в дополнительную поверхность видеопамяти с размерами 128х96. Операция займет очень мало времени. Т.с. создание миниатюры.
3. Переносим из этой поверхности в системную память. Т.к. переносим в 64 раза меньше, операция выполняется в 64 раза быстрее. У нас уже есть миниатюра от предыдущего кадра, выполняем сравнение блоков(пикселей) - если отличаются, то данный блок необходимо захватить.
4. Переносим отмеченные блоки из основной поверхности в предыдущий битмап - получаем таким образом новый скриншот.
Переносить блоки 8х8 можно операцией BltBatch - по возможности видеокарты они перенесутся быстрее.
В теории изменение цвета хотя бы одного пикселя в блоке 8х8 повлияет на пиксель в миниатюре.
Попробую реализовать сегодня, если что о результатах сообщу.
It's a long way to the top if you wanna rock'n'roll
metrosci
Сообщения: 13
Зарегистрирован: 12 авг 2007, 04:17

отличная идея, я тоже попробую :) только у меня задача проще - мне и нужен мини-экран, где-то 192х144. Можно даже обойтись без сравнения и захвата основных блоков. Спасибо!
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

Что же ты раньше молчал? - тогда совсем проблем не будет. Нужно всего-то сделать
1. DirectDraw7.Blt (Stretch) до нужных размеров из основной поверхности в дополнительную, главное чтобы она была в видеопамяти.
2. BitBlt с контекста дополнительной в контекст битмапа. И все!!!
Настоятельно рекомендую делать именно так, потому что если видеокарта на аппаратном уровне не умеет делать Stretch из VM в SM - то будет оччччень медленно.
В понедельник могу показать как, щас под рукой ничего нет.
It's a long way to the top if you wanna rock'n'roll
Ответить