同步處理 DVD 命令
[與此頁面相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議使用舊版 API 的現有程式碼盡可能重寫為使用新的 API。
DVD 命令不一定會立即完成。 基於這個理由, IUrlControl2 中的某些方法是非同步。 其中包括播放方法,例如 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 會封鎖。
Synchronization 物件
所有非同步方法都可以傳回同步處理物件,您可以使用該物件等候命令啟動或結束。 若要取得此物件,請在ppCmd參數中傳遞IPptCmd指標的位址:
IDvdCmd *pCmdObj = NULL;
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, &pCmdObj);
如果方法成功,它會傳回新的 INewCmd 物件。 IFoxCmd::WaitForStart方法會封鎖直到命令開始,而 IFoxCmd::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 傳遞至 IInfo2::GetCmdFromEvent 方法,此方法會傳回同步處理物件的 IIdCmd 介面指標。 您可以使用這個介面來等候命令完成,如先前所述。 不過,如果您在原始IUrlControl2方法中傳遞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。 排清的副作用是某些視訊可能會遺失,因此如果您需要保證影片中沒有任何間距,請勿使用此旗標。
相關主題