ฮาร์ดแวร์กราฟิก 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.