SharpDX MapSubresource перевернут по вертикали C#

Как я могу перевернуть SharpDX.Databox, не преобразовывая его в растровое изображение? Я делаю запись экрана, используя SharpDX и Media Foundation. Ниже приведен код того, как я получаю Databox.

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

Но когда я передал mapSource в mediafoundation.net, я создал вертикальное видео.

        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);

введите здесь описание изображения


person kripto    schedule 18.05.2017    source источник


Ответы (1)


В вашем коде есть ошибка в коде с MFCopyImage. Согласно функции MFCopyImage вы должны установить _In_ LONG lDestStride, _In_ const BYTE *pSrc, _In_ LONG lSrcStride, - lDestStride и lSrcStride - это ширина памяти для хранения одной строки пикселей - ваше вычисление videoWidth * BYTES_PER_PIXEL неверно, потому что для формата Windows RGB шаг может быть шире, чем videoWidth * BYTES_PER_PIXEL. Вы должны вычислить шаг назначения с помощью функции MFGetStrideForBitmapInfoHeader, исходный шаг вы можете получить из исходного кода вашего изображения - я не знаю вашего кода, но для своего проекта я использовал

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,
  • Строка.

С Уважением.

P.S. Шаг назначения mStride может быть отрицательным - это означает, что нужно писать с последней строки на первую. Это можно сделать следующим изменением указателя назначения - aPtrData += (mHeight - 1)*mStride;

person Evgeny Pereguda    schedule 18.05.2017
comment
Я использую С#, я думаю, вы программист на С++. Но я попробую ваше решение. и дайте вам знать результат Спасибо. - person kripto; 18.05.2017
comment
Вы используете MFExtern - это просто оболочка для отображения C-функции MediaFoundation на код C#. Попробуйте найти MFExtern.MFGetStrideForBitmapInfoHeader. - person Evgeny Pereguda; 18.05.2017
comment
Извините, но я все еще не могу сделать свой вывод правильным. Я не очень хорошо разбираюсь в использовании Media Foundation. Источник изображения уже инвертирован, кстати, к моему сообщению есть вложение, я просто забыл переименовать ссылку. Вы можете увидеть это внизу. Я действительно могу сделать это правильно, используя - person kripto; 18.05.2017
comment
начальная строка пикселей хранится в начале сегмента памяти, но в системной памяти для совместимости со старым ПО используется старый формат изображения - начальную строку пикселей можно поместить в конец сегмента памяти и читать эту память нужно с конца к началу. Для распознавания такой ситуации необходимо проверить значение Stride. Вы должны вычислить его из MFExtern.MFGetStrideForBitmapInfoHeader и проверить - если оно отрицательное, то вы должны скопировать из памяти Direct3D в обратной форме от конца к началу, изменив указатель на aPtrData += (mHeight - 1)* abs(mStride) - person Evgeny Pereguda; 18.05.2017
comment
framesizebytes = BYTES_PER_PIXEL * ширина видео * высота видео; BYTESPERPIXEL равен 4, когда я отлаживаю. Я не знаком с копированием памяти и переписыванием памяти с конца в начало. Так ты имеешь в виду, что я должен зацикливаться на этом? - person kripto; 18.05.2017