Desktop Video Capturing
Модераторы: Duncon, Hawk, Romeo, Eugie
поэкспериментировал с DirectDraw захватом - всё работает намного быстрее, чем чистый GDI, но есть такая проблема - нельзя получить доступ к первичной поверхности, если работает DirectDraw приложение.. Видимо, они там используют exclusive mode. Зато отлично захватываются DirectX\OGL приложения. Можно ли как-то обойти проблему DDraw?
поэкспериментировал еще немного и выяснил, что доступ к первичной поверхности может быть осуществлен только если приложение выставляет разрешение и глубину цвета такие же, как на рабочем столе. Т.е. я сделал так: если есть доступ к первичной поверхности, получаем снимок через ddraw, если доступа нет - через gdi. После этого (если доступ был через gdi), пытаемся заново получить доступ к первичной поверхности (попытка полной инициализации). Эта повторная инициализация успешно завершается только в случае возврата на рабочий стол (свернули игру) или если игра меняет свое разрешение на настройки, идентичные настройкам десктопа... Никаких временных настроек я в коде не запоминаю, т.е. там реально идет попытка полной инициализации с нуля..
Если игра(полноэкранное ДД приложение) запрашивает DDSCL_EXLUSIVE то создать свою первичную поверхность не дадут, а вот подключится к уже существующей в игре вполне возможно. Я думаю стоит попробовать EnumSurfaces чтобы получить список всех поверхностей, либо только лишь первичной." писал(а):поэкспериментировал еще немного и выяснил, что доступ к первичной поверхности может быть осуществлен только если приложение выставляет разрешение и глубину цвета такие же, как на рабочем столе
It's a long way to the top if you wanna rock'n'roll
попытался искать эту поверхность - нахожу, получаю ее свойства - всё совпадает, поверхность находится нормально, но вот при попытке Blt возникает ошибка surface lost... Для проверки решил блиттить ее саму на себя, чтобы убедиться, что проблема именно в этой поверхности. Не работает всё равно.
Попробуй ее восстановить... К тому же во время работы дебаггера, когда захватываемое приложение свернуто Surface действительно Lost. Контролировать успехи и ошибки нужно через Log-файл во время выполнения полноэкранного ДД приложения, чтобы потом можно было посмотреть не выходя в дебаггер.Рассмотрим следующую ситуацию: ваше приложение начинает работу. Вы размещаете как можно больше поверхностей в видеопамяти, а все остальные — в системной памяти. В течение некоторого времени приложение работает, но затем пользователь запускает другое приложение или переключается на него. Другое приложение может быть чем угодно — скажем, стандартной Windows-программой (например, Windows Explorer или Notepad). Оно также может оказаться другим приложением, которое тоже работает с DirectDraw и стремится разместить как можно больше поверхностей в видеопамяти. Если DirectDraw откажется выделить новому приложению видеопамять, оно будет работать плохо (а то и вообще не будет). Возможна и обратная ситуация — видеопамять окажется недоступной для вашего приложения.
По этой причине DirectDraw может забрать у неактивного приложения видеопамять, занятую некоторыми (или всеми) поверхностями. Такие поверхности называются потерянными (lost). Вообще говоря, такие поверхности остаются у вашей программы, но они перестают быть связанными с какой-либо областью памяти. Любая попытка использовать потерянную поверхность приводит к ошибке DDERR_SURFACELOST. Функция IsLost позволяет узнать, была ли потеряна память данной поверхности.
Потерянную поверхность можно восстановить функцией Restore, но только после повторной активизации вашего приложения. Тем самым предотвращается восстановление поверхностей для приложений, находящихся в свернутом виде на панели задач.
При этом существует одна загвоздка. Функция Restore восстанавливает лишь память, закрепленную за поверхностью, но не ее содержимое. Следовательно, после восстановления поверхности ваше приложение само должно восстановить ее содержимое.
Обратите внимание: сказанное не относится к поверхностям, находящимся в системной памяти. Если память, занятая такими поверхностями, потребуется для других целей, Windows перенесет их на диск. Все эти действия Windows выполняет автоматически, включая восстановление содержимого поверхностей.
It's a long way to the top if you wanna rock'n'roll
я так и делал - log + WM5 КПК для отслеживания картинок..
Провел еще один эксперимент: написал отдельную маленькую прогу, которая в цикле постоянно пытается перебрать все поверхности и результаты пишет в лог. Выяснилось, что не находится вообще ни одна поверхность - а в предыдущей программе находились поверхности, которые были неудачно созданы самим сервером.. Мне еще показалось странным, почему находятся так мало поверхностей, ведь в играх должно быть еще и множество невидимых.
Спросил гугл, выяснилось(по довольно невнятным высказываниям), что EnumSurfaces возвращает только поверхности, созданные тем приложением, которое вызывает эту функцию. Т.е. нельзя перебрать чужие поверхности... Есть, конечно, process injection, но мне надо контролировать весь десктоп, все игры, которые могут быть запущены, и т.п.. Похоже, тупик..
Провел еще один эксперимент: написал отдельную маленькую прогу, которая в цикле постоянно пытается перебрать все поверхности и результаты пишет в лог. Выяснилось, что не находится вообще ни одна поверхность - а в предыдущей программе находились поверхности, которые были неудачно созданы самим сервером.. Мне еще показалось странным, почему находятся так мало поверхностей, ведь в играх должно быть еще и множество невидимых.
Спросил гугл, выяснилось(по довольно невнятным высказываниям), что EnumSurfaces возвращает только поверхности, созданные тем приложением, которое вызывает эту функцию. Т.е. нельзя перебрать чужие поверхности... Есть, конечно, process injection, но мне надо контролировать весь десктоп, все игры, которые могут быть запущены, и т.п.. Похоже, тупик..
я тут вспомнил одну вещь насчет GDI - ведь там при копировании видеопамять-видеопамять скорость тоже очень приличная. Можно ли как-то отмасштабировать картинку в видеопамяти средствами GDI, а потом дернуть оттуда ее в системную память?
Можно конечно, я именно так и предлагал
и растягиваем
Код: Выделить всё
ZeroMemory(@desc, SizeOf(desc));
with desc do begin
dwSize := SizeOf(desc);
dwFlags := DDSD_CAPS;
ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;
end;
Result := dd7.CreateSurface(desc, dds, nil); // Primary
dds.GetSurfaceDesc(desc);
with desc do begin
dwSize := SizeOf(desc);
dwFlags := DDSD_WIDTH or DDSD_HEIGHT or DDSD_CAPS or DDSD_PIXELFORMAT;
ddsCaps.dwCaps := DDSCAPS_VIDEOMEMORY;
dwWidth := 192;
dwHeight := 144;
end;
Result := dd7.CreateSurface(desc, ddst, nil); // Secodary for stretch
Код: Выделить всё
New(sr); New(dr);
sr.Top := 0; sr.Left := 0;
sr.Right := sWidth; sr.Bottom := sHeight;
dr.Left := 0; dr.Top := 0;
dr.Right := 192; dr.Bottom := 144;
ddst.Blt(dr, dds, sr, DDBLT_WAIT, 0);
ddst.GetDC(dc);
BitBlt(b.Canvas.Handle, 0, 0, 192, 144, dc, 0, 0, SRCCOPY);
ddst.ReleaseDC(dc);
It's a long way to the top if you wanna rock'n'roll
да, но ведь здесь ты создаешь Primary Surface, а этот код не выполнится, если запущено DDraw приложение. нельзя ли как-нибудь сделать масштабирование только средствами GDI, ну или без создания Promary Surface? Может быть, есть способ сделать BitBlt с нулевого контекста (GetDC(0)) в DirectDraw поверхность?
" писал(а):да, но ведь здесь ты создаешь Primary Surface, а этот код не выполнится, если запущено DDraw приложение. нельзя ли как-нибудь сделать масштабирование только средствами GDI, ну или без создания Promary Surface? Может быть, есть способ сделать BitBlt с нулевого контекста (GetDC(0)) в DirectDraw поверхность?
Код: Выделить всё
function GetSurfaceFromDC(hdc: Windows.HDC; out lpDDS: IDirectDrawSurface7): HResult; stdcall;
и работать с его PrimarySurface - я думаю из всех экземпляров только у одного есть активная PrimarySurface
It's a long way to the top if you wanna rock'n'roll