Je souhaite écrire un programme de capture d’écran pour la plate-forme Windows, mais je ne sais pas comment capturer l’écran. La seule méthode que je connaisse est d'utiliser GDI, mais je suis curieux de savoir s'il existe d'autres moyens de procéder et, le cas échéant, qui génère le moins de frais généraux? La vitesse est une priorité.
Le programme de screencasting servira à l’enregistrement de séquences de jeu. Toutefois, si cela permet de réduire les options, je suis toujours ouvert à toute autre suggestion sortant de ce cadre. La connaissance n'est pas mauvaise, après tout.
Edit : Je suis tombé sur cet article: Différentes méthodes pour capturer l'écran . Il m'a présenté la manière de faire de l'API Windows Media et la façon de le faire DirectX. Il est mentionné dans la conclusion que la désactivation de l'accélération matérielle pourrait améliorer considérablement les performances de l'application de capture. Je suis curieux de savoir pourquoi. Quelqu'un pourrait-il remplir les espaces manquants pour moi?
Edit : J'ai lu que les programmes de screencasting tels que Camtasia utilisent leur propre pilote de capture. Quelqu'un pourrait-il m'expliquer en détail comment cela fonctionne et pourquoi c'est plus rapide? J'aurai peut-être aussi besoin de conseils pour mettre en œuvre quelque chose comme ça, mais je suis sûr qu'il existe de toute façon une documentation.
De plus, je sais maintenant comment FRAPS enregistre l’écran. Il relie l’API graphique sous-jacente à la lecture de la mémoire tampon de retour. D'après ce que j'ai compris, cela est plus rapide que de lire à partir de la mémoire tampon avant, car vous lisez à partir de la RAM système plutôt que de la mémoire vidéo. Vous pouvez lire l'article ici .
C’est ce que j’utilise pour collecter des images uniques, mais si vous le modifiez et maintenez les deux cibles ouvertes tout le temps, vous pouvez le "diffuser" sur le disque en utilisant un compteur statique pour le nom du fichier. - Je ne me souviens plus où j'ai trouvé ça, mais ça a été modifié, grâce à qui que ce soit!
void dump_buffer()
{
IDirect3DSurface9* pRenderTarget=NULL;
IDirect3DSurface9* pDestTarget=NULL;
const char file[] = "Pickture.bmp";
// sanity checks.
if (Device == NULL)
return;
// get the render target surface.
HRESULT hr = Device->GetRenderTarget(0, &pRenderTarget);
// get the current adapter display mode.
//hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode);
// create a destination surface.
hr = Device->CreateOffscreenPlainSurface(DisplayMde.Width,
DisplayMde.Height,
DisplayMde.Format,
D3DPOOL_SYSTEMMEM,
&pDestTarget,
NULL);
//copy the render target to the destination surface.
hr = Device->GetRenderTargetData(pRenderTarget, pDestTarget);
//save its contents to a bitmap file.
hr = D3DXSaveSurfaceToFile(file,
D3DXIFF_BMP,
pDestTarget,
NULL,
NULL);
// clean up.
pRenderTarget->Release();
pDestTarget->Release();
}
EDIT: Je peux voir que cela est répertorié sous votre premier lien d'édition en tant que "chemin GDI". C’est toujours une manière décente d’aller même avec l’avis de performance sur ce site, vous pouvez facilement atteindre 30 images par seconde, je pense.
De this comment (je n'ai aucune expérience dans ce domaine, je ne fais que référencer quelqu'un qui le fait):
_HDC hdc = GetDC(NULL); // get the desktop device context
HDC hDest = CreateCompatibleDC(hdc); // create a device context to use yourself
// get the height and width of the screen
int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
// create a bitmap
HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height);
// use the previously created device context with the bitmap
SelectObject(hDest, hbDesktop);
// copy from the desktop device context to the bitmap device context
// call this once per 'frame'
BitBlt(hDest, 0,0, width, height, hdc, 0, 0, SRCCOPY);
// after the recording is done, release the desktop context you got..
ReleaseDC(NULL, hdc);
// ..delete the bitmap you were using to capture frames..
DeleteObject(hbDesktop);
// ..and delete the context you created
DeleteDC(hDest);
_
Je ne dis pas que c'est le plus rapide, mais l'opération BitBlt
est généralement très rapide si vous effectuez une copie entre des contextes de périphérique compatibles.
Pour référence, Open Broadcaster Software implémente quelque chose comme ceci dans le cadre de sa méthode "dc_capture" , bien que plutôt que de créer le contexte de destination hDest
en utilisant CreateCompatibleDC
ils utilisent un IDXGISurface1
, qui fonctionne avec DirectX 10+. S'il n'y a pas de support pour cela, ils retombent en CreateCompatibleDC
.
Pour le changer pour utiliser une application spécifique, vous devez modifier la première ligne en GetDC(game)
où game
est le handle de la fenêtre du jeu, puis définir le droit height
et width
de la fenêtre du jeu aussi.
Une fois que vous avez les pixels dans hDest/hbDesktop, vous devez toujours l’enregistrer dans un fichier, mais si vous effectuez une capture d’écran, je pense que vous voudriez en mettre un certain nombre en mémoire tampon et l’enregistrer dans le fichier vidéo. en morceaux, donc je ne vais pas pointer vers le code pour enregistrer une image statique sur le disque.
J'ai écrit un logiciel de capture vidéo, similaire à FRAPS pour les applications DirectX. Le code source est disponible et mon article explique la technique générale. Regardez http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/
Respect de vos questions liées à la performance,
DirectX devrait être plus rapide que GDI sauf lorsque vous lisez à partir du tampon avant, ce qui est très lent. Mon approche est similaire à celle de FRAPS (lecture du backbuffer). J'intercepte un ensemble de méthodes à partir d'interfaces Direct3D.
Pour l'enregistrement vidéo en temps réel (avec un impact minimal sur l'application), un codec rapide est essentiel. FRAPS utilise son propre codec vidéo sans perte. Lagarith et HUFFYUV sont des codecs vidéo génériques sans perte conçus pour des applications en temps réel. Vous devriez les regarder si vous voulez sortir des fichiers vidéo.
Une autre approche pour enregistrer des screencasts pourrait consister à écrire un pilote miroir. Selon Wikipedia: Lorsque la recopie vidéo est activée, chaque fois que le système appelle le périphérique vidéo principal à un emplacement situé à l'intérieur de la zone en miroir, une copie de l'opération de dessin est exécutée sur le périphérique vidéo en miroir. en temps réel. Voir les pilotes miroir à MSDN: http://msdn.Microsoft.com/en-us/library/windows/hardware/ff568315 (v = vs. 85) .aspx .
J'utilise d3d9 pour obtenir le backbuffer et l'enregistre dans un fichier png à l'aide de la bibliothèque d3dx:
IDirect3DSurface9 * surface; // GetBackBuffer Idirect3ddevice9-> GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, & surface); // enregistrer la surface D3DXSaveSurfaceToFileA ("filename.png", D3DXIFF_PNG, surface, NULL, NULL); SAFE_RELEASE (surface);
Pour ce faire, vous devez créer votre swapbuffer avec
d3dpps.SwapEffect = D3DSWAPEFFECT_COPY ; // for screenshots.
(Vous garantissez donc que le backbuffer n'est pas mutilé avant de prendre la capture d'écran).
Dans mon impression, l'approche GDI et l'approche DX sont de nature différente. la peinture à l'aide de GDI applique la méthode FLUSH, l'approche FLUSH dessine le cadre, puis l'efface et redessine un autre cadre dans le même tampon, ce qui entraînera un scintillement dans les jeux nécessitant une fréquence d'images élevée.
Je pense que ce dont vous avez vraiment besoin, c’est d’un système de rejeu que je partage totalement avec ce que les gens ont discuté.
J'ai écrit une classe qui implémentait la méthode GDI pour la capture d'écran. Moi aussi, je voulais un peu plus de vitesse. Après avoir découvert la méthode DirectX (via GetFrontBuffer), j’ai essayé de le faire en espérant que ce serait plus rapide.
J'ai été consterné de constater que GDI exécute environ 2,5 fois plus vite. Après 100 essais de capture de mon affichage à double moniteur, la mise en œuvre de GDI était en moyenne de 0,65 seconde par capture d'écran, alors que la méthode DirectX était en moyenne de 1,72 seconde. Donc, GDI est définitivement plus rapide que GetFrontBuffer, d’après mes tests.
Je ne pouvais pas obtenir le code de Brandrew pour tester DirectX via GetRenderTargetData. La copie d'écran est sortie purement noire. Cependant, il pourrait copier cet écran vierge très vite! Je continuerai à bricoler avec cela et j'espère obtenir une version fonctionnelle pour en voir les résultats concrets.
Quelques choses que j'ai pu glaner: apparemment, utiliser un "pilote miroir" est rapide bien que je ne sois pas au courant d'un pilote OSS.
Pourquoi RDP est-il si rapide comparé à un autre logiciel de contrôle à distance?
Apparemment aussi, utiliser certaines convolutions de StretchRect est plus rapide que BitBlt
http://betterlogic.com/roger/2010/07/fast-screen-capture/comment-page-1/#comment-519
Et celui que vous avez mentionné (connexion de fraps aux dll D3D) est probablement le seul moyen pour les applications D3D, mais ne fonctionnera pas avec la capture de bureau Windows XP. Alors maintenant, j'aimerais juste qu'il y ait une vitesse équivalente à celle des fraps pour les fenêtres de bureau normales ... ça vous tente?
(Je pense qu'avec aero, vous pourriez peut-être utiliser des crochets de type fraps, mais les utilisateurs de XP n'auraient pas de chance).
Apparemment aussi changer les profondeurs de bits de l'écran et/ou désactiver l'accélération matérielle. pourrait aider (et/ou désactiver aero).
https://github.com/rdp/screen-capture-recorder-program inclut un utilitaire de capture basé sur BitBlt raisonnablement rapide, ainsi qu'un benchmark dans le cadre de son installation, ce qui peut vous permettre de comparer les vitesses BitBlt à optimisez-les.
VirtualDub dispose également d’un module de capture d’écran "opengl" réputé rapide et capable de détecter, par exemple, les modifications http://www.virtualdub.org/blog/pivot/entry.php?id=29
Pour C++, vous pouvez utiliser: http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html
Cela risque toutefois de ne pas fonctionner sur tous les types d'applications 3D/applications vidéo. Alors ce lien peut être plus utile car il décrit 3 méthodes différentes que vous pouvez utiliser.
Ancienne réponse (C #):
Vous pouvez utiliser System.Drawing.Graphics.Copy , mais ce n’est pas très rapide.
Un exemple de projet que j'ai écrit fait exactement ceci: http://blog.tedd.no/index.php/2010/08/16/c-image-analysis-auto-gaming-with-source/
Je prévois de mettre à jour cet exemple en utilisant une méthode plus rapide, telle que Direct3D: http://spazzarama.com/2009/02/07/screencapture-with-direct3d/
Et voici un lien pour capturer une vidéo: Comment capturer un écran en vidéo avec C # .Net?
Vous pouvez essayer le projet open source c ++ WinRobot @git , un puissant capteur d’écran.
CComPtr<IWinRobotService> pService;
hr = pService.CoCreateInstance(__uuidof(ServiceHost) );
//get active console session
CComPtr<IUnknown> pUnk;
hr = pService->GetActiveConsoleSession(&pUnk);
CComQIPtr<IWinRobotSession> pSession = pUnk;
// capture screen
pUnk = 0;
hr = pSession->CreateScreenCapture(0,0,1280,800,&pUnk);
// get screen image data(with file mapping)
CComQIPtr<IScreenBufferStream> pBuffer = pUnk;
Soutien :
Je me rends compte que la suggestion suivante ne répond pas à votre question, mais la méthode la plus simple que j'ai trouvée pour capturer une vue DirectX en mutation rapide consiste à brancher un caméra vidéo sur le port S-vidéo de la vidéo. carte, et enregistrer les images en tant que film. Transférez ensuite la vidéo de l'appareil photo dans un fichier MPG, WMV, AVI, etc. sur l'ordinateur.
je le fais moi-même avec DirectX et pense que c'est aussi rapide que vous le voudriez. Je n'ai pas un exemple de code rapide, mais j'ai trouvé this ce qui devrait être utile. la version de directx11 ne devrait pas différer beaucoup, directx9 peut-être un peu plus, mais c'est la voie à suivre
Avec Windows 8, Microsoft a introduit l’API de duplication du bureau. C'est la manière officiellement recommandée de le faire. Une fonctionnalité intéressante de la capture d’écran est qu’elle détecte le mouvement des fenêtres, ce qui vous permet de transmettre des deltas de blocs lorsque les fenêtres sont déplacées, au lieu de pixels bruts. En outre, il vous indique quels rectangles ont changé d'une image à l'autre.
L'exemple de code Microsoft est assez complexe, mais l'API est simple et facile à utiliser. J'ai mis en place un exemple de projet beaucoup plus simple que l'exemple officiel:
https://github.com/bmharper/WindowsDesktopDuplicationSample
Docs: https://docs.Microsoft.com/en-gb/windows/desktop/direct3ddxgi/desktop-dup-api
Exemple de code officiel Microsoft: https://code.msdn.Microsoft.com/windowsdesktop/Desktop-Duplication-Sample-da4c696a