Dela via


Okomprimerade videobuffertar

Den här artikeln beskriver hur du arbetar med mediebuffertar som innehåller okomprimerade videoramar. I prioritetsordning är följande alternativ tillgängliga. Alla mediebuffertar stöder inte varje alternativ.

  1. Använd den underliggande Direct3D-ytan. (Gäller endast för videoramar som lagras i Direct3D-ytor.)
  2. Använd gränssnittet IMF2DBuffer.
  3. Använd gränssnittet IMFMediaBuffer.

Använda den underliggande Direct3D-ytan

Videoramen kan lagras i en Direct3D-yta. I så fall kan du få en pekare till ytan genom att anropa IMFGetService::GetService eller MFGetService på mediebuffertobjektet. Använd tjänstidentifieraren MR_BUFFER_SERVICE. Den här metoden rekommenderas när komponenten som kommer åt videoramen är utformad för att använda Direct3D. En videodekodare som stöder DirectX Video Acceleration bör till exempel använda den här metoden.

Följande kod visar hur du hämtar IDirect3DSurface9 pekare från en mediebuffert.

IDirect3DSurface9 *pSurface = NULL;

hr = MFGetService(
    pBuffer, 
    MR_BUFFER_SERVICE,
    __uuidof(IDirect3DSurface9), 
    (void**)&pSurface
    );

if (SUCCEEDED(hr))
{
    // Call IDirect3DSurface9 methods.
}

Följande objekt stöder MR_BUFFER_SERVICE-tjänsten:

Använda IMF2DBuffer-gränssnittet

Om videoramen inte lagras i en Direct3D-yta, eller om komponenten inte är utformad för att använda Direct3D, är nästa rekommenderade sätt att komma åt videoramen att fråga bufferten för IMF2DBuffer-gränssnittet. Det här gränssnittet är särskilt utformat för bilddata. Om du vill få en pekare till det här gränssnittet anropar du QueryInterface på mediebufferten. Alla mediebuffertobjekt exponerar inte det här gränssnittet. Men om en mediebuffert exponerar IMF2DBuffer- gränssnitt bör du använda det gränssnittet för att komma åt data, om möjligt, snarare än att använda IMFMediaBuffer. Du kan fortfarande använda IMFMediaBuffer-gränssnittet, men det kan vara mindre effektivt.

  1. Anropa QueryInterface på mediebufferten för att hämta IMF2DBuffer- gränssnitt.
  2. Anropa IMF2DBuffer::Lock2D för att komma åt minnet för bufferten. Den här metoden returnerar en pekare till den första byte av den översta raden med bildpunkter. Den returnerar också bildsteget, vilket är antalet byte från början av en rad med bildpunkter till början av nästa rad. Bufferten kan innehålla utfyllnadsbyte efter varje rad med bildpunkter, så steget kan vara bredare än bildbredden i byte. Stride kan också vara negativt om bilden är orienterad nedifrån och upp i minnet. Mer information finns i Image Stride.
  3. Behåll bufferten låst endast när du behöver komma åt minnet. Lås upp bufferten genom att anropa IMF2DBuffer::Unlock2D.

Alla mediebuffertar implementerar inte IMF2DBuffer- gränssnitt. Om mediebufferten inte implementerar det här gränssnittet (dvs. buffertobjektet returnerar E_NOINTERFACE i steg 1) måste du använda IMFMediaBuffer gränssnittsgränssnitt, som beskrivs härnäst.

Använda IMFMediaBuffer-gränssnittet

Om en mediebuffert inte exponerar IMF2DBuffer- gränssnitt använder du IMFMediaBuffer-gränssnittet. De allmänna semantiken i det här gränssnittet beskrivs i avsnittet Arbeta med mediebuffertar.

  1. Anropa QueryInterface på mediebufferten för att hämta IMFMediaBuffer- gränssnitt.
  2. Anropa IMFMediaBuffer::Lås för att få åtkomst till buffertminnet. Den här metoden returnerar en pekare till buffertminnet. När metoden Lock används är steget alltid det minsta steget för videoformatet i fråga, utan extra utfyllnadsbyte.
  3. Behåll bufferten låst endast när du behöver komma åt minnet. Lås upp bufferten genom att anropa IMFMediaBuffer::Lås upp.

Du bör alltid undvika att anropa IMFMediaBuffer::Lås om bufferten exponerar IMF2DBuffer, eftersom metoden Lock kan tvinga buffertobjektet till videoramen till ett sammanhängande minnesblock och sedan tillbaka igen. Å andra sidan, om bufferten inte stöder IMF2DBuffer, kommer IMFMediaBuffer::Lås förmodligen inte att resultera i en kopia.

Beräkna minsta steg från medietypen enligt följande:

  • Minsta steg kan lagras i attributet MF_MT_DEFAULT_STRIDE.
  • Om attributet MF_MT_DEFAULT_STRIDE inte har angetts anropar du funktionen MFGetStrideForBitmapInfoHeader för att beräkna steget för de vanligaste videoformaten.
  • Om funktionen MFGetStrideForBitmapInfoHeader inte känner igen formatet måste du beräkna steget baserat på definitionen av formatet. I så fall finns det ingen allmän regel. du behöver känna till information om formatdefinitionen.

Följande kod visar hur du får standardsteget för de vanligaste videoformaten.

HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride)
{
    LONG lStride = 0;

    // Try to get the default stride from the media type.
    HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
    if (FAILED(hr))
    {
        // Attribute not set. Try to calculate the default stride.

        GUID subtype = GUID_NULL;

        UINT32 width = 0;
        UINT32 height = 0;

        // Get the subtype and the image size.
        hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lStride);
        if (FAILED(hr))
        {
            goto done;
        }

        // Set the attribute for later reference.
        (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride));
    }

    if (SUCCEEDED(hr))
    {
        *plStride = lStride;
    }

done:
    return hr;
}

Beroende på ditt program kanske du i förväg vet om en viss mediebuffert stöder IMF2DBuffer- (till exempel om du har skapat bufferten). Annars måste du vara beredd att använda något av de två buffertgränssnitten.

I följande exempel visas en hjälpklass som döljer vissa av dessa uppgifter. Den här klassen har en LockBuffer-metod som anropar antingen Lock2D eller Lock och returnerar en pekare till början av den första raden med pixlar. (Det här beteendet matchar metoden Lock2D.) Metoden LockBuffer tar standardsteget som indataparameter och returnerar det faktiska steget som en utdataparameter.

class CBufferLock
{
public:
    CBufferLock(IMFMediaBuffer *pBuffer) : m_p2DBuffer(NULL), m_bLocked(FALSE)
    {
        m_pBuffer = pBuffer;
        m_pBuffer->AddRef();

        m_pBuffer->QueryInterface(IID_IMF2DBuffer, (void**)&m_p2DBuffer);
    }

    ~CBufferLock()
    {
        UnlockBuffer();
        SafeRelease(&m_pBuffer);
        SafeRelease(&m_p2DBuffer);
    }

    HRESULT LockBuffer(
        LONG  lDefaultStride,    // Minimum stride (with no padding).
        DWORD dwHeightInPixels,  // Height of the image, in pixels.
        BYTE  **ppbScanLine0,    // Receives a pointer to the start of scan line 0.
        LONG  *plStride          // Receives the actual stride.
        )
    {
        HRESULT hr = S_OK;

        // Use the 2-D version if available.
        if (m_p2DBuffer)
        {
            hr = m_p2DBuffer->Lock2D(ppbScanLine0, plStride);
        }
        else
        {
            // Use non-2D version.
            BYTE *pData = NULL;

            hr = m_pBuffer->Lock(&pData, NULL, NULL);
            if (SUCCEEDED(hr))
            {
                *plStride = lDefaultStride;
                if (lDefaultStride < 0)
                {
                    // Bottom-up orientation. Return a pointer to the start of the
                    // last row *in memory* which is the top row of the image.
                    *ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1);
                }
                else
                {
                    // Top-down orientation. Return a pointer to the start of the
                    // buffer.
                    *ppbScanLine0 = pData;
                }
            }
        }

        m_bLocked = (SUCCEEDED(hr));

        return hr;
    }
    
    void UnlockBuffer()
    {
        if (m_bLocked)
        {
            if (m_p2DBuffer)
            {
                (void)m_p2DBuffer->Unlock2D();
            }
            else
            {
                (void)m_pBuffer->Unlock();
            }
            m_bLocked = FALSE;
        }
    }

private:
    IMFMediaBuffer  *m_pBuffer;
    IMF2DBuffer     *m_p2DBuffer;

    BOOL            m_bLocked;
};

Image Stride

mediebuffertar