Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for MemoryMappedFile approach to retrieving captured image #33

Open
justinstenning opened this issue Oct 5, 2015 · 9 comments

Comments

@justinstenning
Copy link
Owner

Use the SharedMemory library to access captured image data in host process rather than IPC.

@MathewSachin
Copy link
Contributor

Can SharedMemory be used with EasyHook?

@MathewSachin
Copy link
Contributor

I am working on a cut-down version of your repository: https://github.com/MathewSachin/Direct3DHook
The Capturing process is now working fine. Thanks to your great work.
I understand that SharedMemory can make the Capturing faster.
Can you give me some directions on implementing the same? Please.

@remcoros
Copy link

Here's a (very specific) implementation using shared memory:

https://github.com/HearthstoneTracker/HearthstoneTracker/blob/master/Capture/Hook/DXHookD3D9SharedMem.cs

And the client: https://github.com/HearthstoneTracker/HearthstoneTracker/blob/master/HearthCap.Core/GameCapture/AutoCaptureEngine.cs#L675

Be ware though, this is pretty advanced stuff, with ring buffer and inter-process locking.

Also, this code is locked to the specific use case here. You'll have to examine it and re-create it to your use case.

Also 2: If you want to look at a real high performance capture engine. Look at OBS / obs-studio (oss, gpl licensed): https://github.com/jp9000/obs-studio

@justinstenning
Copy link
Owner Author

When I add it into this project I will be using my SharedMemory library referenced above to create a circular buffer (aka ring buffer) with enough room to store a few screenshots. This library hides all the complexity for you.

The publisher will be created within the injected library, and the reader will be opened in the host (e.g. TestScreenshot or whatever is being used). An example of how this is done can be found here: http://sharedmemory.codeplex.com/documentation and also there are client/server examples in the source of the project.

@justinstenning
Copy link
Owner Author

The example from the ShareMemory documentation:

using (var producer = new SharedMemory.CircularBuffer(name: "MySharedMemory", nodeCount: 3, nodeBufferSize: 4))
using (var consumer = new SharedMemory.CircularBuffer(name: "MySharedMemory"))
{
    // nodeCount must be one larger than the number
    // of writes that must fit in the buffer at any one time
    producer.Write<int>(new int[] { 123 });
    producer.Write<int>(new int[] { 456 });

    int[] data = new int[1];
    consumer.Read<int>(data);
    Console.WriteLine(data[0]);
    consumer.Read<int>(data);
    Console.WriteLine(data[0]);
}

Although this is all in the same process, providing that the name matches and the producer remains connected, the consumer can be in any process, no synchronisation/locking required.

You would be grabbing an IntPtr to the Direct3D surface/texture, then write that to the producer (using the appropriate size). The nodeBufferSize would also need to be set to the correct size.

@GeeWizWow
Copy link

Hey, bit of a necro : I

Was going to take look at implementing this approach, thought I'd ask before I started if you had made any progress on your end/ had any pointers?

Cheers 😄

@justinstenning
Copy link
Owner Author

@GeeWizWow sure. FYI I wrote a library to be used for this that you can use to help: https://github.com/spazzarama/sharedmemory

Provides a couple of supporting structures using MMF, eg ring-buffer, array

@GeeWizWow
Copy link

GeeWizWow commented Feb 24, 2021

Thanks, I was up and running in no time, after looking at the HearthstoneTracker implementation, I'm glad I didn't have to re-implement that from scratch, nice work!

Somewhat unrelated, but I've been looking at your code in this repo, and the Hearthstonetracker code posted above, and I can't figure out how you guys are getting thread safety when accessing resources from a single d3 device. Any attempts I make always end in D3 complaining about a single context being accessed across multiple threads, really basic example below with lock, am I missing anything?

lock (_lockObj) {
     _renderTarget.Device.ImmediateContext.CopyResource(_renderTarget, _otherTarget);
}

// Kick off a new background thread
ThreadPool.QueueUserWorkItem(new WaitCallback((o) => {

      lock(_lockObj) {
            // Fails
            _otherTarget.Device.ImmediateContext.MapResource(....)
      }
}));

Present();             

@justinstenning
Copy link
Owner Author

justinstenning commented Feb 25, 2021

@GeeWizWow we are using a shared resource to access the render target from another D3D device (we don't use the same device as you stated). You shouldn't need to change most of that code in order to implement your solution (see DXHookD3D11.cs). The copying of the RT remains unchanged, it is just what you do with the bytes when you get them that will differ.

i.e. everything remains the same within PresentHook except what happens in the call to ProcessCapture here https://github.com/spazzarama/Direct3DHook/blob/master/Capture/Hook/DXHookD3D11.cs#L509 and here https://github.com/spazzarama/Direct3DHook/blob/master/Capture/Hook/DXHookD3D11.cs#L514

Actually you don't need to edit DXHookD3Dxx.cs, instead just edit the ProcessCapture implementation within the BaseDXHook.cs: https://github.com/spazzarama/Direct3DHook/blob/master/Capture/Hook/BaseDXHook.cs#L194

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants