次の方法で共有


圧縮されていないビデオ バッファー

この記事では、圧縮されていないビデオ フレームを含むメディア バッファーを操作する方法について説明します。 優先順に、次のオプションを使用できます。 すべてのメディア バッファーで各オプションがサポートされているわけではありません。

  1. 基になる Direct3D サーフェスを使用します。 (Direct3D サーフェスに格納されているビデオ フレームにのみ適用されます)。
  2. IMF2DBuffer インターフェイスを使用します。
  3. IMFMediaBuffer インターフェイスを使用します。

基になる Direct3D サーフェスを使用する

ビデオ フレームは Direct3D サーフェス内に格納される場合があります。 その場合は、IMFGetService::GetService呼び出すか、メディア バッファー オブジェクトで MFGetServiceすることで、サーフェスへのポインターを取得できます。 サービス識別子MR_BUFFER_SERVICEを使用します。 この方法は、ビデオ フレームにアクセスするコンポーネントが Direct3D を使用するように設計されている場合に推奨されます。 たとえば、DirectX ビデオ アクセラレーションをサポートするビデオ デコーダーでは、このアプローチを使用する必要があります。

次のコードは、メディア バッファーから IDirect3DSurface9 ポインターを取得する方法を示しています。

IDirect3DSurface9 *pSurface = NULL;

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

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

次のオブジェクトは、MR_BUFFER_SERVICE サービスをサポートしています。

IMF2DBuffer インターフェイスを使用する

ビデオ フレームが Direct3D サーフェス内に格納されていない場合、またはコンポーネントが Direct3D を使用するように設計されていない場合、次に推奨されるビデオ フレームへのアクセス方法は、IMF2DBuffer インターフェイスのバッファーを照会することです。 このインターフェイスは、画像データ専用に設計されています。 このインターフェイスへのポインターを取得するには、メディア バッファー QueryInterface を呼び出します。 すべてのメディア バッファー オブジェクトがこのインターフェイスを公開しているわけではありません。 ただし、メディア バッファーが IMF2DBuffer インターフェイス 公開している場合は、可能であれば、そのインターフェイスを使用してデータにアクセス 、IMFMediaBufferを使用する必要があります。 IMFMediaBuffer インターフェイスは引き続き使用できますが、効率が低下する可能性があります。

  1. メディア バッファー QueryInterface を呼び出して、IMF2DBuffer インターフェイスを取得します。
  2. IMF2DBuffer::Lock2D呼び出して、バッファーのメモリにアクセスします。 このメソッドは、ピクセルの先頭行の最初のバイトへのポインターを返します。 また、イメージストライドも返されます。これは、ピクセルの行の先頭から次の行の先頭までのバイト数です。 バッファーには、ピクセルの各行の後に埋め込みバイトが含まれている可能性があるため、ストライドはイメージの幅 (バイト単位) よりも広い可能性があります。 ストライドは、画像がメモリ内のボトムアップ方向にある場合にも負の値になる可能性があります。 詳細については、「イメージ ストライド 」を参照してください。
  3. メモリにアクセスする必要がある間だけ、バッファーをロックしたままにしておきます。 IMF2DBuffer::Unlock2D呼び出してバッファーのロックを解除します。

すべてのメディア バッファーが IMF2DBufferインターフェイス実装しているわけではありません。 メディア バッファーがこのインターフェイスを実装していない場合 (つまり、バッファー オブジェクトは手順 1 でE_NOINTERFACEを返します)、次に説明する IMFMediaBuffer インターフェイス インターフェイスを使用する必要があります。

IMFMediaBuffer インターフェイスを使用する

メディア バッファーが IMF2DBufferインターフェイス公開しない場合は、IMFMediaBuffer インターフェイスを使用します。 このインターフェイスの一般的なセマンティクスについては、「メディア バッファーの操作 」を参照してください。

  1. メディア バッファー QueryInterface を呼び出して、IMFMediaBuffer インターフェイスを取得します。
  2. IMFMediaBuffer::Lock呼び出してバッファー メモリにアクセスします。 このメソッドは、バッファー メモリへのポインターを返します。 Lock メソッドを使用する場合、ストライドは常に問題のビデオ形式の最小ストライドであり、余分なパディング バイトはありません。
  3. メモリにアクセスする必要がある間だけ、バッファーをロックしたままにしておきます。 IMFMediaBuffer::Unlock呼び出してバッファーのロックを解除します。

バッファーが IMF2DBuffer公開されている場合は、常に IMFMediaBuffer::Lock呼び出さないようにする必要があります。これは、Lock メソッドによって、バッファー オブジェクトをビデオ フレームに強制的に連続したメモリ ブロックにしてから、もう一度戻すことができるためです。 一方、バッファーが IMF2DBuffer サポートしていない場合、IMFMediaBuffer::Lock しても、コピーは行われません。

メディアの種類から最小ストライドを次のように計算します。

  • 最小ストライドは、MF_MT_DEFAULT_STRIDE 属性に格納される場合があります。
  • MF_MT_DEFAULT_STRIDE 属性が設定されていない場合は、MFGetStrideForBitmapInfoHeader 関数を呼び出して、最も一般的なビデオ形式のストライドを計算します。
  • MFGetStrideForBitmapInfoHeader 関数が形式を認識しない場合は、形式の定義に基づいてストライドを計算する必要があります。 その場合、一般的なルールはありません。形式定義の詳細を知っている必要があります。

次のコードは、最も一般的なビデオ形式の既定のストライドを取得する方法を示しています。

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

アプリケーションによっては、特定のメディア バッファーが IMF2DBufferサポートしているかどうか (たとえば、バッファーを作成した場合) が事前にわかっている可能性があります。 それ以外の場合は、2 つのバッファー インターフェイスのいずれかを使用するように準備する必要があります。

次の例は、これらの詳細の一部を非表示にするヘルパー クラスを示しています。 このクラスには、Lock2D または lockを呼び出し、最初の行のピクセルの先頭へのポインターを返す LockBuffer メソッドがあります。 (この動作は、Lock2D メソッドと一致します)。LockBuffer メソッドは、入力パラメーターとして既定のストライドを受け取り、実際のストライドを出力パラメーターとして返します。

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

イメージストライド

メディア バッファーの