Freigeben über


Synchronisieren von DVD-Befehlen

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde von MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation abgelöst. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code mediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet, wenn möglich. Microsoft schlägt vor, dass vorhandener Code, der die Legacy-APIs verwendet, so umgeschrieben wird, dass nach Möglichkeit die neuen APIs verwendet werden.]

DVD-Befehle werden nicht immer sofort abgeschlossen. Aus diesem Grund sind einige der Methoden in IDvdControl2 asynchron. Dazu gehören Wiedergabemethoden wie PlayTitle und Menünavigationsmethoden wie ShowMenu und ReturnFromSubmenu. Eine asynchrone Methode gibt sofort zurück, ohne auf den Abschluss des Befehls zu warten. Nachdem die Methode zurückgegeben wurde, können andere Ereignisse den Abschluss des Befehls verhindern, selbst wenn die Methode erfolgreich war. DirectShow bietet mehrere Optionen für die Synchronisierung von Befehlen, die von keiner Synchronisierung bis hin zur vollständigen Synchronisierung mithilfe von Filterdiagrammereignissen reichen.

Alle asynchronen Methoden verfügen über einen dwFlags-Parameter und einen ppCmd-Parameter . Der dwFlags-Parameter gibt das Synchronisierungsverhalten an, und der ppCmd-Parameter gibt einen Zeiger auf ein optionales Synchronisierungsobjekt zurück. Je nachdem, welche Werte Sie für diese Parameter angeben, ergeben sich unterschiedliche Verhaltensweisen.

Keine Synchronisierung

Für eine einfache DVD-Wiedergabeanwendung kann die beste Option sein, Synchronisierungsprobleme einfach zu ignorieren. Gelegentlich schlägt ein Befehl fehl, oder die Benutzeroberfläche kann bei der Aktualisierung etwas verzögert werden, aber diese Fehler liegen in der Reihenfolge von Sekundenbruchteilen.

Wenn Sie einen Befehl ohne Synchronisierung ausgeben möchten, legen Sie das flag DVD_CMD_FLAG_None im dwFlags-Parameter fest, und legen Sie den ppCmd-Parameter auf NULL fest:

hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, NULL);

Blockierung

Wenn Sie das EC_DVD_CMD_FLAG_Block-Flag im dwFlags-Parameter festlegen, blockiert die Methode, bis der Befehl abgeschlossen ist:

hr = pDVDControl2->PlayTitle(uTitle, EC_DVD_CMD_FLAG_Block, NULL);

Tatsächlich wandelt dieses Flag eine asynchrone Methode in eine synchrone Methode um. Der Nachteil ist, dass Ihre Benutzeroberfläche blockiert, wenn Sie die Methode aus dem Anwendungsthread aufrufen.

Synchronization-Objekt

Alle asynchronen Methoden können ein Synchronisierungsobjekt zurückgeben, das Sie verwenden können, um zu warten, bis der Befehl gestartet oder beendet wird. Um dieses Objekt abzurufen, übergeben Sie die Adresse eines IDvdCmd-Zeigers im ppCmd-Parameter :

IDvdCmd *pCmdObj = NULL;
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, &pCmdObj);

Wenn die Methode erfolgreich ist, wird ein neues IDvdCmd-Objekt zurückgegeben. Die IDvdCmd::WaitForStart-Methode blockiert, bis der Befehl beginnt, und die IDvdCmd::WaitForEnd-Methode blockiert, bis der Befehl endet. Der Rückgabewert gibt die status des Befehls an.

Der folgende Code entspricht funktional dem Festlegen des zuvor gezeigten flags 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();
}

In diesem Fall blockiert die PlayTitle-Methode nicht, aber die Anwendung blockiert, indem WaitForEnd aufgerufen wird.

Befehlsstatusereignisse

Wenn Sie das DVD_CMD_FLAG_SendEvents-Flag im dwFlags-Parameter festlegen, sendet der DVD-Navigator ein EC_DVD_CMD_START-Ereignis , wenn der Befehl beginnt, und ein EC_DVD_CMD_END-Ereignis , wenn der Befehl beendet wird.

Der lParam2-Parameter des Ereignisses ist der HRESULT-Rückgabewert für den Befehl. Der lParam1-Parameter des Ereignisses bietet eine Möglichkeit, das Synchronisierungsobjekt für den Befehl abzurufen. Wenn Sie lParam1 an die IDvdInfo2::GetCmdFromEvent-Methode übergeben, gibt die Methode einen Zeiger auf die IDvdCmd-Schnittstelle des Synchronisierungsobjekts zurück. Sie können diese Schnittstelle verwenden, um auf den Abschluss des Befehls zu warten, wie zuvor beschrieben. Wenn Sie jedoch NULL für den ppCmd-Parameter in der ursprünglichen IDvdControl2-Methode übergeben haben, erstellt der DVD-Navigator kein Synchronisierungsobjekt, und GetCmdFromEvent gibt E_FAIL zurück.

Der folgende Code zeigt, wie Sie Befehle status Ereignisse ohne Synchronisierungsobjekt verwenden.

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;
}

Beachten Sie, dass Sie ohne ein Synchronisierungsobjekt nicht erkennen können, welcher Befehl dem Ereignis zugeordnet ist. Der folgende Code zeigt, wie Ereignisse mit dem Synchronisierungsobjekt verwendet werden. Die Idee besteht darin, die Synchronisierungsobjekte in einer Liste zu speichern und dann Objektzeiger zu vergleichen, wenn Sie das EC_DVD_CMD_START- oder EC_DVD_CMD_END-Ereignis erhalten.

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;
} 

Leeren der Puffer des DVD-Navigators

Während der Wiedergabe puffert der DVD-Navigator Videodaten. Die Menge der gepufferten Daten variiert. Wenn der DVD-Navigator zu einem neuen Videoteil wechselt, gehen die bereits in der Pipeline vorhandenen Daten nicht verloren, sodass der Übergang nahtlos erfolgt. Wenn der DVD-Navigator einen Befehl ausgibt, werden keine Daten geleert, die sich bereits in der Pipeline befinden. Daher kann es eine gewisse Latenz geben, bevor Sie die Auswirkungen des Befehls sehen können, je nachdem, wie viele Daten gepuffert werden. Um die Reaktionsfähigkeit zu erhöhen, können Sie das Leeren des DVD-Navigators erzwingen, indem Sie das Flag DVD_CMD_FLAG_Flush festlegen.

hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_Flush, NULL);

Dieses Flag kann mit jedem der zuvor beschriebenen Flags kombiniert werden, wobei ein bitweises OR verwendet wird. Ein Nebeneffekt des Leerens ist, dass einige Videos möglicherweise verloren gehen. Verwenden Sie daher dieses Flag nicht, wenn Sie sicherstellen müssen, dass es keine Lücken im Video gibt.

DVD-Anwendungen