Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Media";
Текущий архив: 2005.07.25;
Скачать: [xml.tar.bz2];

Вниз

Максимально быстро подготовить картинку для передачи по сети   Найти похожие ветки 

 
Citizen ©   (2005-03-24 01:09) [0]

Цель моей программы: передача скриншотов по сети. Сама передача по сети - это другой вопрос. На данный момент меня интересует как максимально быстро снять скрингот и подготовить его к отправке. Конечно за RAdmin"ом я не гонюсь, но хотелось бы сделать, чтобы передавался хотя бы 1 скрин в секунду. Возникли кое-какие проблемы.
Делаю следующее: снимаю скриншот, преобразую его в jpg, чтобы размер был поменьше, затем преобразую в поток для передачи по сети.

var jpg:TJPEGImage;
   dd:hdc;
   bmp:TBitmap;
   ms:TMemoryStream;
begin
 dd:=GetDC(0);
 bmp:=TBitmap.Create;
 bmp.Width:=Screen.Width;
 bmp.Height:=Screen.Height;
 StretchBlt(bmp.Canvas.Handle,0,0,Screen.Width,Screen.Height,dd,0,0,Screen.Width,Screen.Height,MERGECOPY);
 ReleaseDC(0,dd);
 jpg:=TJPEGImage.Create;
 jpg.CompressionQuality:=70;
 jpg.Compress;
 jpg.Assign(bmp);
 ms:= TMemoryStream.Create;
 jpg.SaveToStream(ms);
 bmp.free;
 jpg.free;
 ms.free;
end;


Ставлю этот код в обработчик таймера, и каждые 500 мс допустим уменя снимается скриншот. Но возникают тормоза каждые полсекунды. Оказалось из-за этой строчки:

jpg.SaveToStream(ms);

Если её закомментировать, то никаких тормозов нет. Это я картинку преобразую в поток для дальнейшей передачи по сети.
Это действие занимает где-то 250 мс. Причём, если первоначально скриншот не преобразовывать в jpg, а сразу из BMP в поток:

bmp.SaveToStream(ms);

то эта команда выполняется быстрее раза в полтора.
Так вот мне интересно, как обойти эти тормоза? Как можно ещё картинку в поток преобразовать, но чтобы не притормаживало?

И ещё вопрос: для уменьшения передаваемых данных хочу сравнивать новый скриншот с предыдущим и посылать только изменённую информацию. Как это можно организовать (сравнение и получение изменившихся частей)?


 
uny ©   (2005-03-24 08:10) [1]

jpg это сжатие, winrar тоже не мгновенно жмёт
идея - не скриншот передавать, а данные для создания картинки - т.е. если рабочий стол, то какие обои, какие ярлыки, как изменилось положение мыши, какие клавиши были нажаты, программы запущены(программы, отдельные окна скриншотом - не весь экран, а только их, как получается при нажатии alt + print screen)


 
Digitman ©   (2005-03-24 10:03) [2]


> то эта команда выполняется быстрее раза в полтора


что ж тут удивительного ?
разумеется, перекодировка битмапа в jpg-формат - алгоритм нетривиальный ..


> как обойти эти тормоза?


например, жать граф.данные RLE-алгоритмом, он весьма быстр ..


> хочу сравнивать новый скриншот с предыдущим и посылать только
> изменённую информацию


совершенно логично.


> Как это можно организовать (сравнение и получение изменившихся
> частей)?


разбивай битмап на прямоугольные регионы
сжимай и посылай (целиком) только те регионы, в которых произошло изменение хотя бы, например, одного пикселя


 
Анонимщик1   (2005-03-24 12:15) [3]

Этот вопрос неоднократно обсуждался. Лучшее, что мне запомнилось - рекомендация ставить хук на запись в видеопамять или что-то вроде того (точно не помню, тем более, что не понял как это). Это по существу вопроса.
А что касается сравнения и сжатия разницы, то для этого существуют кодеки видеопотоков, и ты вряд ли напишешь то же самое оптимальнее. Так что смотри в эту сторону.


 
Citizen ©   (2005-03-24 14:24) [4]

>jpg это сжатие, winrar тоже не мгновенно жмёт

Так тормоза возникают не при сжатии, а при преобразовании в поток:

jpg.SaveToStream(ms);

>идея - не скриншот передавать, а данные для создания картинки -> т.е. если рабочий стол, то какие обои, какие ярлыки, как >изменилось положение мыши, какие клавиши были нажаты, >программы запущены(программы, отдельные окна скриншотом - не >весь экран, а только их, как получается при нажатии alt + >print screen)
Мысль конечно интересная, только как это делать? Откуда брать такую информацию (об окнах, ярлыках, обоях)? А самое главное, как потом это в своём окне всё отображать. Ну допустим узнал я что были нажаты такие то клавиши и запущены такие то процессы, и что?
То есть вы предлагаете посылать скриншоты отдельных окон программ, а потом в самой программе их уже располагать как нужно?

>> то эта команда выполняется быстрее раза в полтора

>что ж тут удивительного ?
>разумеется, перекодировка битмапа в jpg-формат - алгоритм >нетривиальный ..

Я имел ввиду, что команда

bmp.SaveToStream(ms);

выполняется в полтора раза быстрее, чем

jpg.SaveToStream(ms);

JPG уже получен, а этими командами я сохраняю данные в поток.

>например, жать граф.данные RLE-алгоритмом, он весьма быстр ..
Где можно про это почитать? Есть ли какие-нибудь примерчики?
А как насчёт быстрого сохранения в поток?

>разбивай битмап на прямоугольные регионы
>сжимай и посылай (целиком) только те регионы, в которых >произошло изменение хотя бы, например, одного пикселя
Что-то мне кажется, что это займёт кучу времени - все эти манипуляции.
Всё ясно с этим:
1). Разбиваю новый скриншот.
2). Последовательно сравниваю каждую часть с предыдущей.
3). Сжимаю изменившиеся части и отсылаю.
Интересует меня 2-ой пункт, как сравнить две картинки, но так, чтобы была высокая скорость?
И есть ли какой-то метод, чтобы сравнить оба скриншота без разбивки? Получить только изменившиеся пиксели, их упаковать и отослать?

>Этот вопрос неоднократно обсуждался.

А можешь кинуть какие-нибудь ссылочки, где это обсуждалось, а то я искал, ничего конкретного не нашёл.
Иль посовету, где поискать.

>Лучшее, что мне запомнилось - рекомендация ставить хук на >запись в видеопамять или что-то вроде того (точно не помню, >тем более, что не понял как это). Это по существу вопроса.

Нда, я тоже не особо понимаю. Может кто объяснит из знающих?

>А что касается сравнения и сжатия разницы, то для этого >существуют кодеки видеопотоков, и ты вряд ли напишешь то же >самое оптимальнее. Так что смотри в эту сторону.

То, что я сам такое не напишу - это точно. Может тогда можно готовыми решениями воспользоваться? Есть ли что-нибудь подобное?


 
Anatoly Podgoretsky ©   (2005-03-24 14:37) [5]

Citizen ©   (24.03.05 14:24) [4]
То есть вы предлагаете посылать скриншоты отдельных окон программ, а потом в самой программе их уже располагать как нужно?

Именно так и поступают серьезные програмы, только они еще дальше идут передают или измененые регионы или вообще классовые параметры, а не картинки.


 
Анонимщик1   (2005-03-24 17:21) [6]

Есть DirectShow фильтр PushSource - вполне подойдет для видеопотока.


 
Citizen ©   (2005-03-25 01:17) [7]

>например, жать граф.данные RLE-алгоритмом, он весьма быстр ..
Вот скачал пример сжатия данных с помощью RLE-алгоритма
http://torry.net/pages.php?id=357
Там самый первый пример.
Быстрый то он может и быстрый, даже не стал проверять. Но только степень сжатия очень маленькая. Попробовал сжать bmp-файл размером 3.6 мегабайта, стал 3 мегабайта. Лучше уж в jpg преобразовывать.


 
DiamondShark ©   (2005-03-25 12:20) [8]


> Интересует меня 2-ой пункт, как сравнить две картинки, но
> так, чтобы была высокая скорость?

Выполнить попиксельную операцию XOR над картинками.
Ненулевые пикселы будут соответствовать изменённым пикселам.

Потом разбиваем изображение на прямоугольники по примерно такому алгоритму:

1. Ищем минимальный прямоугольник, включающий все ненулевые пикселы
2. Разбиваем его пополам поперёк длиннейшей стороны
3. Повторяем рекурсивно для каждого вновь полученного прямоугольника, пока либо не будет достигнуто некоторое количество фрагментов, либо некий минимальный размер фрагмента.

Некоторые фрагменты могут оказаться вырожденными, их исключаем.
Пакуем без потерь (например, RLE или ZIP) фрагменты и передаём.


 
Earser   (2005-03-25 13:42) [9]

Citizen ©

RLE не поддерживает true color. Самый лучший выбор- zlib.


 
DiamondShark ©   (2005-03-25 13:47) [10]


> RLE не поддерживает true color

Да чито ви гойворите?!


 
Eraser ©   (2005-03-25 13:59) [11]

DiamondShark ©

Ещё скажи что поддерживает....


 
DiamondShark ©   (2005-03-25 14:34) [12]


> Eraser ©   (25.03.05 13:59) [11]

Разумеется, нет! Точно так же, как не поддерживает high color, альфа-канал и арабскую кодировку.
А всё по одной и той же причине: RLE -- это алгоритм (точнее, класс алгоритмов) сжатия битового (байтового, символьного и т.п.) потока, и ему по-барабану смысловое содержание сжимаемых данных.


 
Citizen ©   (2005-03-25 19:41) [13]


> Выполнить попиксельную операцию XOR над картинками.
> Ненулевые пикселы будут соответствовать изменённым пикселам.


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


> Пакуем без потерь (например, RLE или ZIP) фрагменты и передаём.

Упаковка тоже много времени займёт.


 
Магнитон Борыч   (2005-03-25 20:46) [14]

> Citizen ©  (25.03.05 19:41) [13]
> По-моему это будет очень долго выполняться, если попиксельно сравнивать.


Я бы не сказал
http://www.delphimaster.ru/articles/pixels/index.html


 
Citizen ©   (2005-03-26 08:16) [15]


> Выполнить попиксельную операцию XOR над картинками.
> Ненулевые пикселы будут соответствовать изменённым пикселам.
>
> Потом разбиваем изображение на прямоугольники по примерно
> такому алгоритму:
>
> 1. Ищем минимальный прямоугольник, включающий все ненулевые
> пикселы
> 2. Разбиваем его пополам поперёк длиннейшей стороны
> 3. Повторяем рекурсивно для каждого вновь полученного прямоугольника,
> пока либо не будет достигнуто некоторое количество фрагментов,
> либо некий минимальный размер фрагмента.
>
> Некоторые фрагменты могут оказаться вырожденными, их исключаем.
> Пакуем без потерь (например, RLE или ZIP) фрагменты и передаём.


Попробовал реализовать нечто подобное, только минимальный прямоугольник не искал, и рекурсию не делал. А разбил весь скриншот на прямоугольники, например 20 на 20, то есть на 400 прямоугольников. Потом смотрел, если в прямоугольнике есть хотя бы одна единица, то вырезаю его для отправки, а где все нули - те пропускаю.
В результате получается n прямоугольников - изменившиеся части картинки.
Но всё это по времени достаточно продолжительно получается - 150 мс.
Соответственно, чем мельче сетка разбития - тем дольше всё это будет происходить, но тем более точно определим изменения картинки и если изменений немного, то и данных для отсылки будет немного. Чем реже сетка, тем менее точно будут зафиксированы изменения - тем больше инфы посылать придётся.
По моему легче преобразовать в jpg да и послать - быстрее будет.


 
ЮЮ ©   (2005-03-26 11:20) [16]

>По моему легче преобразовать в jpg да и послать - быстрее будет.
>Так тормоза возникают не при сжатии, а при преобразовании в поток: jpg.SaveToStream(ms);

именнно при "преобразовании в поток" и происходит "сжатие в jpg", ибо jpg - это формат хранения данных, а не их представления. При jpg.Assign(bmp) скорей всего никакого преобразования нет, т.к. твой TJPEGImage тоже работает с Bitmap-ом, как и вся Windows

jpg:=TJPEGImage.Create;
jpg.CompressionQuality:=70;
jpg.Compress;
чего жмет в только что созданном объекте ?


 
Citizen ©   (2005-03-26 15:04) [17]


> именнно при "преобразовании в поток" и происходит "сжатие
> в jpg", ибо jpg - это формат хранения данных, а не их представления.
> При jpg.Assign(bmp) скорей всего никакого преобразования
> нет, т.к. твой TJPEGImage тоже работает с Bitmap-ом, как
> и вся Windows
> чего жмет в только что созданном объекте ?


Да, действительно, изменил код на следующий:

jpg:=TJPEGImage.Create;
jpg.Assign(bmp);
jpg.CompressionQuality:=70;
jpg.Compress;
ms:= TMemoryStream.Create;
jpg.SaveToStream(ms);


Теперь задержка при сжатии jpg - 300 мс, а задержки при записи в поток нет. Но задержки при записи в поток нет, потому что у меня комп быстрый и получившаяся jpg мало весит. Попробовал на медленном компе - при записи в поток тоже есть задержка.
А сжатие в jpg вообще 1 секунду занимает!
Как ещё можно сжать bmp, но так чтобы быстро. RLE как то плохо сжимает, почти никакого эффекта.

Вот ещё что, строчка

bmp.SaveToStream(ms);

тоже притормаживает, окола 100 мс. Как то можно записать данные в поток другим образом без тормозов?
Где то слышал, что надо сначала выделить в потоке память для картинки, а потом туда картичнку уже записать, но как это сделать не знаю.


 
Anatoly Podgoretsky ©   (2005-03-26 15:26) [18]

Earser   (25.03.05 13:42) [9]
Ты это сам придумал?
Смотри DiamondShark ©   (25.03.05 14:34) [12] точнее не скажешь, данный алгоритм никакими видеоданными не оперирует. Только байтами, слова и т.д.



Страницы: 1 вся ветка

Форум: "Media";
Текущий архив: 2005.07.25;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.013 c
10-1097502395
Roobee
2004-10-11 17:46
2005.07.25
Интеграция Delphi и Excel. Мастера откликнитесь.


14-1120398403
Soft
2005-07-03 17:46
2005.07.25
Как с 3 V можно получить 7 KV?


1-1120554271
СергейК
2005-07-05 13:04
2005.07.25
Может ли форма работать как функция?


14-1119556021
Ломброзо
2005-06-23 23:47
2005.07.25
И снова DMJS Client


14-1120131748
Иксик
2005-06-30 15:42
2005.07.25
Можно ли переоформлять билеты на поезд на Украине?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский