手順 3: Frame-Grabbing関数を実装する
[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayer、IMFMediaEngine、Audio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]
[この API はサポートされていないため、今後変更または使用できない可能性があります。]
このトピックは、「 ポスター フレームをつかむ」の手順 3 です。
次の手順では、Media Detector を使用してポスター フレームを取得する GetBitmap 関数を実装します。 この関数内で、次の手順を実行します。
- Media Detector を作成します。
- メディア ファイルを指定します。
- ファイル内の各ストリームを調べます。 ビデオ ストリームの場合は、ビデオのネイティブ ディメンションを取得します。
- シーク時間とターゲット ディメンションを指定して、ポスター フレームを取得します。
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: クライアント領域にビットマップを描画する
関連トピック