Udostępnij przez


Synchronizowanie poleceń DVD

[Funkcja skojarzona z tą stroną, DirectShow, jest starszą funkcją. Został zastąpiony przez MediaPlayer, IMFMediaEngineoraz Audio/Video Capture w Media Foundation. Te funkcje zostały zoptymalizowane pod kątem systemów Windows 10 i Windows 11. Firma Microsoft zdecydowanie zaleca, aby nowy kod używał MediaPlayer, IMFMediaEngine i Audio/Video Capture w programie Media Foundation zamiast DirectShow, jeśli to możliwe. Firma Microsoft sugeruje, że istniejący kod, który używa starszych interfejsów API, należy przepisać go do korzystania z nowych interfejsów API, jeśli to możliwe.]

Polecenia DVD nie zawsze są wykonywane natychmiast. Z tego powodu niektóre metody w IDvdControl2 są asynchroniczne. Obejmują one metody odtwarzania, takie jak PlayTitlei metody nawigacji menu, takie jak ShowMenu i ReturnFromSubmenu. Metoda asynchroniczna zwraca natychmiast, nie czekając na ukończenie polecenia. Po powrocie metody inne zdarzenia mogą uniemożliwić ukończenie polecenia, nawet jeśli metoda zakończyła się pomyślnie. DirectShow udostępnia kilka opcji synchronizowania poleceń, począwszy od braku synchronizacji do pełnej synchronizacji przy użyciu zdarzeń wykresu filtru.

Wszystkie metody asynchroniczne mają parametr dwFlags i parametr ppCmd. Parametr dwFlags określa zachowanie synchronizacji, a parametr ppCmd zwraca wskaźnik do opcjonalnego obiektu synchronizacji. Różne zachowania są wynikiem w zależności od wartości podanych dla tych parametrów.

brak synchronizacji

W przypadku podstawowej aplikacji odtwarzania DVD najlepszą opcją może być po prostu ignorowanie problemów z synchronizacją. Czasami polecenie może zakończyć się niepowodzeniem lub interfejs użytkownika może nieco opóźniać się podczas aktualizacji, ale te błędy będą trwały ułamki sekund.

Aby wydać polecenie bez synchronizacji, ustaw flagę DVD_CMD_FLAG_None w parametrze dwFlags i ustaw parametr ppCmd na null:

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

blokowanie

Jeśli ustawisz flagę EC_DVD_CMD_FLAG_Block w parametrze dwFlags, metoda zostanie zablokowana do momentu zakończenia polecenia:

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

W efekcie ta flaga zamienia metodę asynchroniczną w metodę synchroniczną. Wadą jest to, że interfejs użytkownika blokuje wywołanie metody z wątku aplikacji.

obiektu synchronizacji

Wszystkie metody asynchroniczne mogą zwracać obiekt synchronizacji, którego można użyć do oczekiwania na uruchomienie lub zakończenie polecenia. Aby uzyskać ten obiekt, przekaż adres wskaźnika IDvdCmd w parametrze ppCmd:

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

Jeśli metoda powiedzie się, zwraca nowy obiekt IDvdCmd. Metoda IDvdCmd::WaitForStart blokuje metodę do momentu rozpoczęcia polecenia, a IDvdCmd::WaitForEnd metoda zostanie zablokowana do momentu zakończenia polecenia. Wartość zwracana wskazuje stan polecenia.

Poniższy kod jest funkcjonalnie równoważny z ustawieniem flagi EC_DVD_CMD_FLAG_Block pokazanej wcześniej.

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

W tym przypadku metoda PlayTitle nie blokuje, ale aplikacja blokuje się w wyniku wywołania WaitForEnd.

zdarzenia stanu polecenia

Jeśli ustawisz flagę DVD_CMD_FLAG_SendEvents w parametrze dwFlags, nawigator DVD wysyła zdarzenie EC_DVD_CMD_START po rozpoczęciu polecenia i EC_DVD_CMD_END zdarzenie po zakończeniu polecenia.

Parametr lParam2 zdarzenia jest wartością zwracaną HRESULT dla polecenia . Parametr lParam1 zdarzenia umożliwia pobranie obiektu synchronizacji dla polecenia. Jeśli przekażesz lParam1 do IDvdInfo2::GetCmdFromEvent, metoda zwraca wskaźnik do interfejsu IDvdCmd obiektu synchronizacji. Za pomocą tego interfejsu można czekać na ukończenie polecenia, zgodnie z wcześniejszym opisem. Jeśli jednak przekazano null dla parametru ppCmd w oryginalnej metodzie IDvdControl2, nawigator DVD nie tworzy obiektu synchronizacji, a GetCmdFromEvent zwraca E_FAIL.

Poniższy kod pokazuje, jak używać zdarzeń stanu polecenia bez obiektu synchronizacji.

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

Należy pamiętać, że bez obiektu synchronizacji nie można stwierdzić, które polecenie jest skojarzone ze zdarzeniem. Poniższy kod pokazuje, jak używać zdarzeń z obiektem synchronizacji. Chodzi o przechowywanie obiektów synchronizacji na liście, a następnie porównywanie wskaźników obiektów po otrzymaniu zdarzenia EC_DVD_CMD_START lub 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;
} 

Opróżnianie buforów nawigatora DVD

Podczas odtwarzania nawigator DVD buforuje dane wideo. Ilość buforowanych danych różni się. Gdy nawigator DVD przełączy się na nowy fragment wideo, dane już znajdujące się w potoku nie zostaną utracone, więc przejście jest bezproblemowe. Domyślnie, gdy Nawigator DVD wydaje polecenie, nie opróżnia danych już w przepływie danych. W związku z tym może wystąpić pewne opóźnienie, zanim zobaczysz efekt polecenia, w zależności od ilości buforowanych danych. Aby zwiększyć responsywność, możesz wymusić opróżnienie nawigatora DVD, ustawiając flagę DVD_CMD_FLAG_Flush.

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

Tę flagę można połączyć z dowolną z wcześniej opisanych flag, używając operatora bitowego OR. Efekt uboczny czyszczenia bufora polega na tym, że niektóre fragmenty wideo mogą zostać utracone, więc nie używaj tej flagi, jeśli musisz zagwarantować ciągłość nagrania.

aplikacje DVD