Search code examples
directxms-media-foundationsharpdxdxgi

SharpDX MapSubresource is vertically flipped C#


How can I flipped the SharpDX.Databox without converting it to bitmap? I'm making a screen recording using SharpDX and Media foundation. Below is the code on how I get the Databox.

mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0,SharpDX.Direct3D11.MapMode.Read, SharpDX.Direct3D11.MapFlags.None);

But when I passed the mapSource in mediafoundation.net I produced a vertical video.

        IMFSample sample = null;
        IMFMediaBuffer buffer = null;

        IntPtr data = new IntPtr();
        int bufferMaxLength;
        int bufferCurrentLength;

        int hr = (int)MFExtern.MFCreateMemoryBuffer(frameSizeBytes, out buffer);

        if (Succeeded(hr)) hr = (int)buffer.Lock(out data, out bufferMaxLength, out bufferCurrentLength);
        if (Succeeded(hr))
        {

            hr = (int)MFExtern.MFCopyImage(data, videoWidth * BYTES_PER_PIXEL, mapSource.DataPointer, videoWidth * BYTES_PER_PIXEL, videoWidth * BYTES_PER_PIXEL, videoHeight);
        }
        if (Succeeded(hr)) hr = (int)buffer.Unlock();
        if (Succeeded(hr)) hr = (int)buffer.SetCurrentLength(frameSizeBytes);
        if (Succeeded(hr)) hr = (int)MFExtern.MFCreateSample(out sample);
        if (Succeeded(hr)) hr = (int)sample.AddBuffer(buffer);
        if (Succeeded(hr)) hr = (int)sample.SetSampleTime(frame.prevRecordingDuration.Ticks);//(TICKS_PER_SECOND * frames / VIDEO_FPS);
        if (Succeeded(hr)) hr = (int)sample.SetSampleDuration((frame.recordDuration-frame.prevRecordingDuration).Ticks);
        if (Succeeded(hr)) hr = (int)sinkWriter.WriteSample(streamIndex, sample);
        if (Succeeded(hr)) frames++;

        COMBase.SafeRelease(sample);
        COMBase.SafeRelease(buffer);

enter image description here


Solution

  • In your code there is a mistake in code with MFCopyImage. According MFCopyImage function you must set _In_ LONG lDestStride, _In_ const BYTE *pSrc, _In_ LONG lSrcStride, - lDestStride and lSrcStride - is width of memory for storing one line of pixels - your computing videoWidth * BYTES_PER_PIXEL is not correct, because for Windows RGB format stride can be widther than videoWidth * BYTES_PER_PIXEL. You must compute destination stride by function MFGetStrideForBitmapInfoHeader, source stride you can get from you image source code - I do not know you code, but for my project I used

    D3D11_MAPPED_SUBRESOURCE resource;
                    UINT subresource = D3D11CalcSubresource(0, 0, 0);
                    ctx->Map(mDestImage, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
                    LOG_INVOKE_MF_FUNCTION(MFCopyImage,
                        aPtrData,
                        mStride,
                        (BYTE*)resource.pData,
                        resource.RowPitch,
    
    • RowPitch.

    Regards.

    P.S. Destination stride mStride can be negative - it means that it needs write from last line to the first. It can done by the next changing of destination pointer - aPtrData += (mHeight - 1)*mStride;