Ffplay में हरी स्क्रीन प्राप्त करना: Live555 का उपयोग करके RTP स्ट्रीम पर H264 वीडियो के रूप में डेस्कटॉप (DirectX सतह) को स्ट्रीम करना


9

मैं डेस्कटॉप पर (NVX प्रारूप में DirectX सतह) स्ट्रीम करने की कोशिश कर रहा हूँ क्योंकि Live555 और Windows10 पर विंडोज मीडिया फाउंडेशन के हार्डवेयर एनकोडर का उपयोग करके RTP स्ट्रीम पर H264 वीडियो, और इसे ffplay (ffmx 4.2) द्वारा रेंडर किए जाने की उम्मीद है। लेकिन केवल नीचे की तरह एक हरी स्क्रीन मिल रही है,

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

मैंने MF55ebCamToRTP मीडियाफाउंडेशन-सैंपल को संदर्भित किया और live555 के FramedSource को कार्यान्वित करने के लिए हार्डवेयर MFT का उपयोग करके DirectX सतह का उपयोग किया और इनपुट स्रोत को WebCam के बजाय DirectX सतह में बदल दिया।

यहाँ LiveX5 के doGetNextFrame कॉलबैक के लिए मेरे कार्यान्वयन का एक अंश है: XX कण से इनपुट नमूने खिलाने के लिए:

virtual void doGetNextFrame()
{
    if (!_isInitialised)
    {
        if (!initialise()) {
            printf("Video device initialisation failed, stopping.");
            return;
        }
        else {
            _isInitialised = true;
        }
    }

    //if (!isCurrentlyAwaitingData()) return;

    DWORD processOutputStatus = 0;
    HRESULT mftProcessOutput = S_OK;
    MFT_OUTPUT_STREAM_INFO StreamInfo;
    IMFMediaBuffer *pBuffer = NULL;
    IMFSample *mftOutSample = NULL;
    DWORD mftOutFlags;
    bool frameSent = false;
    bool bTimeout = false;

    // Create sample
    CComPtr<IMFSample> videoSample = NULL;

    // Create buffer
    CComPtr<IMFMediaBuffer> inputBuffer;
    // Get next event
    CComPtr<IMFMediaEvent> event;
    HRESULT hr = eventGen->GetEvent(0, &event);
    CHECK_HR(hr, "Failed to get next event");

    MediaEventType eventType;
    hr = event->GetType(&eventType);
    CHECK_HR(hr, "Failed to get event type");


    switch (eventType)
    {
    case METransformNeedInput:
        {
            hr = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), surface, 0, FALSE, &inputBuffer);
            CHECK_HR(hr, "Failed to create IMFMediaBuffer");

            hr = MFCreateSample(&videoSample);
            CHECK_HR(hr, "Failed to create IMFSample");
            hr = videoSample->AddBuffer(inputBuffer);
            CHECK_HR(hr, "Failed to add buffer to IMFSample");

            if (videoSample)
            {
                _frameCount++;

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

                // Pass the video sample to the H.264 transform.

                hr = _pTransform->ProcessInput(inputStreamID, videoSample, 0);
                CHECK_HR(hr, "The resampler H264 ProcessInput call failed.\n");

                mTimeStamp += VIDEO_FRAME_DURATION;
            }
        }

        break;

    case METransformHaveOutput:

        {
            CHECK_HR(_pTransform->GetOutputStatus(&mftOutFlags), "H264 MFT GetOutputStatus failed.\n");

            if (mftOutFlags == MFT_OUTPUT_STATUS_SAMPLE_READY)
            {
                MFT_OUTPUT_DATA_BUFFER _outputDataBuffer;
                memset(&_outputDataBuffer, 0, sizeof _outputDataBuffer);
                _outputDataBuffer.dwStreamID = outputStreamID;
                _outputDataBuffer.dwStatus = 0;
                _outputDataBuffer.pEvents = NULL;
                _outputDataBuffer.pSample = nullptr;

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

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

                        //CHECK_HR(_outputDataBuffer.pSample->SetSampleTime(mTimeStamp), "Error setting MFT sample time.\n");
                        //CHECK_HR(_outputDataBuffer.pSample->SetSampleDuration(VIDEO_FRAME_DURATION), "Error setting MFT sample duration.\n");

                        IMFMediaBuffer *buf = NULL;
                        DWORD bufLength;
                        CHECK_HR(_outputDataBuffer.pSample->ConvertToContiguousBuffer(&buf), "ConvertToContiguousBuffer failed.\n");
                        CHECK_HR(buf->GetCurrentLength(&bufLength), "Get buffer length failed.\n");
                        BYTE * rawBuffer = NULL;

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

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

                        FramedSource::afterGetting(this);

                        buf->Unlock();
                        SafeRelease(&buf);

                        frameSent = true;
                        _lastSendAt = GetTickCount();

                        _outputDataBuffer.pSample->Release();
                    }

                    if (_outputDataBuffer.pEvents)
                        _outputDataBuffer.pEvents->Release();
                }

                //SafeRelease(&pBuffer);
                //SafeRelease(&mftOutSample);

                break;
            }
        }

        break;
    }

    if (!frameSent)
    {
        envir().taskScheduler().triggerEvent(eventTriggerId, this);
    }

    return;

done:

    printf("MediaFoundationH264LiveSource doGetNextFrame failed.\n");
    envir().taskScheduler().triggerEvent(eventTriggerId, this);
}

प्रारंभिक विधि:

bool initialise()
{
    HRESULT hr;
    D3D11_TEXTURE2D_DESC desc = { 0 };

    HDESK CurrentDesktop = nullptr;
    CurrentDesktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);
    if (!CurrentDesktop)
    {
        // We do not have access to the desktop so request a retry
        return false;
    }

    // Attach desktop to this thread
    bool DesktopAttached = SetThreadDesktop(CurrentDesktop) != 0;
    CloseDesktop(CurrentDesktop);
    CurrentDesktop = nullptr;
    if (!DesktopAttached)
    {
        printf("SetThreadDesktop failed\n");
    }

    UINT32 activateCount = 0;

    // h264 output
    MFT_REGISTER_TYPE_INFO info = { MFMediaType_Video, MFVideoFormat_H264 };

    UINT32 flags =
        MFT_ENUM_FLAG_HARDWARE |
        MFT_ENUM_FLAG_SORTANDFILTER;

    // ------------------------------------------------------------------------
    // Initialize D3D11
    // ------------------------------------------------------------------------

    // Driver types supported
    D3D_DRIVER_TYPE DriverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE,
    };
    UINT NumDriverTypes = ARRAYSIZE(DriverTypes);

    // Feature levels supported
    D3D_FEATURE_LEVEL FeatureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_1
    };
    UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);

    D3D_FEATURE_LEVEL FeatureLevel;

    // Create device
    for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
    {
        hr = D3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr,
            D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
            FeatureLevels, NumFeatureLevels, D3D11_SDK_VERSION, &device, &FeatureLevel, &context);
        if (SUCCEEDED(hr))
        {
            // Device creation success, no need to loop anymore
            break;
        }
    }

    CHECK_HR(hr, "Failed to create device");

    // Create device manager
    UINT resetToken;
    hr = MFCreateDXGIDeviceManager(&resetToken, &deviceManager);
    CHECK_HR(hr, "Failed to create DXGIDeviceManager");

    hr = deviceManager->ResetDevice(device, resetToken);
    CHECK_HR(hr, "Failed to assign D3D device to device manager");


    // ------------------------------------------------------------------------
    // Create surface
    // ------------------------------------------------------------------------
    desc.Format = DXGI_FORMAT_NV12;
    desc.Width = surfaceWidth;
    desc.Height = surfaceHeight;
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.SampleDesc.Count = 1;

    hr = device->CreateTexture2D(&desc, NULL, &surface);
    CHECK_HR(hr, "Could not create surface");

    hr = MFTEnumEx(
        MFT_CATEGORY_VIDEO_ENCODER,
        flags,
        NULL,
        &info,
        &activateRaw,
        &activateCount
    );
    CHECK_HR(hr, "Failed to enumerate MFTs");

    CHECK(activateCount, "No MFTs found");

    // Choose the first available encoder
    activate = activateRaw[0];

    for (UINT32 i = 0; i < activateCount; i++)
        activateRaw[i]->Release();

    // Activate
    hr = activate->ActivateObject(IID_PPV_ARGS(&_pTransform));
    CHECK_HR(hr, "Failed to activate MFT");

    // Get attributes
    hr = _pTransform->GetAttributes(&attributes);
    CHECK_HR(hr, "Failed to get MFT attributes");

    // Unlock the transform for async use and get event generator
    hr = attributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
    CHECK_HR(hr, "Failed to unlock MFT");

    eventGen = _pTransform;
    CHECK(eventGen, "Failed to QI for event generator");

    // Get stream IDs (expect 1 input and 1 output stream)
    hr = _pTransform->GetStreamIDs(1, &inputStreamID, 1, &outputStreamID);
    if (hr == E_NOTIMPL)
    {
        inputStreamID = 0;
        outputStreamID = 0;
        hr = S_OK;
    }
    CHECK_HR(hr, "Failed to get stream IDs");

     // ------------------------------------------------------------------------
    // Configure hardware encoder MFT
   // ------------------------------------------------------------------------
    CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, reinterpret_cast<ULONG_PTR>(deviceManager.p)), "Failed to set device manager.\n");

    // Set low latency hint
    hr = attributes->SetUINT32(MF_LOW_LATENCY, TRUE);
    CHECK_HR(hr, "Failed to set MF_LOW_LATENCY");

    hr = MFCreateMediaType(&outputType);
    CHECK_HR(hr, "Failed to create media type");

    hr = outputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
    CHECK_HR(hr, "Failed to set MF_MT_MAJOR_TYPE on H264 output media type");

    hr = outputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
    CHECK_HR(hr, "Failed to set MF_MT_SUBTYPE on H264 output media type");

    hr = outputType->SetUINT32(MF_MT_AVG_BITRATE, TARGET_AVERAGE_BIT_RATE);
    CHECK_HR(hr, "Failed to set average bit rate on H264 output media type");

    hr = MFSetAttributeSize(outputType, MF_MT_FRAME_SIZE, desc.Width, desc.Height);
    CHECK_HR(hr, "Failed to set frame size on H264 MFT out type");

    hr = MFSetAttributeRatio(outputType, MF_MT_FRAME_RATE, TARGET_FRAME_RATE, 1);
    CHECK_HR(hr, "Failed to set frame rate on H264 MFT out type");

    hr = outputType->SetUINT32(MF_MT_INTERLACE_MODE, 2);
    CHECK_HR(hr, "Failed to set MF_MT_INTERLACE_MODE on H.264 encoder MFT");

    hr = outputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
    CHECK_HR(hr, "Failed to set MF_MT_ALL_SAMPLES_INDEPENDENT on H.264 encoder MFT");

    hr = _pTransform->SetOutputType(outputStreamID, outputType, 0);
    CHECK_HR(hr, "Failed to set output media type on H.264 encoder MFT");

    hr = MFCreateMediaType(&inputType);
    CHECK_HR(hr, "Failed to create media type");

    for (DWORD i = 0;; i++)
    {
        inputType = nullptr;
        hr = _pTransform->GetInputAvailableType(inputStreamID, i, &inputType);
        CHECK_HR(hr, "Failed to get input type");

        hr = inputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
        CHECK_HR(hr, "Failed to set MF_MT_MAJOR_TYPE on H264 MFT input type");

        hr = inputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
        CHECK_HR(hr, "Failed to set MF_MT_SUBTYPE on H264 MFT input type");

        hr = MFSetAttributeSize(inputType, MF_MT_FRAME_SIZE, desc.Width, desc.Height);
        CHECK_HR(hr, "Failed to set MF_MT_FRAME_SIZE on H264 MFT input type");

        hr = MFSetAttributeRatio(inputType, MF_MT_FRAME_RATE, TARGET_FRAME_RATE, 1);
        CHECK_HR(hr, "Failed to set MF_MT_FRAME_RATE on H264 MFT input type");

        hr = _pTransform->SetInputType(inputStreamID, inputType, 0);
        CHECK_HR(hr, "Failed to set input type");

        break;
    }

    CheckHardwareSupport();

    CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL), "Failed to process FLUSH command on H.264 MFT.\n");
    CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL), "Failed to process BEGIN_STREAMING command on H.264 MFT.\n");
    CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL), "Failed to process START_OF_STREAM command on H.264 MFT.\n");

    return true;

done:

    printf("MediaFoundationH264LiveSource initialisation failed.\n");
    return false;
}


    HRESULT CheckHardwareSupport()
    {
        IMFAttributes *attributes;
        HRESULT hr = _pTransform->GetAttributes(&attributes);
        UINT32 dxva = 0;

        if (SUCCEEDED(hr))
        {
            hr = attributes->GetUINT32(MF_SA_D3D11_AWARE, &dxva);
        }

        if (SUCCEEDED(hr))
        {
            hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE);
        }

#if defined(CODECAPI_AVLowLatencyMode) // Win8 only

        hr = _pTransform->QueryInterface(IID_PPV_ARGS(&mpCodecAPI));

        if (SUCCEEDED(hr))
        {
            VARIANT var = { 0 };

            // FIXME: encoder only
            var.vt = VT_UI4;
            var.ulVal = 0;

            hr = mpCodecAPI->SetValue(&CODECAPI_AVEncMPVDefaultBPictureCount, &var);

            var.vt = VT_BOOL;
            var.boolVal = VARIANT_TRUE;
            hr = mpCodecAPI->SetValue(&CODECAPI_AVEncCommonLowLatency, &var);
            hr = mpCodecAPI->SetValue(&CODECAPI_AVEncCommonRealTime, &var);

            hr = attributes->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE);

            if (SUCCEEDED(hr))
            {
                var.vt = VT_UI4;
                var.ulVal = eAVEncCommonRateControlMode_Quality;
                hr = mpCodecAPI->SetValue(&CODECAPI_AVEncCommonRateControlMode, &var);

                // This property controls the quality level when the encoder is not using a constrained bit rate. The AVEncCommonRateControlMode property determines whether the bit rate is constrained.
                VARIANT quality;
                InitVariantFromUInt32(50, &quality);
                hr = mpCodecAPI->SetValue(&CODECAPI_AVEncCommonQuality, &quality);
            }
        }
#endif

        return hr;
    }

ffplay कमांड:

ffplay -protocol_whitelist file,udp,rtp -i test.sdp -x 800 -y 600 -profile:v baseline

एसडीपी:

v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
t=0 0
c=IN IP4 127.0.0.1
m=video 1234 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1

मुझे नहीं पता कि मैं क्या याद कर रहा हूं, मैं लगभग एक सप्ताह तक इसे बिना किसी प्रगति के ठीक करने की कोशिश कर रहा हूं, और लगभग हर चीज की कोशिश कर रहा हूं जो मैं कर सकता था। इसके अलावा, एक DirectX सतह को वीडियो के रूप में एन्कोडिंग करने के लिए ऑनलाइन संसाधन बहुत सीमित हैं।

किसी भी सहायता की सराहना की जाएगी।


1
मुझे लगता है कि आप गलत तरीके से doGetNextFrame को METransformNeedInput के बाद फिर से कॉल करने की उम्मीद करते हैं। हो सकता है कि आपको तब तक इसके अंदर लूप करना चाहिए जब तक आपको एक वैध ProcessOutput कॉल न मिल जाए।
वूवर्ट

hr = event-> GetType (& eventType); स्विच (EventType) {....} अगर (? फ्रेमसेट) {envir ()। taskScheduler ()। trigEvent (eventTriggerId, यह); } उपरोक्त 2 ब्लॉक अच्छी तरह से कॉल करने का ख्याल रखते हैं जब तक कि हम एनकोडर से आउटपुट प्राप्त नहीं कर लेते। मैंने उसी का सत्यापन किया है। @VuVirt
राम

तो क्या होता है जब फ्रेमसेट सत्य होता है? क्या आप इस मामले में एक नई घटना को ट्रिगर करते हैं? आपके पास उसके बाद "वापसी" कथन है।
VuVirt

@VuVirt यह एक लूप में अंतर्निहित live555 लाइब्रेरी द्वारा स्वचालित रूप से कहा जाता है। "ProcessInput" और "ProcessOutput" को वैकल्पिक रूप से स्विच स्टेटमेंट में घटना के आधार पर कहा जाता है। मुझे ProcessOut से एक सतत स्ट्रीम मिल रहा है, लेकिन इसे देखने में सक्षम नहीं है। मुझे यकीन है कि मैं सही ढंग से नमूना समय और अवधि निर्धारित कर रहा हूं।
राम

1
आपको यह जांचने की आवश्यकता हो सकती है कि क्या आपको ProcessOutput से MF_E_TRANSFORM_STREAM_CHANGE प्राप्त हुआ है या नहीं और तदनुसार प्रारूप को संभालना है।
VuVirt

जवाबों:


6

ऐसा लगता है कि यह कठिन है।

यदि आप एनकोडर का उपयोग करना चाहते हैं जैसा कि आप कर रहे हैं, तो सीधे IMFTransform इंटरफ़ेस को कॉल करके , आपको RGB फ्रेम को NV12 में बदलना होगा। यदि आप अच्छा प्रदर्शन चाहते हैं, तो आपको इसे GPU पर करना चाहिए। पिक्सेल शेड्स के साथ करना संभव है, 2 फ्रेम रेंडर करें, DXGI_FORMAT_R8_UNORM में पूर्ण आकार एक, चमक के साथ लक्ष्य प्रस्तुत करें, रंग में DXGI_FORMAT_R8G8_UNORM लक्ष्य में आधा आकार और NV12 मान उत्पन्न करने के लिए दो पिक्सेल शेड लिखें। दोनों लक्ष्य एक ही NV12 बनावट के 2 विमानों में प्रस्तुत कर सकते हैं, लेकिन केवल विंडोज 8 के बाद से।

अन्य विधि का उपयोग सिंक लेखक है । यह एक ही समय में कई एमएफटी की मेजबानी कर सकता है ताकि आप वीआरएएम में आरजीबी बनावट की आपूर्ति कर सकें, सिंक लेखक पहले उन्हें एनवी 12 में एक एमएफटी के साथ परिवर्तित कर देगा (यह संभावना है कि जीपीयू चालक द्वारा कार्यान्वित एक हार्डवेयर, एनकोडर की तरह), फिर MFT को एनकोडर करने के लिए पास। एक mp4 फ़ाइल में एनकोड करना अपेक्षाकृत आसान है, लेखक बनाने के लिए MFCreateSinkWriterFromURL API का उपयोग करें। यह बहुत मुश्किल है कि कच्चे नमूने सिंक लेखक से बाहर निकले, लेकिन आपको वीडियो स्ट्रीम के लिए कस्टम मीडिया सिंक, कस्टम स्ट्रीम सिंक लागू करना होगा और लेखक को बनाने के लिए MFCreateSinkWriterFromMediaSink को कॉल करना होगा।

अभी और है।

एन्कोडिंग विधियों पर ध्यान दिए बिना, आप फ़्रेम बनावट का पुन: उपयोग नहीं कर सकते। प्रत्येक फ्रेम जो आपको डीडी से मिलता है, आपको एक नई बनावट तैयार करनी चाहिए और इसे एमएफ को पास करना चाहिए।

वीडियो एनकोडर निरंतर फ्रेम दर की उम्मीद करते हैं। डीडी आपको वह नहीं देता है, यह आपको स्क्रीन पर हर बार कुछ बदलाव के लिए एक फ्रेम देता है। यदि आपके पास गेमिंग मॉनीटर है तो 144 FPS हो सकता है, यदि केवल ब्लिंकिंग कर्सर में 2 FPS हो सकते हैं। आदर्श रूप से, आपको अपने वीडियो मीडिया प्रकार में निर्दिष्ट स्थिर फ्रेम दर पर एमएफ को फ्रेम जमा करना चाहिए।

यदि आप नेटवर्क पर स्ट्रीम करना चाहते हैं, तो अधिक बार आपको पैरामीटर सेट की आपूर्ति नहीं करनी है। जब तक आप Intel हार्डवेयर h265 एनकोडर का उपयोग नहीं कर रहे हैं, जो Intel से कोई टिप्पणी नहीं मिली है , MF आपको MF_MT_MPEG_SEQUENCE_HEADER में मीडिया प्रकार की सुविधा देता है, जो कि IMFCediaTypeHandler इंटरफ़ेस में SetCurrentMediaType को कॉल करके। आप उस इंटरफ़ेस को अधिसूचित करने के लिए कार्यान्वित कर सकते हैं। एन्कोडिंग शुरू करने के बाद आपको केवल वह डेटा मिलेगा। यदि आप एक सिंक लेखक का उपयोग करते हैं, तो IMFTransformविधि के लिए यह आसान है, आपको विधि MF_E_TRANSFORM_STREAM_CHANGEसे कोड प्राप्त करना चाहिए ProcessOutput, फिर GetOutputAvailableTypeअपडेट किए गए मीडिया प्रकार को उस डेटा ब्लॉब के साथ प्राप्त करने के लिए कॉल करें ।


आपका मतलब है कि डायरेक्टएक्स (डेस्कटॉप दोहराव) NV12 फॉर्मेट में फ्रेम वितरित नहीं करता है, तब भी जब डिवाइस डीएक्सडीआई_FORM__N_N12 और ट्रांसफॉर्मेशन में MFT_MESSAGE_SET_D3D_MANAGER सेट करने के लिए D3D11_CREATE_DEVICE_VIDEO_SUPPORT और सतही डिस्क्रिप्टर के साथ intialized है, तब भी। मुझे भी लगा कि हमें RGB बफर को NV12 या किसी भी समर्थित इनपुट फॉर्मेट (ज्यादातर YUV के वेरिएंट) में स्पष्ट रूप से बदलना होगा या सिंकड्राइटर का उपयोग करना होगा। लेकिन, यह व्यक्ति किसी भी तरह से मेरे दृष्टिकोण से खुद को हासिल करने में सक्षम था। stackoverflow.com/questions/43432670/…
राम


1
@ राम डेस्कटॉप दोहराव हमेशा DXGI_FORMAT_B8G8R8A8_UNORMप्रारूप में RGB फ्रेम बचाता है । H264 और h265 एनकोडर एमएफटी केवल NV12 और युगल दूसरों का समर्थन करते हैं, समान रूप से अजीब हैं। किसी को रूपांतरित करना है। आप डेस्कटॉप दोहराव का उपयोग करते हैं; आप पहले से ही इसके साथ विंडोज 7 का समर्थन नहीं कर सकते। एक सिंक लेखक का उपयोग करें। मुझे पूरा यकीन है कि ये nVidia / Intel के हार्डवेयर MFTs, RGB को NV12 में बदलने के लिए पिक्सेल shader ALU की तुलना में अधिक कुशल हैं, उन्होंने संभवतः हार्डवेयर में विशुद्ध रूप से लागू किया है।
सूट्स 11

तुम सही हो। रंग रूपांतरण स्पष्ट रूप से किया जाना चाहिए। github.com/GPUOpen-LibrariesAndSDKs/AMF/issues/92 । मैं उस दिशा में आगे बढ़ रहा हूं।
राम

1
@ राम यह काम करना चाहिए, मैंने पहले भी किया था। जब डीडी आपको एक नया फ्रेम देने से इंकार करता है क्योंकि कोई अपडेट नहीं था, तो आप फिर से एनकोडर को एक ही बनावट सबमिट करके बहुत सारे वीआरएएम को बचा सकते हैं। जब डीडी के पास नया फ्रेम हो तब ही नए टेक्सचर बनाएं। लेकिन यह पता लगाने के लिए कोड कि आपको फ्रेम कब जमा करना चाहिए और कितनी देर तक इंतजार करना है तुच्छ नहीं है। मैंने समय को मापने के लिए QueryPerformanceCounter का उपयोग किया है, और यह पता लगाने के लिए कि मुझे पकड़ना चाहिए, या क्या मुझे सोना चाहिए, पिछले कुछ फ़्रेमों पर किसी तरह का रोलिंग औसत। BTW, सोने का सही तरीका IDXGIOutput :: WaitForVBlank तरीका है।
सूट्स

1

चूंकि ffplayमैं स्ट्रीम मापदंडों के बारे में शिकायत कर रहा हूं, इसलिए मुझे लगता है कि यह एसपीएस / पीपीएस नहीं उठा सकता है। आपने उन्हें अपने हार्डकोड एसडीपी में सेट नहीं किया है - RFC-3984 देखें और देखें sprop-parameter-sets। RFC से एक उदाहरण:

m = वीडियो 49170 RTP / AVP 98
a = rtpmap: 98 H264 / 90000
a = fmtp: 98 प्रोफाइल-स्तर-आईडी = 42A01E; स्प्रॉप-पैरामीटर-सेट = Z0IACCZTBYmI, aMljiA ==

मैं दृढ़ता ffplayसे एसडीपी में इन की उम्मीद कर रहा हूं । मुझे दिल से याद नहीं है कि मीडिया फाउंडेशन एनकोडर से एसपीएस / पीपीएस कैसे प्राप्त करें, लेकिन या तो नमूना पेलोड में हैं और आपको उचित एनएएल इकाइयों या Google को देखकर उन्हें निकालने की आवश्यकता है कि अतिरिक्त डेटा कैसे निकाला जाए। एनकोडर - पहला हिट मुझे आशाजनक लग रहा था।


यह एक वैध बिंदु है। मुझे भी एसपीएस / पीपीएस पर संदेह है। मैं अभी इसे सत्यापित कर रहा हूँ। मुझे MSDN थ्रेड को निर्देशित करने के लिए धन्यवाद जो मुझे कुछ उम्मीद देता है।
राम

@ अच्छा नमूना है कि एसपीएस / पीपीएस सैंपल पेलोड में हैं, इसलिए मैं पहले जांच करूंगा।
रुडोल्फ्स बुंडूलिस

हाँ, मैं समझता हूँ कि। जब मैं Mpeg4MediaSink के माध्यम से एक फ़ाइल के लिए नमूने लिखने की कोशिश की, तो मुझे सीधे मीडिया फाउंडेशन एन्कोडर्स से एसपीएस / पीपीएस प्राप्त करने और पार्स करने का कुछ ज्ञान मिला है। मैं इस दिशा में आगे बढ़ूंगा।
राम

1

Soonts आपकी समस्या को हल करने के लिए आपको सभी आवश्यक चीजें देता है।

पहली चीज़ जो आपको करने की ज़रूरत है, वह है DXGI_FORMAT_B8G8R8A8_UNORM और MFVideoFormat_NV12 के बीच प्रारूप रूपांतरण:

प्रारूप रूपांतरण

प्रारूप रूपांतरण जानकारी

मुझे लगता है कि प्रारूप रूपांतरण करने के लिए shader का उपयोग करना बेहतर है, क्योंकि सभी बनावट GPU (प्रदर्शन के लिए बेहतर) में रहेगी।

यह पहला कदम है जो आपको करने की आवश्यकता है। अपने कार्यक्रम को बेहतर बनाने के लिए आपके पास अन्य होंगे।


1
2x4 छवि NV12 में 12 बाइट्स लेती है न कि 24: 8 चमक मान जो आपके पास हैं, लेकिन रंग छवि दो गुना छोटी है, 1x2 पिक्सेल, इसलिए उस 2x4 छवि की रंग जानकारी के लिए कुल 4 बाइट्स, 2 बाइट्स यू के लिए वी। के लिए 2 बाइट्स
19 को सूट्स

हां, आप सही हैं, मैंने downsampling को NV12 प्रारूप के 4.2.0 पर छोड़ दिया। मैं एक अधिक फिटिंग आरेख बनाने की कोशिश करूंगा।
mofo77
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.