Mémoires tampons vidéo non compressées

Cet article explique comment utiliser des mémoires tampons multimédias qui contiennent des images vidéo non compressées. Dans l’ordre de préférence, les options suivantes sont disponibles. Toutes les mémoires tampons multimédias ne prennent pas en charge chaque option.

  1. Utilisez la surface Direct3D sous-jacente. (S’applique uniquement aux images vidéo stockées dans des surfaces Direct3D.)
  2. Utilisez l’interface IMF2DBuffer .
  3. Utilisez l’interface IMFMediaBuffer .

Utiliser la surface Direct3D sous-jacente

La trame vidéo peut être stockée à l’intérieur d’une surface Direct3D. Si c’est le cas, vous pouvez obtenir un pointeur vers la surface en appelant IMFGetService::GetService ou MFGetService sur l’objet de mémoire tampon multimédia. Utilisez l’identificateur de service MR_BUFFER_SERVICE. Cette approche est recommandée lorsque le composant accédant à la trame vidéo est conçu pour utiliser Direct3D. Par exemple, un décodeur vidéo qui prend en charge l’accélération vidéo DirectX doit utiliser cette approche.

Le code suivant montre comment obtenir le pointeur IDirect3DSurface9 à partir d’une mémoire tampon multimédia.

IDirect3DSurface9 *pSurface = NULL;

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

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

Les objets suivants prennent en charge le service MR_BUFFER_SERVICE :

Utiliser l’interface IMF2DBuffer

Si la trame vidéo n’est pas stockée dans une surface Direct3D ou si le composant n’est pas conçu pour utiliser Direct3D, la méthode recommandée suivante pour accéder à la trame vidéo consiste à interroger la mémoire tampon pour l’interface IMF2DBuffer . Cette interface est conçue spécifiquement pour les données d’image. Pour obtenir un pointeur vers cette interface, appelez QueryInterface sur la mémoire tampon multimédia. Tous les objets de mémoire tampon multimédia n’exposent pas cette interface. Toutefois, si une mémoire tampon multimédia expose l’interface IMF2DBuffer , vous devez utiliser cette interface pour accéder aux données, si possible, plutôt que d’utiliser IMFMediaBuffer. Vous pouvez toujours utiliser l’interface IMFMediaBuffer , mais elle peut être moins efficace.

  1. Appelez QueryInterface sur la mémoire tampon multimédia pour obtenir l’interface IMF2DBuffer .
  2. Appelez IMF2DBuffer::Lock2D pour accéder à la mémoire mémoire de la mémoire tampon. Cette méthode retourne un pointeur vers le premier octet de la ligne supérieure de pixels. Elle retourne également la foulée de l’image, qui correspond au nombre d’octets entre le début d’une ligne de pixels et le début de la ligne suivante. La mémoire tampon peut contenir des octets de remplissage après chaque ligne de pixels, de sorte que la foulée peut être plus large que la largeur de l’image en octets. Stride peut également être négatif si l’image est orientée de bas en haut en mémoire. Pour plus d’informations, consultez Image Stride.
  3. Conservez la mémoire tampon verrouillée uniquement pendant que vous avez besoin d’accéder à la mémoire. Déverrouillez la mémoire tampon en appelant IMF2DBuffer::Unlock2D.

Tous les tampons multimédias n’implémentent pas l’interface IMF2DBuffer . Si la mémoire tampon multimédia n’implémente pas cette interface (autrement dit, l’objet buffer retourne E_NOINTERFACE à l’étape 1), vous devez utiliser l’interface d’interface IMFMediaBuffer , décrite ci-dessous.

Utiliser l’interface IMFMediaBuffer

Si une mémoire tampon multimédia n’expose pas l’interface IMF2DBuffer , utilisez l’interface IMFMediaBuffer . La sémantique générale de cette interface est décrite dans la rubrique Utilisation des mémoires tampons multimédias.

  1. Appelez QueryInterface sur la mémoire tampon multimédia pour obtenir l’interface IMFMediaBuffer .
  2. Appelez IMFMediaBuffer::Lock pour accéder à la mémoire tampon. Cette méthode retourne un pointeur vers la mémoire tampon. Lorsque la méthode Lock est utilisée, la foulée est toujours la foulée minimale pour le format vidéo en question, sans octets de remplissage supplémentaires.
  3. Conservez la mémoire tampon verrouillée uniquement pendant que vous avez besoin d’accéder à la mémoire. Déverrouillez la mémoire tampon en appelant IMFMediaBuffer::Unlock.

Vous devez toujours éviter d’appeler IMFMediaBuffer::Lock si la mémoire tampon expose IMF2DBuffer, car la méthode Lock peut forcer l’objet de mémoire tampon à l’image vidéo dans un bloc de mémoire contiguë, puis revenir à nouveau. En revanche, si la mémoire tampon ne prend pas en charge IMF2DBuffer, IMFMediaBuffer::Lock n’aboutira probablement pas à une copie.

Calculez la foulée minimale à partir du type de média comme suit :

  • La foulée minimale peut être stockée dans l’attribut MF_MT_DEFAULT_STRIDE .
  • Si l’attribut MF_MT_DEFAULT_STRIDE n’est pas défini, appelez la fonction MFGetStrideForBitmapInfoHeader pour calculer la foulée pour les formats vidéo les plus courants.
  • Si la fonction MFGetStrideForBitmapInfoHeader ne reconnaît pas le format, vous devez calculer la foulée en fonction de la définition du format. Dans ce cas, il n’y a pas de règle générale; vous devez connaître les détails de la définition de format.

Le code suivant montre comment obtenir la progression par défaut pour les formats vidéo les plus courants.

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;
}

Selon votre application, vous pouvez savoir à l’avance si une mémoire tampon de média donnée prend en charge IMF2DBuffer (par exemple, si vous avez créé la mémoire tampon). Sinon, vous devez être prêt à utiliser l’une des deux interfaces de mémoire tampon.

L’exemple suivant montre une classe d’assistance qui masque certains de ces détails. Cette classe a une méthode LockBuffer qui appelle Lock2D ou Lock et retourne un pointeur vers le début de la première ligne de pixels. (Ce comportement correspond à la méthode Lock2D .) La méthode LockBuffer prend la foulée par défaut en tant que paramètre d’entrée et retourne la foulée réelle en tant que paramètre de sortie.

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;
};

Stride d’image

Mémoires tampons multimédias