Capture unity screen in native code using DirectX capture

I want to capture game in Native code using DirectX capture. I use staging buffer to capture the screen. But I only get black screen after capture. Any input on what I am doing wrong in code attached?

// Check out http://docs.unity3d.com/Documentation/Manual/NativePluginInterface.html
// for additional documentation about this process.

#include "UnityPlugin.h"
#include "GraphicsInclude.h"

#if _WIN32
#include "Capture/DXCapture.h"
#include <d3d11.h>
#include <DXGI.h>
#endif


#include <string>
#include <iostream>


#if _WIN32
// DirectX states
ID3D11Device* g_d3d_Device;
ID3D11DeviceContext* g_d3d_DeviceContext;
ID3D11RenderTargetView* g_renderTargetView[1];
ID3D11Texture2D* g_backBuffer;
#endif

// For now width and height are hardcoded
int width = 1280;
int height = 720;
int bpp = 4;

#pragma once

#pragma warning (push)

#if _MSC_VER && !__INTEL_COMPILER
// Disable warnings about macro re-definitions if we're using the DX SDK
// http://stackoverflow.com/questions/19336841/i-get-a-lot-of-macro-redefinition-when-using-directx-10
#pragma warning (disable: 4005)
#endif

#if _WIN32
#include <d3d11.h>
#endif

#pragma warning (pop)

typedef void(*FuncPtr)(const char *);

FuncPtr Debug;

static void DebugLog (const char* str)
{
#if UNITY_WIN
    OutputDebugStringA (str);   
    //Debug(str);
#else
    printf ("%s", str);
#endif
}

extern "C"
{
    EXPORT_API void SetDebugFunction(FuncPtr fp)
    {
        Debug = fp;
    }
}

// If exported by a plugin, this function will be called when graphics device is created, destroyed,
// and before and after it is reset (ie, resolution changed).
extern "C" void EXPORT_API UnitySetGraphicsDevice( void* device, int deviceType, int eventType )
{
    char log[256];

#if _WIN32
    ID3D11DepthStencilView* depthViews[1];
    ID3D11Resource* targetResource;
    D3D11_RENDER_TARGET_VIEW_DESC targetView;
    // Assign default values.
    g_d3d_Device = (ID3D11Device*)device;
    g_d3d_Device->GetImmediateContext(&g_d3d_DeviceContext);

    g_d3d_DeviceContext->OMGetRenderTargets(1, g_renderTargetView, depthViews);

    if (g_renderTargetView[0] == nullptr){
        DebugLog("No debug target view found\n");
    }

    g_renderTargetView[0]->GetResource(&targetResource);

    g_renderTargetView[0]->GetDesc(&targetView);

    sprintf(log, "Format is %d\n", targetView.Format);
    DebugLog(log);

    // Try to initialize screen capture methods.
    // We try them explicitly one by one until we find one that works

    DebugLog("Trying DirectX capture method\n");
    g_screenCapture = new DXCapture(g_d3d_Device, g_d3d_DeviceContext, targetResource, width, height, targetView.Format);
    if (!g_screenCapture->supported())
    {
        DebugLog("Cannot initialize DirectX capture method\n");
        delete g_screenCapture;
        g_screenCapture = NULL;
    }
    else
    {
        DebugLog("Using DirectX Capture method\n");
        goto foundCaptureMethod;
    }

    // at this point, couldn't find any capture methods
    DebugLog("Could not initialize any capture methods");

foundCaptureMethod:
    DebugLog("Initialize capture methods");

#endif


}


// If exported by a plugin, this function will be called for GL.IssuePluginEvent script calls.
// The function will be called on a rendering thread; note that when multithreaded rendering is used,
// the rendering thread WILL BE DIFFERENT from the thread that all scripts & other game logic happens!
// You have to ensure any synchronization with other plugin script calls is properly done by you.
extern "C" void EXPORT_API UnityRenderEvent ( int eventID )
{

        // Capture the frame using our current capture method
        const unsigned char* theFrame = g_screenCapture->capture();
        g_screenCapture->endCapture(); // Done with capture data

}

DXCapture.cpp

#include "DXCapture.h"

DXCapture::smile:XCapture(ID3D11Device* d3DDevice, ID3D11DeviceContext* d3DDeviceContext,
                                         ID3D11Resource* backbuffer,
                     int backbufferWidth, int backbufferHeight,
                                         DXGI_FORMAT format)
    : _d3D11Device(d3DDevice),
      _d3D11DeviceContext(d3DDeviceContext),
      _backbuffer(backbuffer),
      _backbufferWidth(backbufferWidth),
      _backbufferHeight(backbufferHeight),
          _format(format)
{
}

bool DXCapture::supported()
{
    try
    {
        // Create a staging resource
        D3D11_TEXTURE2D_DESC stagingTextureDesc;
        stagingTextureDesc.Width = _backbufferWidth;
        stagingTextureDesc.Height = _backbufferHeight;
        stagingTextureDesc.MipLevels = stagingTextureDesc.ArraySize = 1;
        //stagingTextureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
                stagingTextureDesc.Format = _format;
        stagingTextureDesc.SampleDesc.Count = 1;
        stagingTextureDesc.SampleDesc.Quality = 0;
        stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
        stagingTextureDesc.BindFlags = 0;
        stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
        stagingTextureDesc.MiscFlags = 0;

        if (!SUCCEEDED(_d3D11Device->CreateTexture2D(&stagingTextureDesc, NULL, &_stagingBuffer)))
            return false;

        return true;
    }
    catch (...)
    {
        return false; // Something went wrong, we can't set up DX capture
    }
}

CapturePixelFormat DXCapture::getCapturePixelFormat()
{
    return CAPTURE_PIXELFORMAT_R8G8B8A8; // Always
}

const unsigned char* DXCapture::capture()
{
    // Copy the frame to the staging buffer
    _d3D11DeviceContext->CopyResource(_stagingBuffer, _backbuffer);

    // Lock the staging buffer and post it to the host app for encoding
    D3D11_MAPPED_SUBRESOURCE mappedBuffer;
    HRESULT bufferMapResult = _d3D11DeviceContext->Map(_stagingBuffer, 0, D3D11_MAP_READ, 0, &mappedBuffer);
    if (SUCCEEDED(bufferMapResult))
    {
        unsigned char* pixel_bytes = (unsigned char*)mappedBuffer.pData;
        return pixel_bytes;
    }

    return NULL;
}

void DXCapture::endCapture()
{
    // Unmap this buffer, the application is done with the capture
    _d3D11DeviceContext->Unmap(_stagingBuffer, 0);
}

DXCapture::~DXCapture()
{
    if (_stagingBuffer != NULL)
    {
        _stagingBuffer->Release();
        _stagingBuffer = NULL;
    }
}

I know the issues. I should us D3D11_RTV_DIMENSION_TEXTURE2D for copyresource.

I tried using ResolveSubresource as per sample code from https://github.com/walbourn/directx-sdk-samples/blob/master/DirectXTK/Src/ScreenGrab.cpp but I am getting black frames on client side.

Can someone help me with this?

I try your method and use ScreenGrab, here is the code:

void App3Main::SaveScreenshot()
{
    auto file = ref new Platform::String(Windows::Storage::ApplicationData::Current->TemporaryFolder->Path->Data()) + "\\Screenshot.png";



    /*
    ComPtr<ID3D11Texture2D> backBuffer;
    DX::ThrowIfFailed(m_deviceResources->GetSwapChain()->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBuffer));
    */
  
    ID3D11RenderTargetView* targets[] = { nullptr, nullptr };
    m_sceneRenderer->GetContext()->OMGetRenderTargets(ARRAYSIZE(targets), targets, nullptr);
    D3D11_RENDER_TARGET_VIEW_DESC targetView;
    targets[0]->GetDesc(&targetView);
    ID3D11Resource* targetResource;
    targets[0]->GetResource(&targetResource);

    auto hResult = SaveWICTextureToFile(m_sceneRenderer->GetContext(), targetResource, GUID_ContainerFormatPng, file->Data());
}

Eventually, I succeeded. Good luck!!!