DVD コマンドの同期

[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayerIMFMediaEngineAudio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]

DVD コマンドがすぐに完了するとは限りません。 このため、 IDvdControl2 のメソッドの一部は非同期です。 これには、 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 パラメーターに 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 ナビゲーターはコマンドの開始時に EC_DVD_CMD_START イベントを送信し、コマンドの終了時に EC_DVD_CMD_END イベントを送信します。

イベントの lParam2 パラメーターは、コマンドの HRESULT 戻り値です。 イベントの lParam1 パラメーターは、コマンドの同期オブジェクトを取得する方法を提供します。 iDvdInfo2::GetCmdFromEvent メソッドに lParam1 を渡すと、同期オブジェクトの IDvdCmd インターフェイスへのポインターが返されます。 前に説明したように、このインターフェイスを使用してコマンドの完了を待機できます。 ただし、元の IDvdControl2 メソッドで ppCmd パラメーターに NULL を渡した場合、DVD ナビゲーターは同期オブジェクトを作成せず、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 を使用して、前に説明した任意のフラグと組み合わせることができます。 フラッシュの副作用は、一部のビデオが失われる可能性があるため、ビデオにギャップがないことを保証する必要がある場合は、このフラグを使用しないでください。

DVD アプリケーション