同步DVD命令
[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayer、IMFMediaEngine以及媒體基金會中的音訊/視訊擷取 取代。 這些功能已針對 Windows 10 和 Windows 11 進行優化。 Microsoft強烈建議新程式代碼盡可能在媒體 基礎中使用 MediaPlayer、IMFMediaEngine 和 音訊/視訊擷取,而不是 DirectShow。 Microsoft建議使用舊版 API 的現有程式代碼,盡可能改寫成使用新的 API。]
DVD 命令不一定會立即完成。 因此,IDvdControl2 中的一些方法都是異步的。 其中包括播放方法,諸如 PlayTitle,以及功能表導覽方法,例如 ShowMenu 和 ReturnFromSubmenu。 異步方法會立即傳回,而不需要等待命令完成。 方法傳回之後,即使方法成功,其他事件仍可能會防止命令完成。 DirectShow 提供數個選項來同步處理命令,範圍從沒有同步處理到使用篩選圖表事件的完整同步處理。
所有異步方法都有 dwFlags 參數和 ppCmd 參數。 dwFlags 參數會指定同步處理行為,而 ppCmd 參數會傳回選擇性同步處理物件的指標。 不同的行為會根據您為這些參數提供的值而產生。
無同步處理
對於基本的 DVD 播放應用程式,最佳選項可能只是忽略同步處理問題。 有時候,命令可能會失敗,或者UI在更新時可能會稍有延遲,但這些錯誤會依秒數的順序排列。
若要發出沒有同步處理的命令,請在 dwFlags 參數中設定DVD_CMD_FLAG_None旗標,並將 ppCmd 參數設定為 NULL:
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, NULL);
封鎖
如果您在 dwFlags 參數中設定EC_DVD_CMD_FLAG_Block旗標,方法會封鎖,直到命令完成為止:
hr = pDVDControl2->PlayTitle(uTitle, EC_DVD_CMD_FLAG_Block, NULL);
實際上,此旗標會將異步方法轉換成同步方法。 缺點是,如果您從應用程式線程呼叫 方法,UI 會封鎖。
同步化物件
所有異步方法都可以傳回同步處理物件,您可以使用這個物件來等候命令啟動或結束。 若要取得此物件,請在 ppCmd 參數中傳遞 IDvdCmd 指標的位址:
IDvdCmd *pCmdObj = NULL;
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, &pCmdObj);
如果方法成功,它會傳回新的 IDvdCmd 物件。 IDvdCmd::WaitForStart 方法會封鎖,直到命令開始;IDvdCmd::WaitForEnd 方法會封鎖,直到命令結束。 傳回值表示命令的狀態。
下列程式代碼的功能相當於設定先前顯示的EC_DVD_CMD_FLAG_Block旗標。
IDvdCmd *pCmdObj = NULL;
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, &pCmdObj);
if (SUCCEEDED(hr))
{
// Use pCmdObj to wait for the command to complete.
hr = pCmdObj->WaitToEnd();
pCmdObj->Release();
}
在此情況下,PlayTitle 方法不會封鎖,但應用程式會藉由呼叫 WaitForEnd來封鎖。
命令狀態事件
如果您在 dwFlags 參數中設定DVD_CMD_FLAG_SendEvents旗標,DVD Navigator 會在命令開始時傳送 EC_DVD_CMD_START 事件,並在命令結束時傳送 EC_DVD_CMD_END 事件。
事件的 lParam2 參數是命令的 HRESULT 傳回值。 事件的 lParam1 參數提供取得命令同步處理物件的方式。 如果您將 lParam1 傳遞至 IDvdInfo2::GetCmdFromEvent 方法,此方法會傳回同步處理物件的 IDvdCmd 介面指標。 您可以使用這個介面來等候命令完成,如先前所述。 不過,如果您在原始 IDvdControl2 方法中傳遞 ppCmd 參數 NULL,DVD Navigator 不會建立同步處理物件,而且 GetCmdFromEvent 會傳回E_FAIL。
下列程式代碼示範如何使用不含同步處理物件的命令狀態事件。
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_SendEvents, NULL);
// In your event handling code:
switch (lEvent)
{
case EC_DVD_CMD_END:
HRESULT hr2 = (HRESULT)lParam2;
/* ... */
break;
}
請注意,如果沒有同步處理物件,您無法判斷哪個命令與事件相關聯。 下列程式代碼示範如何與同步物件一起使用事件。 其概念是將同步處理物件儲存在清單中,然後在取得 EC_DVD_CMD_START 或 EC_DVD_CMD_END 事件時比較物件指標。
IDvdCmd *pCmdObj = NULL;
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_SendEvents, &pCmdObj);
if (SUCCEEDED(hr))
{
// Store pCmdObj in a list of pending commands.
}
// In your event handling code:
switch (lEvent)
{
case EC_DVD_CMD_END:
{
IDvdCmd *pObj = NULL;
hr = pDvdInfo2->GetCmdFromEvent(lParam, &pObj);
if (SUCCEEDED(hr))
{
// Find this object in your list by comparing IUnknown
// pointers. Assume the following function is defined in
// your application:
IDvdCmd *pPendingObj = GetPendingCommandFromList(pObj);
if (pPendingObj)
{
// Update UI accordingly (not shown).
pPendingObj->Release();
}
pObj->Release();
}
}
break;
}
排清 DVD 導覽器的緩衝區
播放期間,DVD 播放器會緩衝處理視頻數據。 緩衝的數據量會有所不同。 當 DVD 導覽器切換至新的視訊片段時,管線中已經有的數據不會遺失,因此轉換是順暢的。 根據預設,當 DVD 導覽器發出命令時,它不會排清管線中已經有的數據。 因此,視緩衝處理的數據量而定,您可能會有一些延遲,才能看到命令的效果。 若要增加回應性,您可以藉由設定 DVD_CMD_FLAG_Flush 旗標,強制 DVD 導覽器排清。
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_Flush, NULL);
這個旗標可以與先前所述的任何旗標結合,使用位元 OR。 排清的副作用是某些視訊可能會遺失,因此如果您需要保證影片中沒有間距,請勿使用此旗標。
相關主題