步驟 3:實作 Frame-Grabbing 函式
[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayer、IMFMediaEngine、以及媒體基礎 的音訊/視訊擷取所取代。 這些功能已針對 Windows 10 和 Windows 11 進行優化。 Microsoft強烈建議新程式代碼盡可能在媒體 基礎中使用 MediaPlayer、IMFMediaEngine 和 音訊/視訊擷取,而不是 DirectShow。 Microsoft建議使用舊版 API 的現有程式代碼,盡可能改寫成使用新的 API。]
[此 API 不受支持,未來可能會改變或無法使用。]
本主題是 擷取海報框架的步驟 3。
下一個步驟是實作 GetBitmap 函式,該函式會使用媒體偵測器來擷取海報框架。 在此函式內,執行下列步驟:
- 建立媒體偵測器。
- 指定媒體檔案。
- 檢查檔案中的每個數據流。 如果是視訊串流,請取得影片的原生維度。
- 取得海報圖文框,指定搜尋時間和目標維度。
呼叫 CoCreateInstance來建立媒體偵測器物件:
CComPtr<IMediaDet> pDet;
hr = pDet.CoCreateInstance(__uuidof(MediaDet));
使用 IMediaDet::put_Filename 方法來指定檔名。 此方法會採用 BSTR 參數。
hr = pDet->put_Filename(bstrFilename);
取得串流的數量,並遍歷每個串流以檢查其媒體類型。 IMediaDet::get_OutputStreams 方法會擷取串流數目,而 IMediaDet::put_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 結構。 媒體偵測器會將所有視訊串流轉換成未壓縮的格式,並具有 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 函式。
現在您已準備好取得海報框。 首先,呼叫 IMediaDet::GetBitmapBits 方法,並以緩衝區的 NULL 指標作為參數:
long lSize;
hr = pDet->GetBitmapBits(0, &lSize, NULL, width, height);
此呼叫會傳回 lSize 參數中所需的緩衝區大小。 第一個參數會指定要搜尋的數據流時間;此範例使用時間零。 針對寬度和高度,此範例會使用稍早取得的原生視訊尺寸。 如果您指定其他值,媒體偵測器會延展位圖以符合。
如果方法成功,請配置緩衝區並再次呼叫 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 步:在客戶區域上繪製位圖
相關主題