ฮาร์ดแวร์กราฟิก Intel H264 MFT การประมวลผลการเรียกใช้ล้มเหลวหลังจากป้อนตัวอย่างอินพุตไม่กี่ตัวซึ่งทำงานได้ดีกับฮาร์ดแวร์ Nvidia MFT


9

ฉันใช้เดสก์ท็อปโดยใช้ DesktopDuplication API และแปลงตัวอย่างจาก RGBA เป็น NV12 ใน GPU และให้อาหารแบบเดียวกันกับฮาร์ดแวร์ MediaFoundation H264 MFT ใช้งานได้ดีกับกราฟิก Nvidia และตัวเข้ารหัสซอฟต์แวร์ แต่ล้มเหลวเมื่อมีเฉพาะฮาร์ดแวร์กราฟิก Intel MFT เท่านั้น รหัสทำงานได้ดีบนเครื่องกราฟิก Intel เดียวกันหากฉันเลือกใช้ซอฟต์แวร์ MFT ฉันยังมั่นใจได้ว่าการเข้ารหัสจะทำจริงในฮาร์ดแวร์บนเครื่องกราฟิก Nvidia

ในกราฟิก Intel, MFT ผลตอบแทน MEError ( ข้อผิดพลาด "ไม่ได้ระบุ" ) ซึ่งเกิดขึ้นเพียงหลังจากที่ตัวอย่างแรกจะถูกป้อนและโทรตามมา ProcessInput (เมื่อกำเนิดเหตุการณ์ทริกเกอร์ METransformNeedInput) ผลตอบแทน"ผู้ถูกเรียกในปัจจุบันคือการไม่ยอมรับการป้อนข้อมูลต่อไป" เป็นเรื่องยากที่ MFT จะใช้ตัวอย่างเพิ่มเติมไม่กี่ตัวอย่างก่อนส่งคืนข้อผิดพลาดเหล่านี้ พฤติกรรมนี้สับสนฉันให้อาหารตัวอย่างเฉพาะเมื่อตัวสร้างเหตุการณ์ทริกเกอร์ METransformNeedInput แบบอะซิงโครนัสผ่าน IMFAsyncCallback และตรวจสอบอย่างถูกต้องว่า METransformHaveOutput ถูกทริกเกอร์ทันทีที่ตัวอย่างถูกป้อน สิ่งนี้ทำให้ฉันงงงวยเมื่อตรรกะแบบอะซิงโครนัสเดียวกันทำงานได้ดีกับตัวเข้ารหัสฮาร์ดแวร์ MFT & Microsoft ของ Nvidia

นอกจากนี้ยังมีคำถามที่ไม่ได้รับการแก้ไขที่คล้ายกันในฟอรัม intel รหัสของฉันคล้ายกับรหัสที่กล่าวถึงในเธรด intel ยกเว้นความจริงที่ว่าฉันยังตั้งค่าตัวจัดการอุปกรณ์ d3d เป็นโปรแกรมเปลี่ยนไฟล์ตามด้านล่าง

และมีเธรดโอเวอร์โฟลว์อื่น ๆ อีกสามตัวที่รายงานปัญหาที่คล้ายกันโดยไม่มีวิธีแก้ปัญหา ( MFTransform encoder-> ProcessInput ส่งคืน E_FAILและ วิธีสร้าง IMFSample จากพื้นผิว D11 สำหรับการเข้ารหัส Intel MFTและAsynchronous MFT ไม่ส่ง MFTransformHaveOutput MFT) ) ฉันได้ลองทุกทางเลือกที่เป็นไปได้โดยไม่มีการปรับปรุงในเรื่องนี้

รหัสตัวแปลงสีนำมาจากตัวอย่างสื่อ sdk ของ intel ฉันยังได้อัปโหลดรหัสทั้งหมดของฉันที่นี่

วิธีการตั้ง d3d manager:

void SetD3dManager() {

    HRESULT hr = S_OK;

    if (!deviceManager) {

        // Create device manager
        hr = MFCreateDXGIDeviceManager(&resetToken, &deviceManager);
    }

    if (SUCCEEDED(hr)) 
    {
        if (!pD3dDevice) {

            pD3dDevice = GetDeviceDirect3D(0);
        }
    }

    if (pD3dDevice) {

        // NOTE: Getting ready for multi-threaded operation
        const CComQIPtr<ID3D10Multithread> pMultithread = pD3dDevice;
        pMultithread->SetMultithreadProtected(TRUE);

        hr = deviceManager->ResetDevice(pD3dDevice, resetToken);
        CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, reinterpret_cast<ULONG_PTR>(deviceManager.p)), "Failed to set device manager.");
    }
    else {
        cout << "Failed to get d3d device";
    }
}

Getd3ddevice:

CComPtr<ID3D11Device> GetDeviceDirect3D(UINT idxVideoAdapter)
{
    // Create DXGI factory:
    CComPtr<IDXGIFactory1> dxgiFactory;
    DXGI_ADAPTER_DESC1 dxgiAdapterDesc;

    // Direct3D feature level codes and names:

    struct KeyValPair { int code; const char* name; };

    const KeyValPair d3dFLevelNames[] =
    {
        KeyValPair{ D3D_FEATURE_LEVEL_9_1, "Direct3D 9.1" },
        KeyValPair{ D3D_FEATURE_LEVEL_9_2, "Direct3D 9.2" },
        KeyValPair{ D3D_FEATURE_LEVEL_9_3, "Direct3D 9.3" },
        KeyValPair{ D3D_FEATURE_LEVEL_10_0, "Direct3D 10.0" },
        KeyValPair{ D3D_FEATURE_LEVEL_10_1, "Direct3D 10.1" },
        KeyValPair{ D3D_FEATURE_LEVEL_11_0, "Direct3D 11.0" },
        KeyValPair{ D3D_FEATURE_LEVEL_11_1, "Direct3D 11.1" },
    };

    // Feature levels for Direct3D support
    const D3D_FEATURE_LEVEL d3dFeatureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
        D3D_FEATURE_LEVEL_9_1,
    };

    constexpr auto nFeatLevels = static_cast<UINT> ((sizeof d3dFeatureLevels) / sizeof(D3D_FEATURE_LEVEL));

    CComPtr<IDXGIAdapter1> dxgiAdapter;
    D3D_FEATURE_LEVEL featLevelCodeSuccess;
    CComPtr<ID3D11Device> d3dDx11Device;

    std::wstring_convert<std::codecvt_utf8<wchar_t>> transcoder;

    HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
    CHECK_HR(hr, "Failed to create DXGI factory");

    // Get a video adapter:
    dxgiFactory->EnumAdapters1(idxVideoAdapter, &dxgiAdapter);

    // Get video adapter description:
    dxgiAdapter->GetDesc1(&dxgiAdapterDesc);

    CHECK_HR(hr, "Failed to retrieve DXGI video adapter description");

    std::cout << "Selected DXGI video adapter is \'"
        << transcoder.to_bytes(dxgiAdapterDesc.Description) << '\'' << std::endl;

    // Create Direct3D device:
    hr = D3D11CreateDevice(
        dxgiAdapter,
        D3D_DRIVER_TYPE_UNKNOWN,
        nullptr,
        (0 * D3D11_CREATE_DEVICE_SINGLETHREADED) | D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
        d3dFeatureLevels,
        nFeatLevels,
        D3D11_SDK_VERSION,
        &d3dDx11Device,
        &featLevelCodeSuccess,
        nullptr
    );

    // Might have failed for lack of Direct3D 11.1 runtime:
    if (hr == E_INVALIDARG)
    {
        // Try again without Direct3D 11.1:
        hr = D3D11CreateDevice(
            dxgiAdapter,
            D3D_DRIVER_TYPE_UNKNOWN,
            nullptr,
            (0 * D3D11_CREATE_DEVICE_SINGLETHREADED) | D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
            d3dFeatureLevels + 1,
            nFeatLevels - 1,
            D3D11_SDK_VERSION,
            &d3dDx11Device,
            &featLevelCodeSuccess,
            nullptr
        );
    }

    // Get name of Direct3D feature level that succeeded upon device creation:
    std::cout << "Hardware device supports " << std::find_if(
        d3dFLevelNames,
        d3dFLevelNames + nFeatLevels,
        [featLevelCodeSuccess](const KeyValPair& entry)
        {
            return entry.code == featLevelCodeSuccess;
        }
    )->name << std::endl;

done:

    return d3dDx11Device;
}

การใช้งาน Async Callback:

struct EncoderCallbacks : IMFAsyncCallback
{
    EncoderCallbacks(IMFTransform* encoder)
    {
        TickEvent = CreateEvent(0, FALSE, FALSE, 0);
        _pEncoder = encoder;
    }

    ~EncoderCallbacks()
    {
        eventGen = nullptr;
        CloseHandle(TickEvent);
    }

    bool Initialize() {

        _pEncoder->QueryInterface(IID_PPV_ARGS(&eventGen));

        if (eventGen) {

            eventGen->BeginGetEvent(this, 0);
            return true;
        }

        return false;
    }

    // dummy IUnknown impl
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override { return E_NOTIMPL; }
    virtual ULONG STDMETHODCALLTYPE AddRef(void) override { return 1; }
    virtual ULONG STDMETHODCALLTYPE Release(void) override { return 1; }

    virtual HRESULT STDMETHODCALLTYPE GetParameters(DWORD* pdwFlags, DWORD* pdwQueue) override
    {
        // we return immediately and don't do anything except signaling another thread
        *pdwFlags = MFASYNC_SIGNAL_CALLBACK;
        *pdwQueue = MFASYNC_CALLBACK_QUEUE_IO;
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE Invoke(IMFAsyncResult* pAsyncResult) override
    {
        IMFMediaEvent* event = 0;
        eventGen->EndGetEvent(pAsyncResult, &event);
        if (event)
        {
            MediaEventType type;
            event->GetType(&type);
            switch (type)
            {
            case METransformNeedInput: InterlockedIncrement(&NeedsInput); break;
            case METransformHaveOutput: InterlockedIncrement(&HasOutput); break;
            }
            event->Release();
            SetEvent(TickEvent);
        }

        eventGen->BeginGetEvent(this, 0);
        return S_OK;
    }

    CComQIPtr<IMFMediaEventGenerator> eventGen = nullptr;
    HANDLE TickEvent;
    IMFTransform* _pEncoder = nullptr;

    unsigned int NeedsInput = 0;
    unsigned int HasOutput = 0;
};

สร้างวิธีตัวอย่าง:

bool GenerateSampleAsync() {

    DWORD processOutputStatus = 0;
    HRESULT mftProcessOutput = S_OK;
    bool frameSent = false;

    // Create sample
    CComPtr<IMFSample> currentVideoSample = nullptr;

    MFT_OUTPUT_STREAM_INFO StreamInfo;

    // wait for any callback to come in
    WaitForSingleObject(_pEventCallback->TickEvent, INFINITE);

    while (_pEventCallback->NeedsInput) {

        if (!currentVideoSample) {

            (pDesktopDuplication)->releaseBuffer();
            (pDesktopDuplication)->cleanUpCurrentFrameObjects();

            bool bTimeout = false;

            if (pDesktopDuplication->GetCurrentFrameAsVideoSample((void**)& currentVideoSample, waitTime, bTimeout, deviceRect, deviceRect.Width(), deviceRect.Height())) {

                prevVideoSample = currentVideoSample;
            }
            // Feed the previous sample to the encoder in case of no update in display
            else {
                currentVideoSample = prevVideoSample;
            }
        }

        if (currentVideoSample)
        {
            InterlockedDecrement(&_pEventCallback->NeedsInput);
            _frameCount++;

            CHECK_HR(currentVideoSample->SetSampleTime(mTimeStamp), "Error setting the video sample time.");
            CHECK_HR(currentVideoSample->SetSampleDuration(VIDEO_FRAME_DURATION), "Error getting video sample duration.");

            CHECK_HR(_pTransform->ProcessInput(inputStreamID, currentVideoSample, 0), "The resampler H264 ProcessInput call failed.");

            mTimeStamp += VIDEO_FRAME_DURATION;
        }
    }

    while (_pEventCallback->HasOutput) {

        CComPtr<IMFSample> mftOutSample = nullptr;
        CComPtr<IMFMediaBuffer> pOutMediaBuffer = nullptr;

        InterlockedDecrement(&_pEventCallback->HasOutput);

        CHECK_HR(_pTransform->GetOutputStreamInfo(outputStreamID, &StreamInfo), "Failed to get output stream info from H264 MFT.");

        CHECK_HR(MFCreateSample(&mftOutSample), "Failed to create MF sample.");
        CHECK_HR(MFCreateMemoryBuffer(StreamInfo.cbSize, &pOutMediaBuffer), "Failed to create memory buffer.");
        CHECK_HR(mftOutSample->AddBuffer(pOutMediaBuffer), "Failed to add sample to buffer.");

        MFT_OUTPUT_DATA_BUFFER _outputDataBuffer;
        memset(&_outputDataBuffer, 0, sizeof _outputDataBuffer);
        _outputDataBuffer.dwStreamID = outputStreamID;
        _outputDataBuffer.dwStatus = 0;
        _outputDataBuffer.pEvents = nullptr;
        _outputDataBuffer.pSample = mftOutSample;

        mftProcessOutput = _pTransform->ProcessOutput(0, 1, &_outputDataBuffer, &processOutputStatus);

        if (mftProcessOutput != MF_E_TRANSFORM_NEED_MORE_INPUT)
        {
            if (_outputDataBuffer.pSample) {

                CComPtr<IMFMediaBuffer> buf = NULL;
                DWORD bufLength;
                CHECK_HR(_outputDataBuffer.pSample->ConvertToContiguousBuffer(&buf), "ConvertToContiguousBuffer failed.");

                if (buf) {

                    CHECK_HR(buf->GetCurrentLength(&bufLength), "Get buffer length failed.");
                    BYTE* rawBuffer = NULL;

                    fFrameSize = bufLength;
                    fDurationInMicroseconds = 0;
                    gettimeofday(&fPresentationTime, NULL);

                    buf->Lock(&rawBuffer, NULL, NULL);
                    memmove(fTo, rawBuffer, fFrameSize > fMaxSize ? fMaxSize : fFrameSize);

                    bytesTransfered += bufLength;

                    FramedSource::afterGetting(this);

                    buf->Unlock();

                    frameSent = true;
                }
            }

            if (_outputDataBuffer.pEvents)
                _outputDataBuffer.pEvents->Release();
        }
        else if (MF_E_TRANSFORM_STREAM_CHANGE == mftProcessOutput) {

            // some encoders want to renegotiate the output format. 
            if (_outputDataBuffer.dwStatus & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE)
            {
                CComPtr<IMFMediaType> pNewOutputMediaType = nullptr;
                HRESULT res = _pTransform->GetOutputAvailableType(outputStreamID, 1, &pNewOutputMediaType);

                res = _pTransform->SetOutputType(0, pNewOutputMediaType, 0);//setting the type again
                CHECK_HR(res, "Failed to set output type during stream change");
            }
        }
        else {
            HandleFailure();
        }
    }

    return frameSent;
}

สร้างตัวอย่างวิดีโอ & การแปลงสี:

bool GetCurrentFrameAsVideoSample(void **videoSample, int waitTime, bool &isTimeout, CRect &deviceRect, int surfaceWidth, int surfaceHeight)
{

FRAME_DATA currentFrameData;

m_LastErrorCode = m_DuplicationManager.GetFrame(&currentFrameData, waitTime, &isTimeout);

if (!isTimeout && SUCCEEDED(m_LastErrorCode)) {

    m_CurrentFrameTexture = currentFrameData.Frame;

    if (!pDstTexture) {

        D3D11_TEXTURE2D_DESC desc;
        ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));

        desc.Format = DXGI_FORMAT_NV12;
        desc.Width = surfaceWidth;
        desc.Height = surfaceHeight;
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.SampleDesc.Count = 1;
        desc.CPUAccessFlags = 0;
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.BindFlags = D3D11_BIND_RENDER_TARGET;

        m_LastErrorCode = m_Id3d11Device->CreateTexture2D(&desc, NULL, &pDstTexture);
    }

    if (m_CurrentFrameTexture && pDstTexture) {

        // Copy diff area texels to new temp texture
        //m_Id3d11DeviceContext->CopySubresourceRegion(pNewTexture, D3D11CalcSubresource(0, 0, 1), 0, 0, 0, m_CurrentFrameTexture, 0, NULL);

        HRESULT hr = pColorConv->Convert(m_CurrentFrameTexture, pDstTexture);

        if (SUCCEEDED(hr)) { 

            CComPtr<IMFMediaBuffer> pMediaBuffer = nullptr;

            MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), pDstTexture, 0, FALSE, (IMFMediaBuffer**)&pMediaBuffer);

            if (pMediaBuffer) {

                CComPtr<IMF2DBuffer> p2DBuffer = NULL;
                DWORD length = 0;
                (((IMFMediaBuffer*)pMediaBuffer))->QueryInterface(__uuidof(IMF2DBuffer), reinterpret_cast<void**>(&p2DBuffer));
                p2DBuffer->GetContiguousLength(&length);
                (((IMFMediaBuffer*)pMediaBuffer))->SetCurrentLength(length);

                //MFCreateVideoSampleFromSurface(NULL, (IMFSample**)videoSample);
                MFCreateSample((IMFSample * *)videoSample);

                if (videoSample) {

                    (*((IMFSample **)videoSample))->AddBuffer((((IMFMediaBuffer*)pMediaBuffer)));
                }

                return true;
            }
        }
    }
}

return false;
}

ไดรเวอร์กราฟิก Intel ในเครื่องทันสมัยแล้ว

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

เฉพาะเหตุการณ์ TransformNeedInput เท่านั้นที่ถูกทริกเกอร์ตลอดเวลา แต่ตัวเข้ารหัสบ่นว่าไม่สามารถรับอินพุตเพิ่มเติมได้อีก เหตุการณ์ TransformHaveOutput ไม่เคยถูกเรียกใช้

ป้อนคำอธิบายรูปภาพที่นี่

ปัญหาที่คล้ายกันที่รายงานในฟอรัม intel & msdn: 1) https://software.intel.com/en-us/forums/intel-media-sdk/topic/607189 2) https://social.msdn.microsoft.com/ กระดานสนทนา / ความปลอดภัย / en-US / fe051dd5-b522-4e4b-9cbb-2c06a5450e40 / imfsinkwriter บุญการตรวจสอบล้มเหลวสำหรับ MFT-Intel อย่างรวดเร็วซิงค์วิดีโอ-h264 เข้ารหัส-MFT? ฟอรั่ม = mediafoundationdevelopment

อัปเดต: ฉันพยายามที่จะจำลองเพียงแหล่งอินพุต (โดยการสร้างตัวอย่าง NV12 สี่เหลี่ยมผืนผ้าที่เคลื่อนไหวได้โดยทางโปรแกรม) ทำให้ทุกอย่างอื่นไม่ถูกแตะต้อง ครั้งนี้ตัวเข้ารหัส intel ไม่ได้บ่นอะไรเลยฉันยังมีตัวอย่างเอาท์พุท ยกเว้นข้อเท็จจริงที่ว่าวิดีโอเอาท์พุทของเอนโค้ดเดอร์ของ Intel นั้นบิดเบี้ยวในขณะที่เอ็นโค้ดเดอร์ Nvidia ทำงานได้อย่างสมบูรณ์

นอกจากนี้ฉันยังคงได้รับข้อผิดพลาด ProcessInput สำหรับแหล่ง NV12 ดั้งเดิมของฉันพร้อมตัวเข้ารหัส intel ฉันไม่มีปัญหากับ Nvidia MFT และซอฟต์แวร์ตัวเข้ารหัส

เอาต์พุตของฮาร์ดแวร์ Intel MFT: (โปรดดูเอาต์พุตของตัวเข้ารหัสของ Nvidia) ป้อนคำอธิบายรูปภาพที่นี่

การส่งออกของฮาร์ดแวร์ Nvidia MFT: ป้อนคำอธิบายรูปภาพที่นี่

สถิติการใช้กราฟิก Nvidia: ป้อนคำอธิบายรูปภาพที่นี่

สถิติการใช้งานกราฟิกของ Intel (ฉันไม่เข้าใจว่าเพราะเหตุใดเครื่องยนต์เอนจินของ GPU จึงถูกแสดงเป็นตัวถอดรหัสวิดีโอ): ป้อนคำอธิบายรูปภาพที่นี่


ไม่แสดงรหัสที่เกี่ยวข้อง มันมีแนวโน้มว่าอะไรผิดพลาดตรงรอบที่ได้รับ "ความจำเป็นในการป้อนข้อมูล" ProcessInputและให้มันด้วย
— Roman R.

@RomanR ถ้าเป็นเช่นนั้นมันอาจล้มเหลวสำหรับซอฟต์แวร์ & Nvidia Hardware MFTs ใช่ไหม? ฉันไม่ได้แสดงรหัสใด ๆ ที่เกี่ยวข้องกับการแจกแจง MFT และการกำหนดค่าอินพุตและเอาต์พุตเนื่องจากจะซ้ำซ้อนไม่จำเป็นและยาวเกินไปสำหรับเธรดที่ฉันกล่าวว่าฉันได้ปฏิบัติตามรหัสเดียวกันที่กำหนดในฟอรัม intel ( software.intel.com / en-us / ฟอรัม / intel-media-sdk / topic / 681571 ) ฉันจะพยายามอัพเดตเธรดนี้ด้วยบล็อคโค้ดที่จำเป็น
— ราม

ไม่มันไม่ใช่. MFT ของฮาร์ดแวร์จาก AMD, Intel และ NVIDIA ใช้งานได้เหมือนกัน แต่ในขณะเดียวกันก็มีพฤติกรรมที่แตกต่างกันเล็กน้อย ทั้งสามส่วนใหญ่ทำงานเป็น async MFTs ดังนั้นคำถามของคุณเป็นข้อบ่งชี้ที่ชัดเจนว่าคุณกำลังทำอะไรผิดพลาด ไม่มีรหัสมันเป็นเพียงการคาดเดาสิ่งที่แน่นอน ซอฟต์แวร์เข้ารหัสของ Microsoft ทำข้อมูลให้ตรงกัน MFT AFAIR ดังนั้นจึงค่อนข้างเป็นไปได้ว่าเป็นส่วนหนึ่งของการสื่อสารกับ async MFT ซึ่งเป็นสิ่งที่ไม่เป็นไร
— โรมันอาร์

BTW รหัสจากลิงก์ฟอรัม Intel นั้นเหมาะกับฉันและสร้างวิดีโอ
— อาร์โรมันอาร์

@RomanR ฉันได้อัพเดตเธรดด้วยการใช้ IMFAsyncCallback ของฉันการสร้างตัวอย่างและการแปลงสี ProcessInput & ProcessOutput ตัวแปลงสีนั้นใช้จากที่นี่ ( github.com/NVIDIA/video-sdk-samples/blob/master/… )
— ราม

คำตอบ:


2

ฉันดูโค้ดของคุณ

จากการโพสต์ของคุณฉันสงสัยว่ามีปัญหาเกี่ยวกับโปรเซสเซอร์วิดีโอของ Intel

ระบบปฏิบัติการของฉันคือ Win7 ดังนั้นฉันตัดสินใจทดสอบพฤติกรรมของตัวประมวลผลวิดีโอด้วย D3D9Device บนการ์ด Nvidia ของฉันและจากนั้นบน Intel HD Graphics 4000

ฉันคิดว่าความสามารถของตัวประมวลผลวิดีโอจะทำงานในลักษณะเดียวกันสำหรับ D3D9Device สำหรับ D3D11Device แน่นอนว่ามันจำเป็นต้องตรวจสอบ

ดังนั้นฉันจึงทำโปรแกรมนี้เพื่อตรวจสอบ: https://github.com/mofo7777/DirectXVideoScreen (ดู D3D9VideoProcessor โครงการย่อย)

ดูเหมือนว่าคุณไม่ได้ตรวจสอบสิ่งที่เพียงพอเกี่ยวกับความสามารถของตัวประมวลผลวิดีโอ

ด้วย IDXVAHD_Device :: GetVideoProcessorDeviceCaps นี่คือสิ่งที่ฉันตรวจสอบ:

DXVAHD_VPDEVCAPS.MaxInputStreams> 0

DXVAHD_VPDEVCAPS.VideoProcessorCount> 0

DXVAHD_VPDEVCAPS.OutputFormatCount> 0

DXVAHD_VPDEVCAPS.InputFormatCount> 0

DXVAHD_VPDEVCAPS.InputPool == D3DPOOL_DEFAULT

ฉันยังตรวจสอบรูปแบบอินพุตและเอาต์พุตที่สนับสนุนด้วย IDXVAHD_Device :: GetVideoProcessorOutputFormats และ IDXVAHD_Device :: GetVideoProcessorInputFormats

ที่นี่ฉันพบความแตกต่างระหว่าง Nvidia GPU และ Intel GPU

NVIDIA: รูปแบบเอาต์พุต 4

  • D3DFMT_A8R8G8B8
  • D3DFMT_X8R8G8B8
  • D3DFMT_YUY2
  • D3DFMT_NV12

INTEL: 3 รูปแบบผลลัพธ์

  • D3DFMT_A8R8G8B8
  • D3DFMT_X8R8G8B8
  • D3DFMT_YUY2

บน Intel HD Graphics 4000 ไม่มีการรองรับรูปแบบเอาต์พุต NV12

นอกจากนี้เพื่อให้โปรแกรมทำงานอย่างถูกต้องฉันต้องตั้งค่าสถานะสตรีมก่อนใช้ VideoProcessBltHD:

  • DXVAHD_STREAM_STATE_D3DFORMAT
  • DXVAHD_STREAM_STATE_FRAME_FORMAT
  • DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE
  • DXVAHD_STREAM_STATE_SOURCE_RECT
  • DXVAHD_STREAM_STATE_DESTINATION_RECT

สำหรับ D3D11:

ID3D11VideoProcessorEnumerator :: GetVideoProcessorCaps == IDXVAHD_Device :: GetVideoProcessorDeviceCaps

(D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT) ID3D11VideoProcessorEnumerator :: CheckVideoProcessorFormat == IDXVAHD_Device :: GetVideoProcessorOutputFormats

(D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT) ID3D11VideoProcessorEnumerator :: CheckVideoProcessorFormat == IDXVAHD_Device :: GetVideoProcessorInputFormats

ID3D11VideoContext :: (... ) == IDXVAHD_VideoProcessor :: SetVideoProcessStreamState

คุณช่วยยืนยันความสามารถของตัวประมวลผลวิดีโอของ GPU ของคุณก่อนได้ไหม คุณเห็นความแตกต่างเช่นเดียวกับที่ฉันเห็นหรือไม่?

นี่เป็นสิ่งแรกที่เราจำเป็นต้องรู้และดูเหมือนว่าโปรแกรมของคุณจะไม่ตรวจสอบสิ่งนี้จากสิ่งที่ฉันได้เห็นในโครงการ github ของคุณ


คุณพูดถูก GetVideoProcessorOutputFormats บนกราฟิก Intel ส่งคืนเฉพาะตัวแปร RGB และ YUY2
— ราม

ฉันสามารถแปลงพื้นผิว RGBA เป็น YUY2 บนโปรเซสเซอร์ของ Intel ได้อย่างง่ายดาย แต่ที่จับได้ดูเหมือนว่ากราฟิก Intel สนับสนุนรูปแบบอินพุต NV12 เท่านั้น ตอนนี้ตัวแปลงสีและตัวเข้ารหัสวิดีโอเข้ากันไม่ได้ ฉันยังสงสัยว่าทำไม Intel ตัดสินใจที่จะทำเช่นนี้ มีวิธีอื่นในการแปลง RGB เป็น NV12 อย่างมีประสิทธิภาพหรือไม่ ฉันได้ลองใช้วิธีการซอฟต์แวร์ที่ไม่มีประสิทธิภาพเพียงพอแล้ว
— Ram

คุณมี shader หรือคำนวณ shader
— mofo77

1
ฉันกำลังทำงานบนวิธี Shader ตรวจสอบ การอัปเดตgithub.com/mofo7777/DirectXVideoScreen
— mofo77

ที่ดี! ขอบคุณสำหรับการแบ่งปันมันมีประโยชน์จริงๆ
— ราม

1

ดังที่กล่าวไว้ในโพสต์ข้อผิดพลาด MEError ("ข้อผิดพลาดที่ไม่ระบุ") ถูกส่งคืนโดยตัวสร้างเหตุการณ์การแปลงทันทีหลังจากป้อนตัวอย่างอินพุตแรกบนฮาร์ดแวร์ของ Intel และการเรียกกลับมาเพียงแค่ "กลับมา . รหัสเดียวกันทำงานได้ดีบนเครื่อง Nvidia หลังจากการทดลองและค้นคว้ามากฉันคิดว่าฉันกำลังสร้างอินสแตนซ์ของ D3d11Device มากเกินไปในกรณีของฉันฉันได้สร้างอุปกรณ์ 2 ถึง 3 อุปกรณ์สำหรับการจับการแปลงสีและการเข้ารหัสฮาร์ดแวร์ตามลำดับ ในขณะที่ฉันสามารถนำอินสแตนซ์ D3dDevice เดียวกลับมาใช้ใหม่ได้ การสร้างอินสแตนซ์ D3d11Device หลายรายการอาจทำงานบนเครื่องระดับสูงได้ นี่ไม่ใช่เอกสารใด ๆ ฉันไม่สามารถค้นหาแม้แต่เงื่อนงำสาเหตุของข้อผิดพลาด "MEError" มันพูดถึงที่ไหนเลย

การใช้อินสแตนซ์ D3D11Device ซ้ำแก้ปัญหาแล้ว การโพสต์โซลูชันนี้เนื่องจากอาจเป็นประโยชน์สำหรับผู้ที่ประสบปัญหาเช่นเดียวกับของฉัน


ฉันไม่เห็นในโพสต์ของคุณที่มีการกล่าวถึงข้อผิดพลาด E_UNEXPECTED ...
— mofo77

@ mofo77 ขออภัยเป็น MEError = 1 ("ข้อผิดพลาดที่ไม่ระบุ") ตามที่กล่าวไว้ในโพสต์ ฉันหลงทาง แก้ไขคำตอบของฉัน ขอบคุณสำหรับการชี้ให้เห็น
— Ram
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.