Giter VIP home page Giter VIP logo

win32capturesample's Introduction

Win32CaptureSample

A simple sample using the Windows.Graphics.Capture APIs in a Win32 application.

Table of Contents

Requirements

This sample requires the Windows 11 SDK (10.0.22000.194) and Visual Studio 2022 to compile. Neither are required to run the sample once you have a binary. The minimum verison of Windows 10 required to run the sample is build 17134.

Win32 vs UWP

This sample demonstrates using the Windows.Graphics.Capture APIs in a Win32 application. For the most part, the usage is the same, except for a few tweaks:

HWND or HMONITOR based capture

Win32 applications have access to the IGraphicsCaptureItemInterop interface. This interface can be found by QIing for it on the GraphicsCaptureItem factory:

#include <winrt/Windows.Graphics.Capture.h>
#include <windows.graphics.capture.interop.h>
#include <windows.graphics.capture.h>

namespace winrt
{
    using namespace Windows::Graphics::Capture;
}

// Obtaining the factory
auto interopFactory = winrt::get_activation_factory<
    winrt::GraphicsCaptureItem, 
    IGraphicsCaptureItemInterop>();

winrt::GraphicsCaptureItem item{ nullptr };

// Creating a GraphicsCaptureItem from a HWND
winrt::check_hresult(interopFactory->CreateForWindow(
    hwnd, 
    winrt::guid_of<winrt::GraphicsCaptureItem>(), 
    winrt::put_abi(item)));

// Creating a GraphicsCaptureItem from a HMONITOR
winrt::check_hresult(interopFactory->CreateForMonitor(
    hmon, 
    winrt::guid_of<winrt::GraphicsCaptureItem>(), 
    winrt::put_abi(item)));

This sample makes uses a collection of common header files which contains helpers for GraphicsCaptureItem creation.

Using the GraphicsCapturePicker

Win32 applications may also use the GraphicsCapturePicker to obtain a GraphicsCaptureItem, which asks the user to do the selection. Like other pickers, the GraphicsCapturePicker won't be able to infer your window in a Win32 application. You'll need to QI for the IInitializeWithWindow interface and provide your window's HWND.

#include <winrt/Windows.Graphics.Capture.h>
#include <shobjidl_core.h>

namespace winrt
{
    using namespace Windows::Graphics::Capture;
}

auto picker = winrt::GraphicsCapturePicker();
auto initializeWithWindow = picker.as<IInitializeWithWindow>();
winrt::check_hresult(initializeWithWindow->Initialize(hwnd));
// The picker is now ready for use!

Create vs CreateFreeThreaded

When a Direct3D11CaptureFramePool is created using Create, you're required to have a DispatcherQueue for the current thread and for that thread to be pumping messages. When created with Create, the FrameArrived event will fire on the same thread that created the frame pool.

When created with CreateFreeThreaded, there is no DispatcherQueue requirement. However, the FrameArrived event will fire on the frame pool's internal thread. This means that the callback you provide must be agile (this is usually handled by the language projection).

Points of interest

The code is organized into a couple of classes:

  • App.h/cpp handles the basic logic of the sample, as well as setting up the visual tree to present the capture preview.
  • SampleWindow.h/cpp handles the main window and the controls.
  • SimpleCapture.h/cpp handles the basics of using the Windows.Graphics.Capture API given a GraphicsCaptureItem. It starts the capture and copies each frame to a swap chain that is shown on the main window.
  • CaptureSnapshot.h/cpp shows how to take a snapshot with the Windows.Graphics.Capture API. The current version uses coroutines, but you could synchronously wait as well using the same events. Just remember to create your frame pool with CreateFreeThreaded so you don't deadlock!

win32capturesample's People

Contributors

chrisguzak avatar robmikh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

win32capturesample's Issues

I created simple helper function to snapshot window bassed on HWND and I have questions

Hello,
Bassed on this source file:
https://github.com/robmikh/Win32CaptureSample/blob/master/Win32CaptureSample/CaptureSnapshot.cpp

I remix it, and created from it this function:

struct CapturedData
{
	byte* pBts = nullptr; // byte array of the pixels 
	unsigned pBtsSize = 0; // The size of the byte array
	int xSize = 0; // weight of the frame
	int ySize = 0;	// height of the frame
};

bool WinRtTakeSnapshot(
	winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice& device,
	HWND hwndTarget,
	CapturedData* capturedData)
{

	using namespace winrt;

	using namespace Windows;
	using namespace Windows::Foundation;
	using namespace Windows::System;
	using namespace Windows::Graphics;
	using namespace Windows::Graphics::Capture;
	using namespace Windows::Graphics::DirectX;
	using namespace Windows::Graphics::DirectX::Direct3D11;
	using namespace Windows::Foundation::Numerics;
	using namespace Windows::UI;
	using namespace Windows::UI::Composition;

	auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(device);
	com_ptr<ID3D11DeviceContext> d3dContext;
	d3dDevice->GetImmediateContext(d3dContext.put());


	GraphicsCaptureItem item = CreateCaptureItemForWindow(hwndTarget);

	auto framePool = Direct3D11CaptureFramePool::CreateFreeThreaded(
		device,
		DirectXPixelFormat::B8G8R8A8UIntNormalized,
		1,
		item.Size());
	auto session = framePool.CreateCaptureSession(item);


	auto working = true;
	auto success = false;

	framePool.FrameArrived([session, d3dDevice, d3dContext, capturedData, &working,&success](auto& framePool, auto&)
		{


			auto frame = framePool.TryGetNextFrame();
			auto frameTexture = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());


			// Make a copy of the texture
			D3D11_TEXTURE2D_DESC desc = {};
			frameTexture->GetDesc(&desc);

			desc.Usage = D3D11_USAGE_STAGING;//D3D11_USAGE_DEFAULT;
			desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
			desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
			desc.MiscFlags = 0;

			desc.MipLevels = 1;
			desc.ArraySize = 1;
			desc.SampleDesc = { 1,0 };
			desc.BindFlags = 0;

			com_ptr<ID3D11Texture2D> textureCopy;
			if (d3dDevice->CreateTexture2D(&desc, nullptr, textureCopy.put()) != S_OK)
			{
				working = false;
				return;
			}

			d3dContext->CopyResource(textureCopy.get(), frameTexture.get());

			// map the texture
			D3D11_MAPPED_SUBRESOURCE mapInfo;
			ZeroMemory(&mapInfo, sizeof(D3D11_MAPPED_SUBRESOURCE));

			HRESULT hr = d3dContext->Map
			(
				textureCopy.get(),
				0,  // Subresource
				D3D11_MAP_READ,
				0,  // MapFlags
				&mapInfo
			);
			if (hr != S_OK)
			{
				working = false;
				return;
			}

			capturedData->xSize = mapInfo.RowPitch / 4;
			capturedData->ySize = mapInfo.DepthPitch / mapInfo.RowPitch;
			capturedData->pBtsSize = mapInfo.DepthPitch;
			capturedData->pBts = new unsigned char[mapInfo.DepthPitch + 1];


			memcpy(capturedData->pBts, mapInfo.pData, mapInfo.DepthPitch * sizeof(unsigned char));

			d3dContext->Unmap(textureCopy.get(), 0);
			//textureCopy.get()->Release();

			// End the capture
			session.Close();
			framePool.Close();

			working = false;
			success = true;

			return;

		});

	session.StartCapture();

	while (working);
	
	return success;

}

The function gets HWND and return CapturedData struct that points to the pixels data.

Questions:

  1. I had to disable the line textureCopy.get()->Release(); because If I did not disable, it crashed
    image

Does the API release the textrue for me and this is why it throw the exception? If not than how to release the resource without getting crash?

  1. I did it right? I closed any resource after the function finished?

Thanks

Graphics Capture doesn't work when running as different user?

Been a while, but it's me again. Hopefully I didn't miss anything obvious this time.

The scenario is the following:
A user of my application is using a standard user account for daily use, but needs to run my application as administrator sometimes. They are launching the application from their standard account, but as the separate admin account (as opposed to straight elevating from an admin account).

In this scenario, Graphics Capture appears to be unavailable. Win32CaptureSample crashes, but this is recoverable by catching exceptions when calling GraphicsCaptureSession::IsSupported().
From what I've observed, it throws winrt::hresult_error (0x80070424, "Service does not exist" afaik) on Windows 11 and std::bad_alloc on Windows 10 (haven't gone through all major versions though). The latter threw me off as I was only catching winrt::hresult_error in my app, which seemed to be good enough on older versions of Windows that didn't support Graphics Capture.

I suppose I can at least not crash with this, but I've been wondering if this is intentional. Guess the desktop and windows of another user may be inaccessible here? The way it fails is a bit unexpected though, and Desktop Duplication still works fine.

I don't disagree if the answer is just "don't do that". Their case here is that they have things in the chain that need admin (Steam with some launchers apparently) and my application is affected down the line (SteamVR as another user won't connect to my app).
Admin account just elevating when necessary works fine, of course.

This more of an API question again, I suppose (unless you want to catch this in the sample), but I'm thankful that you can be reached through this project.

Desktop Duplication API over Remote Desktop in Windows 11

This is not really related to this project per se, but I don't really know where to fill this up; I have learned about this Windows Graphics Capture API only after countless hours of trial and error for getting the older Desktop Duplication API to work over Remote Desktop under Windows 11 (build 22000.856 and 22000.1042). Of course, I have used the official sample which works just fine when at the console, as well as in Windows 10, both when at the console and when using remote desktop. I wasn't able to find any mention of the API being deprecated for this use case, so I presume it is a bug introduced by some Windows 11 version? Do you have any insight on this? I'd happily use Windows Graphics Capture, but I need to be able to capture the secure desktop and access the list of updated rectangles.

Thanks for the great tips and awesome project!

Question: How to bring down GPU usage without lowering FPS?

When capturing a full screen sized window (1440p in my case), GPU usage goes high up to >80% on the integrated GPU. ~10% is used by CopyResource and the other 70% is used by DWM for frame rendering. Questions:

  1. Why to re-render if the content is already rendered?
  2. Is there a way to get the already rendered texture? (with something like DwmDxGetWindowSharedSurface )

Desktop duplication vs Windows Graphics capture?

Hi (Barev) @robmikh

  • Is there any differences between Desktop duplication and this API?

  • Using desktop duplication force you to have an monitor plugged into the GPU, in order to capture frames. Is the requirement the same for Windows Graphics capture? So my goal is to use it on a "headless machine".

How to enable isWin32ProgrammaticPresent for capturing without capturePicker?

Hi,

Just want to start off by saying that this sample is really great and really helped me get started with the API! Thanks you so much!

Background

I am a bit new to the area and this might be a dumb question.

I was stuck trying to use App::StartCapture(HWND) and App::StartCapture(HMONITOR) to start programmatic capturing without using the graphics picker. The error I keep getting was "Interface Not Support" while creating the capture item and was stuck for a few month :( I also made some mistakes detailed later.

I gave up and started testing using the capturePicker, that had no problems. But I really wanted create captureItems without using the the pop up window of capture picker.

I found some confusing/conflicting info online elsewhere and want to just clarify.

I am using the latest Windows SDK 10.0.19041.0 and it seems that I only still have Version 7 of L"Windows.Foundation.UniversalApiContract". I should have saw this and realized my mistakes...

    auto isWin32ProgrammaticPresent = winrt::ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 8);

Question

Is Win32Programmatic capturing actually supported today? (i.e. I should be able to use App::StartCapture(HWND) and not limited to use capturePicker)

If so:
what could I be doing wrong and where should I look?

If not:
Was it supported in the past and got removed?
Will it be supported in the future? If not, maybe the deprecated code should be removed to avoid confusion?

Thank you in advance!

Access Violation on GraphicsCaptureSession.IsCursorCaptureEnabled

Using this command results in
0xC0000005: Access violation reading location 0x0000000000000000.

I tried it by adding it in SimpleCapture.cpp like so:

    m_framePool = winrt::Direct3D11CaptureFramePool::Create(m_device, m_pixelFormat, 2, m_item.Size());
    m_session = m_framePool.CreateCaptureSession(m_item);
    m_session.IsCursorCaptureEnabled(false);                //<------------------------ this doesnt work
    m_lastSize = m_item.Size();
    m_framePool.FrameArrived({ this, &SimpleCapture::OnFrameArrived });

Following also give the same exception:
auto isCursorCaptureEnabled= m_session.IsCursorCaptureEnabled();

HDR Support

Currently the hdr branch exposes the ability to configure the pixel format for HDR capture. The only thing missing right now is snapshot support, currently it defaults to SDR.

Capture frame rate

Hello ... this is more a question than issue ... is there any way to configure the frame rate at which the SDK will deliver frames? Right now ( testing on nvidia card ) it delivers frames at 60fps. I tried configuring the vsync of my card and decreased it in half but still the same. I do not want to drop samples on my own because this way quality may suffer especially given these are textures and there is no easy way to tell if the texture is unique or same as previous. Any idea if this can be done ?

is OnFrameArrived return such as DXGI_OUTDUPL_FRAME_INFO(LastPresentTime,LastMouseUpdateTime)

hi,I'm used dxgi to capture the windows, but it draw cursor on the texture2d too slow,and for about 6ms,with hand cursor it
will go up to 200ms.code sample below

// D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.Width = m_outDesc.ModeDesc.Width;
desc.Height = m_outDesc.ModeDesc.Height;
desc.Format = m_outDesc.ModeDesc.Format;
desc.ArraySize = 1;
desc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_RENDER_TARGET;
desc.SampleDesc.Count = 1;
desc.MipLevels = 1;
desc.CPUAccessFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
hr = pD3DDev->CreateTexture2D(&desc, NULL, ppTex2D);

if (FAILED(hr) || ppTex2D == nullptr) {
    printf("pD3DDev->CreateTexture2D error\n");
    break;
}
printf("time microsecond1: %lld\n", std::chrono::duration_cast<std::chrono::microseconds>(chrono::steady_clock::now() - lastFrameTime).count());
// Copy image into GDI drawing texture
pCtx->CopyResource(lGDIImage, lAcquiredDesktopImage);
// Draw cursor image into GDI drawing texture
CComPtrCustom<IDXGISurface1> lIDXGISurface1;
hr = lGDIImage->QueryInterface(IID_PPV_ARGS(&lIDXGISurface1));
if (FAILED(hr))
	break;
CURSORINFO lCursorInfo = { 0 };
lCursorInfo.cbSize = sizeof(lCursorInfo);
auto lBoolres = GetCursorInfo(&lCursorInfo);
if (lBoolres == TRUE)
{
	if (lCursorInfo.flags == CURSOR_SHOWING)
	{
		auto lCursorPosition = lCursorInfo.ptScreenPos;
		auto lCursorSize = lCursorInfo.cbSize;
		HDC  lHDC;
        printf("time microsecond2: %lld\n", std::chrono::duration_cast<std::chrono::microseconds>(chrono::steady_clock::now() - lastFrameTime).count());
		lIDXGISurface1->GetDC(FALSE, &lHDC);
		DrawIconEx(
			lHDC,
			lCursorPosition.x,
			lCursorPosition.y,
			lCursorInfo.hCursor,
			0,
			0,
			0,
			0,
			DI_NORMAL | DI_DEFAULTSIZE);
        printf("time microsecond3: %lld\n", std::chrono::duration_cast<std::chrono::microseconds>(chrono::steady_clock::now() - lastFrameTime).count());
		lIDXGISurface1->ReleaseDC(nullptr);//too slow
	}
}
printf("time microsecond4: %lld\n", std::chrono::duration_cast<std::chrono::microseconds>(chrono::steady_clock::now() - lastFrameTime).count());
// Copy image into CPU access texture
pCtx->CopyResource(*ppTex2D, lGDIImage);

log

time microsecond1: 19102
time microsecond2: 28896
time microsecond3: 46015
time microsecond4: 146072
time microsecond5: 287259
time microsecond1: 12035
time microsecond2: 22040
time microsecond3: 33243
time microsecond4: 124891
time microsecond5: 248231

and I find windows graphics capture can capture cursor,but there is some problem. it can't detect the image change or cursor change(such as LastPresentTime,LastMouseUpdateTime),so I can't filter the duplicate frames.Is there any other way?thanks

How to use only the snapshot function to an application?

Hello, I want to create an application in C ++
that captures a snapshot of the game screen at each interval.
This example was the only one that worked in games.
Only with the game's HWND does it create a snapshot of the game, even if the game window is inactive.
My problem is that I am not able to extract just the piece of code that creates the snapshots.
Would you help me?
I just wanted an example of how to create a snapshot of a game's HWND.
To then analyze snapshot.png with OpenCV.

GraphicsCaptureItem.Closed Event not firing

Hi,
first of all thank you for making this sample project.

I used your example to create a similar project (C++/Win32) with two notable exceptions:

  • I am not using Create() but rather winrt::Direct3D11CaptureFramePool::CreateFreeThreaded() and
  • I dont have any UI stuff, my entire Capturer is one file/class

Now the event OnFrameArrived works and gets triggered and I am able to use it.
But the event GraphicsCaptureItem.Closed doesn't get triggered when I close the Window.

I bind it like so:
m_itemClosedRevoker = m_item.Closed(winrt::auto_revoke, { this, &MyCapturer::OnCaptureItemClosed });
I also tried just this:
m_item.Closed({ this, &MyCapturer::OnCaptureItemClosed });
I use the preinstalled 3DViewer App as Window for testing.

I know that in your project the OnCaptureItemClosed works, could it be that RegisterWindowClass is necessary for that to work ? Do you might have any idea as to why this event wont fire (while the other one works as expected) ?

Take Snapshot button crashes the application

I am running the code (Debug X64 both with VS2019 and VS2022), and it crashes when I click on the Take Snapshot button. The crash happens in:
auto file = co_await m_savePicker.PickSaveFileAsync();
I've seen people reporting crashes in the FileSavePicker dialog, but the reported tickets have been closed with the advice to Initialize the object with Window handle, which you already do:
window.InitializeObjectWithWindowHandle(savePicker);
The CapturePicker however does work, but only when indeed you initialize it with the window handle.
It seems there is still something wrong with the FileSavePicker.

Capture gets offset when window changes border style

I know this pretty much on the Graphics Capture API implementation and not this sample, but I really have more hope in this ever getting read here than anywhere else to be honest.

The gist is that the window captures can be permanently offset when some border style changes happen. By having an application switch into "fullscreen" for example, where it'd remove the window borders temporarily. This usually results in the window in the capture texture being offset to the right by a couple of pixels, with the right end being cut off. Other times there's a padding around the window except at the top side or all around. This offset stays for the rest of the capture session unless some other border changes occur. It doesn't go back to normal for the windowed appearance, however.
If I had to guess, it might be using the window rect with the shadows in them after the window decorations re-appear.

Okay, to make this a little bit more relevant to this repository: What would be the recommended way to deal with this?
What kind of works is recreating the whole capture session when I detect capture frame's content size to not match the window's DWM frame bounds. Might be overkill, though.
Is there a better way to handle it?

Oh and thanks a lot for this sample code! It's been very helpful to me.

Windows graphics capture vs DDA?

This is more of a question because I don't have somewhere else to ask, and the info about WindowsGraphicsCapture underlying technology seems scarce, what are the advantages & drawbacks of using either over the other, especially performance wise, also can Windows GraphicsCapture be used with hardware encoders like Nvenc and so on the same way DDA can be used, finally is there a difference between their D3d11 & 12 support rn for FSE games?

Convert frame with FFMPEG

Hi @robmikh

One question: do you know how i can access the raw image data in order to encode it with FFMPEG? I assume this has to be done as soon as a new frame has arrived. Which will be in the function "OnFrameArrived". Do i get it from the backbuffer? Please guide me.

void SimpleCapture::OnFrameArrived(winrt::Direct3D11CaptureFramePool const& sender, winrt::IInspectable const&)
{
    auto swapChainResizedToFrame = false;

    {
        auto frame = sender.TryGetNextFrame();
        swapChainResizedToFrame = TryResizeSwapChain(frame);

        winrt::com_ptr<ID3D11Texture2D> backBuffer;
        winrt::check_hresult(m_swapChain->GetBuffer(0, winrt::guid_of<ID3D11Texture2D>(), backBuffer.put_void()));
        auto surfaceTexture = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
        // copy surfaceTexture to backBuffer
        m_d3dContext->CopyResource(backBuffer.get(), surfaceTexture.get());
        
    }

    DXGI_PRESENT_PARAMETERS presentParameters{};
    m_swapChain->Present1(1, 0, &presentParameters);

    swapChainResizedToFrame = swapChainResizedToFrame || TryUpdatePixelFormat();

    if (swapChainResizedToFrame)
    {
        m_framePool.Recreate(m_device, m_pixelFormat, 2, m_lastSize);
    }
}

Capturing File Explorer Window NOT Possible

It seems that Windows.Graphics.Capture is NOT able to capture any file explorer window.

This also includes cases when in some XY application one clicks on Save As or Open File and then the file explorer appears.

It seems to me as if the file explorer is a very special beast and not like "normal" applications, it appears to be much more integrated with internal Windows stuff and maybe because of that its not capturable.

Will it ever be capturable (within the Windows.Graphics.Capture API) , is there some work on that field ?

Audio?

Hey Rob

Thanks for making this sample code, Windows.Graphics.Capture is a very exciting API and I'm eagerly awaiting to see any new updates.

The biggest question I have about this is, from an application capture perspective, is what to do about audio?

Do you know of any method to capture a single applications audio output out side of creating a driver?

HWND Capture returns empty texture if using CreateFreeThreaded.

Hi. Thank you for such a helpful sample project.

I am building a dll that provides functionality to capture monitor and HWND output (It's similar to the SimpleCapture class in the sample). It's was working well until I decided to switch to using "CreateFreeThreaded" due to the project using the dll having the UI on the main thread. For some reason, the HWND capture stops working when it's not run on the main thread. I receive a new texture in the callback function, but all the pixels have the value 0.

I tried doing the same on the Win32CaptureSample by changing to CreateFreeThreaded. It works on the sample project. The difference in my dll project is that instead of outputting to the back buffer, I copy the texture to a staging texture. It does not fail anywhere, but maybe it has something to do with it when running on a worker thread?

Is there anything I need to consider when grabbing from HWND on a worker thread?

Thanks
Martin

Hide Mouse Cursor

Hello,
is it possible to wrap this code to be called from JavaScript, we are interested to export the hide cursor from capture function but it seems that we can't exported it alone it should be attached to a capture session.
I just wanna to know if it's possible to export the hide cursor function alone.
Best Regards
Lafi RAED

StartCapture and RPC errors

I have a question, which I unfortunately can ask with partial detail. In certain specific scenarios (generally the API normally works reliably) I am seeing IGraphicsCaptureSession::StartCapture producing internal exception RPC_S_SERVER_UNAVAILABLE or RPC_S_CALL_FAILED and then the same HRESULT is returned from the API function call.

I wonder if you maybe have some comments about what could be causing this and maybe certain unobvious API limitations?

I am expecting this might be hitting something known since as I mentioned there is little additional info I can give. As far as I understand this does not happen with first session started, instead this problem comes up with recurring and/or concurrent sessions for the same graphics item. One another potential problem might be an unknown threading/apartment status os the caller, the calls could be made on weird threads.

GraphicsCapturePicker breaks Windows Explorer after display is unplugged

System Info: Windows 10 Pro x64 10.0.19041 running on Lenovo L540
Visusal Studio 2019 V16.8.2
Windows SDK: 10.0.19041.0
Platform Toolset: VS 2019 (v142)
Microsoft.Windows.CppWinRT nuget package v2.0.201217.4

Laptop has 2 external displays plugged in.

Repro Steps:

  1. Get and build Win32CaptureSample-master
  2. Start the app and press "Open Picker" to show the GraphicsCapturePicker popup
  3. Unplug one of the external displays
  4. Press cancel on the GraphicsCapturePicker popup

At this point Windows Explorer is in a bad state. Clicking Windows Icon in the task bar does not bring up the start menu. Right clicking any of the app icons in the task bar does not bring up the context menu. Clicking the "Open Picker" button on the Win32CaptureSample app brings up the GraphicsCapturePicker but with no content (see attached image). It was necessary to restart Windows Explorer from the Task Manager in order to recover.

Running the same steps as above with only 1 external display will result in Win32CaptureSample throwing an exception when the display is unplugged (see attached image)
CaptureSampleException
CaptureSampleBlankPicker

.

The application crashes when calling IsBorderRequired(false/true)

After creating the session via m_session = m_framePool.CreateCaptureSession(m_item); and setting the border requirement:
m_session.IsBorderRequired(false); the application crashes with the following exception

Exception thrown at 0x00007FF63ACA7E6C in Win32CaptureSample.exe: 0xC0000005: Access violation reading location 0x0000000000000000.

Is this an API bug or the function should be called somewhere else outside of SimpleCapture::SimpleCapture() constructor?

Parts of window are NOT being captured

I tried Paint, 3DViewer and they all exhibit this behaviour. I uploded the video showing the problem:

WindowGraphicsCapturer

As you can see, we don't capture everything, clicking on Help or View doesn't get captured.

Is there some solution to this problem ?

Simple recorder is giving error in WinUI3

I added the code from simplerecord repo to my project when i run its giving error please help. Im using an IDirect3DDevice _device
_framePool = Direct3D11CaptureFramePool.CreateFreeThreaded( _device, DirectXPixelFormat.B8G8R8A8UIntNormalized, 1, size);
System.InvalidCastException: 'Specified cast is not valid. How to write the frames to a video files with a canvas device?

Unable to capture window which tab is removed from the taskbar

I want to capture my window which is not shown on the taskbar. I remove the window's button from the taskbar with this code snippet:

ITaskbarList* pTaskbarList;
auto hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (void**)&pTaskbarList);
pTaskbarList->DeleteTab(hWindow);

The following error happens when trying to capture the window: The parameter is incorrect.
However, I'm able to capture the window if I create a hidden window and make it the parent of the capturable window, this way it is not shown on the taskbar.
Source:
https://docs.microsoft.com/en-us/windows/win32/shell/taskbar

The Shell creates a button on the taskbar whenever an application creates a window that isn't owned. To ensure that the window button is placed on the taskbar, create an unowned window with the WS_EX_APPWINDOW extended style. To prevent the window button from being placed on the taskbar, create the unowned window with the WS_EX_TOOLWINDOW extended style. As an alternative, you can create a hidden window and make this hidden window the owner of your visible window.

Adding/removing the corresponding styles also makes the window uncapturable. So is creating a hidden window the only way to achieve both capturability and invisibility on the taskbar?

Win10 18362 lock screen issue

Hello, I found that in the low version of Win10 lock screen will stop the screenshot, but in the high version of the system lock screen can be captured normally,how to take screenshots normally after locking the screen on 18362 verion?

Stack buffer overrun error in GraphicsCapture.dll when closing a capture session while multiple captures are active (Windows 10 1809)

As the title suggests, I've run into an issue with multiple captures running at once in a single process. But only on Windows 10 1809 (and perhaps earlier), not later.
To be sure I've gone ahead and checked this with fresh VMs of 1809, 1903, 1909, 2004 and 20H2 as well. It only crashes on the 1809 systems (real and VM).
From what I've read this is probably just GraphicsCapture.dll doing a fail-fast instead of a real buffer overrun, but I'm not really an expert on that subject... it crashes, let's say that.

I've had this issue before when just trying to stop a capture, but was able to seemingly circumvent it by adding a short sleep between closing the session and the frame pool. Now that I want to restart the capture on the fly sometimes as a workaround for #26, this proved to be not actually that reliable once a new session was to be set up again right away. Even worse is a situation with two captures on the same target, where such a restart would be triggered twice at the same time, which almost always causes the crash on 1809.

Supporting 1809 likely doesn't make much sense anymore, but I don't like dropping support for no reason either. That aside, I thought I should rather make sure I'm not doing something terribly wrong and newer versions just swallow up my mistake here.

I've forked this repo and modified it to spawn two captures instead of just one, using the same capture item (different ones have the same effect, though). The "Take Snapshot" button was turned into a "Restart Capture" button. The crash can be triggered as long as the CaptureFrame is retrieved in the FrameArrived event, even if it's not doing anything and just releases the frame right away.
Pressing the "Restart Capture" button a couple of times is a surefire way to crash the application on the affected OS versions, but simply using Stop Capture works as well, just more rarely.
The repo is here: https://github.com/elvissteinjr/Win32CaptureSample
While that's not exactly how I'm implementing it in the real project, it's a minimal modification that has the same effect.

Am I doing something terribly wrong? Are there some extra multithreaded considerations to be applied here (but frames are all arriving on the same thread through the DispatcherQueue, aren't they?)? Or is this just something that got fixed in later versions of Windows and I'll have to deal with it? I've seen the ID3D11Multithread recommendation on the C# sample, but that's not helping here.

Oh and in the real project it's one thread per capture. Everything seems to be working fine apart from this issue so I doubt it, but I don't need to synchronize access to the Graphics Capture API when every thread is working with its own set of data, do I?

Thank you for your time. This one's been kind of a bother.

Capture permissions Windows 11

How is SYSTEM-less secure desktop capture coming along? :D

We're hoping to find something that can allow us to capture the secure desktop without running as SYSTEM, and I got excited for a second when I saw the below docs

https://docs.microsoft.com/en-us/uwp/api/windows.graphics.capture.graphicscaptureaccess

I see the initial intent is to allow borderless capture,

Seems like you guys are slowly allowing Windows Graphics Capture to be more flexible.

I would really love a pathway for capturing the secure desktop with running our thread as SYSTEM with DDA :)

Capturing Audio

Hey Rob

Thanks for making this sample code, Windows.Graphics.Capture is a very exciting API and I'm eagerly awaiting to see any new updates.

The biggest question I have about this is, from an application capture perspective, is what to do about audio?

Do you know of any method to capture a single applications audio output out side of creating a driver or hooking?

Performance of the Windows.Graphics.Capture API

I would like to ask you what performance do you get when using Widows.Graphics.Capture API ?

Here is how I measure the FPS coming into OnFrameArrived.

void SimpleCapture::OnFrameArrived(winrt::Direct3D11CaptureFramePool const& sender, winrt::IInspectable const&)
{
    std::atomic<std::chrono::system_clock::time_point> currentTime = std::chrono::system_clock::now();

    auto durationMilisecondsSinceLastFrame = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime.load() - lastFrameTime.load()).count();
    lastFrameTime = currentTime.load();  //add std::atomic<std::chrono::system_clock::time_point> lastFrameTime into SimpleCapture.h

    auto passFrameFPS = 1000 / durationMilisecondsSinceLastFrame;
...

Here are my results:

  1. This demo example, capturing Notepad++ my passFrameFPS is around 30FPS.

  2. Another Project, C++ Win32, capturing the monitor I also get around 30FPS.

I would like to know what is the performance other people get ?
Also, is there a way to increase the rate at which OnFrameArrived is invoked ?

Thanks

XAML island shows up in enumeration updates

When processing live window updates, a window related to XAML islands (I think?) makes it through the filtering process. Since this window does not show up during the initial enumeration, it seems to be that the window changes state after it is shown to something we filter out.

I noticed this with the Windows Terminal preview, but I'm guessing other XAML island applications will behave similarly. At least in the terminal case, the window is titled "DesktopWindowXamlSource". Terminal also caused a window called "PopupHost" to show up... I'm guessing that's related to the shell selection menu.

Here's what Spy++ sees when everything has settled:
image

The procedure entry point CreateDispatcherQueueController could not located on Windows 10, version 1607

Hi Team,
This Win32CaptureSample is a great example to learn and use Windows.Graphics.Capture API. It helps me to implement capturing other application window. Really appreciate you to create such great project.

Background
My desktop Windows application is using C++ and Windows APIs. And my app has been used by instructors in the classroom to collect votes from students. It's one functionality is to capture an image of other application window such as Power Point Slide or web browser window or Google slide... I have used Windows.Graphics.Capture APIs to implement this capture feature. It runs great on Windows10, version 19043.
One requirement is that my app should run on all versions of Windows 10. I Know that Windows.Graphics.Capture is only supported on Windows 10, version 1803 or above. On Windows 10, version 1803 below, it would be ok to not provide this capturing functionality, but we do need to be able to run my app on Windows 10, version 1803.

Question
How to configure Win32CaptureSample project not load DLLs of Windows.Graphics.Capture APIs at runtime if the app detects that Windows OS's version is below Windows 10, version 1803?
I tried to test the Win32CaprtureSample project on Windows 10, version 1607 machine. First of all, I built the Win32CaptureSample without any errors on this machine win10 1607, but when I ran under MSVC2017/2019 IDE, I got the following error:|
The procedure entry point CreateDispatcherQueueController could not located.
How to resolve this runtime error?

Here I have attached two screenshots, one is my win10 version 1607, the other is error message.
Thanks for your help and looking forward to your solution on this,
win10-version
error_to_launch

Why did I get black image (all pixel is 0x00)?

Dear Robbert,

Thanks for these sample code.

Here is my dll project:
https://github.com/SheenArtem/WinRT_WndCapture

I'm trying to make a window capture and access the pixel of the captured frame.

m_swapChain->Present1(1, 0, &presentParameters); works fine and displays correct image of the target window.

But the pixel data that I want to access are always 0x00.

So I get a black image at all time.

(I used the memory debug window to watch the memory location of source)

In the SimpleCapture.cpp, I added some code in OnFrameArrived() :
D3D11_TEXTURE2D_DESC desc;
surfaceTexture->GetDesc(&desc);
com_ptr<ID3D11Texture2D> CopyBuffer = CreateStageTexture2D(d3dDevice,
static_cast<uint32_t>(desc.Width),
static_cast<uint32_t>(desc.Height),
static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized));

m_d3dContext->CopyResource(CopyBuffer.get(), surfaceTexture.get());

D3D11_MAPPED_SUBRESOURCE mapped = {};
winrt::check_hresult(m_d3dContext->Map(CopyBuffer.get(), 0, D3D11_MAP_READ, 0, &mapped));
std::vector<byte> bits(desc.Width * desc.Height * 4, 0);
auto dest = bits.data();
auto source = reinterpret_cast<byte*>(mapped.pData);
for (auto i = 0; i < (int)desc.Height; i++)
{
memcpy(dest, source, desc.Width * 4);
source += mapped.RowPitch;
dest += desc.Width * 4;
}
m_d3dContext->Unmap(CopyBuffer.get(), 0);

And here's my method to create staging texture

inline auto
CreateTexture2D(
winrt::com_ptr<ID3D11Device> const& device,
const D3D11_TEXTURE2D_DESC* desc)
{
winrt::com_ptr<ID3D11Texture2D> texture;
winrt::check_hresult(device->CreateTexture2D(desc, nullptr, texture.put()));
return texture;
}

inline auto
CreateStageTexture2D(
winrt::com_ptr<ID3D11Device> const& device,
uint32_t width,
uint32_t height,
DXGI_FORMAT format)
{
D3D11_TEXTURE2D_DESC DeskTexD = {};
DeskTexD.Width = width;
DeskTexD.Height = height;
DeskTexD.Format = format;
DeskTexD.MipLevels = 1;
DeskTexD.ArraySize = 1;
DeskTexD.SampleDesc.Count = 1;
DeskTexD.SampleDesc.Quality = 0;
DeskTexD.Usage = D3D11_USAGE_STAGING;
DeskTexD.BindFlags = 0;
DeskTexD.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
DeskTexD.MiscFlags = 0;
return CreateTexture2D(device, &DeskTexD);
}

Did I miss some steps ?

Thanks again for the help.

Graphics Capture limits DXGI Desktop Duplication update frequency

Hi, it's me again. Hope this place is still good for reporting general Graphics Capture issues, as this once again isn't on the sample app itself.

My app supports both Desktop Duplication and Graphics Capture. With Desktop Duplication being able to report cursor updates instantly (1000 Hz mouse setting actually delivers 1000 updates per second) and working with exclusive fullscreen applications (on some APIs/games even at frame rates beyond the display's they're rendered to), it still has its use. As my application runs in VR with headsets having higher refresh rates than the still typical bog standard 60 Hz display, those extra frames contribute to a smoother output on that end.

I only recently noticed this, but it appears that using Graphics Capture does impose limits on Desktop Duplication updates. It doesn't matter which application is using Graphics Capture. Starting a capture from the sample affects my app for example. Once this happens, the maximum update rate seems to drop to whatever the primary display's refresh rate is.

I know this isn't exactly critical but I'm still slightly bummed about this side-effect. In any case I wanted to put it out there at least.

In case this depends on the setup, I'm currently running Windows 10 20H2 with an Nvidia card.
Don't have a test app for desktop at hand (for SteamVR, Desktop+ can show this behavior), but I suppose adding a frame counter to the DXGI Desktop Duplication Sample would do the trick, so I could do that if wanted.

I apologize if this one's out of place here, but it seems to be caused by Graphics Capture and I've had good experiences by actually getting responses here before so yeah, thanks!

WinSta0\\winlogon failed

in WinSta0\winlogon (Lock screen, ctrl+alt+del screen)

winrt::Windows::Graphics::Capture::GraphicsCaptureSession::IsSupported();
util::CreateCaptureItemForMonitor

failed

error message:
combase.dll ~~ ReturnHr(1) tid(xxxx) 8007024 ~service ...
winrt originate error 80040111 : 'Windows.Graphics.Capture.Server.CapturableItem'

but
IDXGIOutputDuplication::AcquireNextFrame

works.

Is there any way to make it work using winrt?

Help: Clarification

Hello @robmikh,
Lets say we have a screen size of 2x2 (2 columns x 2 rows) or 12x3 (with all the monitors being HD) and there is a full screen window spanned across the entire size of these screen setup(s). Is it fine/possible to capture the full screen window using windows graphics capture api and record? Your feedback is highly appreciated.

Thanks,
Muthu

How reliable is Windows Graphics Desktop Capture in replicating the monitor frames ?

Lets say that I have a person sitting in front of the monitor and at the same time I use the desktop capture api to store the frames in a video file.

Is it guaranteed that the screen that person sees correspond 1/1 to the video file ?

Or is it a case of screen being rendered by A and desktop capture renders the frames as a B and there may be differences (in framerate or quality) ?

If differences are possible - what may I do (with regards to the C++ desktop capture api) to eliminate any discrepancies, is it possible at all ?

Desktop Duplication / WGC Questions

Hi, I have a few questions that I'd like to post if you don't mind. I have been creating a streaming application that captures the desktop using Desktop Duplication, then encodes the texture with Media Foundation and sends the frames over the network. My questions are as follows

  • Are there any performance benefits of WGC compared to Desktop Duplication?
  • Can WGC capture games in fullscreen?
    • If so, can WGC capture games in fullscreen on another adapter than it was run from? I.e, if a game is run in fullscreen on a dedicated card on a laptop, and the capture application is run on the integrated GPU, will it work?
  • A big problem I am dealing with currently is when I capture external monitor plugged into my laptop, the texture will be on the other adapter and there is not much that can be done to access it currently besides copying to normal memory first, which I would assume has a massive impact on performance. Is there any other way? I know D3D12 has a shared heap feature, but as far as I know neither Desktop Duplication nor WGC support D3D12. Can you shed more light on what to do here?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.