Существует ли простой и эффективный способ чтения файлов и преобразования их в указанный формат DXGI_Format и декодирования выходных форматов? - PullRequest
0 голосов
/ 31 марта 2020

Я читаю файл mp4 (код H264 c) асинхронно, и я настраивал соответствующие параметры раньше, но когда я, наконец, передаю образец через CopyResource в целевую общую разделяемую текстуру, он всегда терпит неудачу, как показано ниже.

D3D11 ERROR: ID3D11DeviceContext::CopyResource: Cannot invoke CopyResource when the Formats of each Resource are not the same or at least castable to each other, unless one format is compressed (DXGI_FORMAT_R9G9B9E5_SHAREDEXP, or DXGI_FORMAT_BC[1,2,3,4,5]_* ) and the source format is similar to the dest according to: BC[1|4] ~= R16G16B16A16|R32G32, BC[2|3|5] ~= R32G32B32A32, R9G9B9E5_SHAREDEXP ~= R32. [ RESOURCE_MANIPULATION ERROR #284: COPYRESOURCE_INVALIDSOURCE]

Если я укажу MF_MT_SUBTYPE / MF_MT_FRAME_SIZE / MF_MT_FRAME_RATE и т. Д., Они действительно могут вступить в силу? Или я должен реализовать CResizerDMO, CColorConvertDMO, CFrameRateConvertDMO и так далее шаг за шагом? Я вижу, что IMFSinkWriter, кажется, способен достичь цели, пока эти параметры настроены.

HRESULT CAsyncFileReader::StartAsyncRead(PCWSTR pszURL)
{   
    CComPtr<IMFAttributes> pAttributes = NULL;

    HRESULT hr = MFCreateAttributes(&pAttributes, 5);
    RETURN_ON_FAIL(hr);

    hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this);
    RETURN_ON_FAIL(hr);
    hr = pAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, _dxgi_device_manager);
    RETURN_ON_FAIL(hr);
    hr = pAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
    RETURN_ON_FAIL(hr);
    hr = pAttributes->SetUINT32(MF_LOW_LATENCY, 1);
    RETURN_ON_FAIL(hr);

    //MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING (version < win8)
    hr = pAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE);
    RETURN_ON_FAIL(hr);

    hr = MFCreateSourceReaderFromURL(pszURL, pAttributes, &m_pReader);
    RETURN_ON_FAIL(hr);

    CComPtr<IMFMediaType> pType = NULL;
    hr = m_pReader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &pType);
    RETURN_ON_FAIL(hr); 
    hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
    MFSetAttributeSize(pType, MF_MT_FRAME_SIZE, Capture_Width, Capture_Height);
    hr = m_pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pType);
    RETURN_ON_FAIL(hr);

    ...
}

//called by OnReadSample callback
HRESULT CAsyncFileReader::Copy2Texture(IMFSample* sample)
{
    CComPtr<IMFMediaBuffer> buffer;
    HRESULT hr = sample->GetBufferByIndex(0, &buffer);
    if (SUCCEEDED(hr))
    {
        CComPtr<IMFDXGIBuffer> dxgiBuffer;
        hr = buffer->QueryInterface(IID_PPV_ARGS(&dxgiBuffer));

        if (SUCCEEDED(hr))
        {
            CComPtr<ID3D11Texture2D> texture;

            hr = dxgiBuffer->GetResource(IID_PPV_ARGS(&texture));
            if (SUCCEEDED(hr))
            {
            //  unsigned int subresource = 0;
            //  hr = dxgiBuffer->GetSubresourceIndex(&subresource);

                if (SUCCEEDED(hr))
                {
                    CComPtr<ID3D11DeviceContext> immediate_context;
                    _d3d_device->GetImmediateContext(&immediate_context);

                    //tbd, AcquireSync need restore if failed under certain conditions
                    UINT64 key = AllocKey();
                    hr = _dxgi_keyed_mutex->AcquireSync(key, 10);
                    RETURN_ON_FAIL(hr);

                    immediate_context->CopyResource(_shared_texture2d, texture); <-------mftrace as above
                    //immediate_context->CopySubresourceRegion(_shared_texture2d, 0, 0, 0, 0, texture, subresource, nullptr);

                    hr = _dxgi_keyed_mutex->ReleaseSync(key + 1);
                    RETURN_ON_FAIL(hr);
                }
            }
        }
    }
    return hr;
}


HRESULT CreateSharedD3D11Texture2D(ID3D11Device* d3d11_device, const UINT32& w, const UINT32& h, ID3D11Texture2D** d3d11_texture_2d)
{

    D3D11_TEXTURE2D_DESC texDesc;
    texDesc.ArraySize = 1;
    texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    texDesc.Width = w;
    texDesc.Height = h;
    texDesc.MipLevels = 1;

    texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.SampleDesc.Count = 1;
    texDesc.SampleDesc.Quality = 0;
    texDesc.Usage = D3D11_USAGE_DEFAULT;

    return d3d11_device->CreateTexture2D(&texDesc, nullptr, d3d11_texture_2d);
}

Кроме того, текстура DXGI_FORMAT_B8G8R8A8_UNORM эквивалентна MFVideoFormat_RGB32, верно?

1 Ответ

0 голосов
/ 01 апреля 2020

Для вопроса, поставленного так же широко, как и в теме, ответ «нет».

Если вы можете сузить его до получения DXGI_FORMAT_B8G8R8A8_UNORM в результате преобразования формата и подгонки с использованием Media Foundation Source Reader API, тогда такое решение существует.

Соответствующие форматы Media Foundation: MFVideoFormat_RGB32 и MFVideoFormat_ARGB32.

В вашем фрагменте кода вы GetNativeMediaType, а затем SetCurrentMediaType то же самое формат точно. Вместо этого вам нужно создать новый тип носителя RGB32 / ARGB32 между этими вызовами и установить вместо этого новый формат. Вам может потребоваться обновить атрибуты Source Reader , чтобы включить преобразования. Source Reader API будет управлять необходимыми примитивами (преобразованиями) внутри, чтобы предоставить вам данные в запрошенном формате.

В качестве альтернативы вы можете извлекать данные в «родном» формате и самостоятельно управлять управляемыми декодерами / преобразователями, которые будут почти то же самое, за исключением того, что потребуется некоторое время, прежде чем вы поймете, как реализовать поток данных через цепочку преобразования.

...