Lire en anglais

Partager via


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. Chaque mémoire tampon multimédia ne prend 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’interfaceIMF2DBuffer.
  3. Utilisez l’interfaceIMFMediaBuffer.

Utiliser la surface Direct3D sous-jacente

La trame vidéo peut être stockée à l’intérieur d’une surface Direct3D. Dans ce 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 DirectX Video Acceleration 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 l’image vidéo n’est pas stockée à l’intérieur d’une surface Direct3D ou si le composant n’est pas conçu pour utiliser Direct3D, la prochaine méthode recommandée 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. Mais 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 pour 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 progression de l’image, qui correspond au nombre d’octets du début d’une ligne de pixels au 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 progression peut être plus large que la largeur de l’image en octets. Stride peut également être négatif si l’image est orientée vers le bas en mémoire. Pour plus d’informations, consultez Image Stride .
  3. Conservez la mémoire tampon verrouillée uniquement pendant que vous devez accéder à la mémoire. Déverrouillez la mémoire tampon en appelant IMF2DBuffer ::Unlock2D.

Chaque mémoire tampon multimédia implémente l’interface IMF2DBuffer. Si la mémoire tampon multimédia n’implémente pas cette interface (autrement dit, l’objet de mémoire tampon retourne E_NOINTERFACE à l’étape 1), vous devez utiliser l’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 progression est toujours la progression 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 devez 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 tampon à l’image vidéo dans un bloc de mémoire contiguë, puis de retour à nouveau. En revanche, si la mémoire tampon ne prend pas en charge IMF2DBuffer, IMFMediaBuffer ::Lock n’entraîne probablement pas de copie.

Calculez le pas minimal à partir du type de média comme suit :

  • La progression 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 progression pour les formats vidéo les plus courants.
  • Si la fonction MFGetStrideForBitmapInfoHeader ne reconnaît pas le format, vous devez calculer la progression en fonction de la définition du format. Dans ce cas, il n’existe aucune règle générale ; vous devez connaître les détails de la définition de format.

Le code suivant montre comment obtenir le pas 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 multimé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 au début de la première ligne de pixels. (Ce comportement correspond à la méthode lock2D.) La méthode LockBuffer prend le pas par défaut en tant que paramètre d’entrée et retourne le pas réel 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;
};

d’image stride

tampons multimédias