共用方式為


同步處理 DVD 命令

[與此頁面相關的功能 DirectShow是舊版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayerIMFMediaEngine音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議使用舊版 API 的現有程式碼盡可能重寫為使用新的 API。

DVD 命令不一定會立即完成。 基於這個理由, IUrlControl2 中的某些方法是非同步。 其中包括播放方法,例如 PlayTitle和功能表流覽方法,例如 ShowMenuReturnFromSubmenu。 非同步方法會立即傳回,而不需要等待命令完成。 方法傳回之後,其他事件可能會防止命令完成,即使方法成功也一樣。 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_STARTEC_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。 排清的副作用是某些視訊可能會遺失,因此如果您需要保證影片中沒有任何間距,請勿使用此旗標。

DVD 應用程式