次の方法で共有


手順 3: Frame-Grabbing関数を実装する

[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayerIMFMediaEngineAudio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]

[この API はサポートされていないため、今後変更または使用できない可能性があります。]

このトピックは、「 ポスター フレームをつかむ」の手順 3 です。

次の手順では、Media Detector を使用してポスター フレームを取得する GetBitmap 関数を実装します。 この関数内で、次の手順を実行します。

  1. Media Detector を作成します。
  2. メディア ファイルを指定します。
  3. ファイル内の各ストリームを調べます。 ビデオ ストリームの場合は、ビデオのネイティブ ディメンションを取得します。
  4. シーク時間とターゲット ディメンションを指定して、ポスター フレームを取得します。

CoCreateInstance を呼び出して Media Detector オブジェクトを作成します。

CComPtr<IMediaDet> pDet;
hr = pDet.CoCreateInstance(__uuidof(MediaDet));

IMediaDet::p ut_Filename メソッドを使用して、ファイル名を指定します。 このメソッドは 、BSTR パラメーターを受け取ります。

hr = pDet->put_Filename(bstrFilename);

ストリームの数を取得し、メディアの種類をチェックする各ストリームをループします。 IMediaDet::get_OutputStreams メソッドはストリームの数を取得し、IMediaDet::p ut_CurrentStream メソッドは調べるストリームを指定します。 最初のビデオ ストリームでループを終了します。

long lStreams;
bool bFound = false;
hr = pDet->get_OutputStreams(&lStreams);
for (long i = 0; i < lStreams; i++)
{
    GUID major_type;
    hr = pDet->put_CurrentStream(i);
    hr = pDet->get_StreamType(&major_type);
    if (major_type == MEDIATYPE_Video)  // Found a video stream.
    {
        bFound = true;
        break;
    }
}
if (!bFound) return VFW_E_INVALIDMEDIATYPE;

ビデオ ストリームが見つからなかった場合、関数は終了します。

前のコードでは、 IMediaDet::get_StreamType メソッドはメジャー型 GUID のみを返します。 これは、メディアの種類全体を調べる必要がない場合に便利です。 ただし、ビデオのサイズを取得するには、フォーマット ブロックを調べる必要があるため、完全なメディアの種類が必要です。 これを取得するには、 IMediaDet::get_StreamMediaType メソッドを呼び出して、 AM_MEDIA_TYPE 構造体を埋めます。 Media Detector は、 VIDEOINFOHEADER 形式ブロックを使用して、すべてのビデオ ストリームを非圧縮形式に変換します。

long width = 0, height = 0; 
AM_MEDIA_TYPE mt;
hr = pDet->get_StreamMediaType(&mt);
if (mt.formattype == FORMAT_VideoInfo) 
{
    VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat);
    width = pVih->bmiHeader.biWidth;
    height = pVih->bmiHeader.biHeight;
    
    // We want the absolute height, and don't care about up-down orientation.
    if (height < 0) height *= -1;
}
else {
    return VFW_E_INVALIDMEDIATYPE; // This should not happen, in theory.
}
FreeMediaType(mt);

get_StreamMediaType メソッドは、呼び出し元が解放する必要がある形式ブロックを割り当てます。 この例では、基本クラス ライブラリの FreeMediaType 関数を使用します。

これで、ポスター フレームを取得する準備ができました。 最初に、バッファーの NULL ポインターを使用して IMediaDet::GetBitmapBits メソッドを呼び出します。

long lSize;
hr = pDet->GetBitmapBits(0, &lSize, NULL, width, height);

この呼び出しは、 lSize パラメーターに必要なバッファー サイズを返します。 最初のパラメーターは、シークするストリーム時間を指定します。この例では、時間 0 を使用します。 幅と高さに対して、この例では、前に取得したネイティブ ビデオ ディメンションを使用します。 他の値を指定した場合、Media Detector は一致するようにビットマップを拡大します。

メソッドが成功した場合は、バッファーを割り当てて 、GetBitmapBits をもう一度呼び出します。

if (SUCCEEDED(hr)) 
{
    char *pBuffer = new char[lSize];
    if (!pBuffer) return E_OUTOFMEMORY;
    hr = pDet->GetBitmapBits(0, NULL, pBuffer, width, height);
    if (FAILED(hr))
        delete [] pBuffer;
}

完全な関数を次に示します。エラー処理はやや優れています。

HRESULT GetBitmap(LPTSTR pszFileName, BITMAPINFOHEADER** ppbmih)
{
    HRESULT hr;
    CComPtr<IMediaDet> pDet;
    hr = pDet.CoCreateInstance(__uuidof(MediaDet));
    if (FAILED(hr)) return hr;

    // Convert the file name to a BSTR.
    CComBSTR bstrFilename(pszFileName);
    hr = pDet->put_Filename(bstrFilename);
    if (FAILED(hr)) return hr;

    long lStreams;
    bool bFound = false;
    hr = pDet->get_OutputStreams(&lStreams);
    if (FAILED(hr)) return hr;

    for (long i = 0; i < lStreams; i++)
    {
        GUID major_type;
        hr = pDet->put_CurrentStream(i);
        if (SUCCEEDED(hr))
        {
            hr = pDet->get_StreamType(&major_type);
        }
        if (FAILED(hr)) break;

        if (major_type == MEDIATYPE_Video)
        {
            bFound = true;
            break;
        }
    }
    if (!bFound) return VFW_E_INVALIDMEDIATYPE;

    long width = 0, height = 0; 
    AM_MEDIA_TYPE mt;
    hr = pDet->get_StreamMediaType(&mt);
    if (SUCCEEDED(hr)) 
    {
        if ((mt.formattype == FORMAT_VideoInfo) && 
            (mt.cbFormat >= sizeof(VIDEOINFOHEADER)))
        {
            VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat);
            width = pVih->bmiHeader.biWidth;
            height = pVih->bmiHeader.biHeight;
        
            // We want the absolute height, don't care about orientation.
            if (height < 0) height *= -1;
        }
        else
        {
            hr = VFW_E_INVALIDMEDIATYPE; // Should not happen, in theory.
        }
        FreeMediaType(mt);
    }
    if (FAILED(hr)) return hr;
    
    // Find the required buffer size.
    long size;
    hr = pDet->GetBitmapBits(0, &size, NULL, width, height);
    if (SUCCEEDED(hr)) 
    {
        char *pBuffer = new char[size];
        if (!pBuffer) return E_OUTOFMEMORY;
        try {
            hr = pDet->GetBitmapBits(0, NULL, pBuffer, width, height);
            if (SUCCEEDED(hr))
            {
                // Delete the old image, if any.
                if (*ppbmih) delete[] (*ppbmih);
                (*ppbmih) = (BITMAPINFOHEADER*)pBuffer;
            }
            else
            {
                delete [] pBuffer;
            }
        }
        catch (...) {
            delete [] pBuffer;
            return E_OUTOFMEMORY;
        }
    }
    return hr;
}

次へ: 手順 4: クライアント領域にビットマップを描画する

ポスターフレームをつかむ