Синхронизация команд DVD

Команды DVD не всегда выполняются мгновенно. По этой причине некоторые методы в IDvdControl2 являются асинхронными. К ним относятся методы воспроизведения, такие как плайтитле, и методы навигации по меню, такие как шовмену и ретурнфромсубмену. Асинхронный метод возвращает значение немедленно, не дожидаясь завершения команды. После возврата метода другие события могут препятствовать завершению выполнения команды, даже если метод выполнен успешно. DirectShow предоставляет несколько вариантов синхронизации команд, от отсутствия синхронизации до полной синхронизации с помощью событий фильтра.

Все асинхронные методы имеют параметр dwFlags и параметр ппкмд . Параметр dwFlags задает поведение синхронизации, а параметр ппкмд возвращает указатель на необязательный объект синхронизации. Различные варианты поведения в зависимости от значений, которые вы предоставляете для этих параметров.

Без синхронизации

Для простого приложения для воспроизведения DVD лучшим вариантом может быть просто пропустить проблемы синхронизации. Иногда команда может завершиться ошибкой или при обновлении пользовательский интерфейс может немного отставать, но эти ошибки будут находиться в порядке долей секунд.

Чтобы выдать команду без синхронизации, установите _ _ флаг флага DVD-метки " _ нет" в параметре dwFlags и присвойте параметру ппкмд значение NULL:

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

Блокировка

Если установить _ _ _ флаг блокировки флага блока DVD-диска EC _ в параметре dwFlags , метод блокируется до завершения команды:

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

Фактически этот флаг превращает асинхронный метод в синхронный метод. Недостаток заключается в том, что пользовательский интерфейс блокируется при вызове метода из потока приложения.

Объект синхронизации

Все асинхронные методы могут возвращать объект синхронизации, который можно использовать для ожидания запуска или завершения команды. Чтобы получить этот объект, передайте адрес указателя идвдкмд в параметре ппкмд :

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

Если метод завершается с ошибкой, возвращается новый объект идвдкмд . Метод идвдкмд:: ваитфорстарт блокируется до начала команды, а метод Идвдкмд:: ваитфоренд блокируется до завершения команды. Возвращаемое значение указывает состояние команды.

Следующий код функционально эквивалентен установке _ _ _ флага блока флага DVD-диска EC _ , показанного ранее.

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

В этом случае метод плайтитле не блокируется, но приложение блокируется путем вызова ваитфоренд.

События состояния команды

Если установить флаг _ _ _ SendEvents в параметре DWFLAGS , то Навигатор DVD отправляет событие _ _ _ запуска CMD DVD , когда команда начинается, а в случае завершения команды — _ DVD-диску _ _ EC .

Параметр lParam2 события возвращает возвращаемое значение HRESULT для команды. Параметр lParam1 события обеспечивает способ получения объекта синхронизации для команды. При передаче lParam1 в метод IDvdInfo2:: жеткмдфромевент метод возвращает указатель на интерфейс идвдкмд объекта синхронизации. Этот интерфейс можно использовать для ожидания завершения команды, как описано выше. Однако если в исходном методе IDvdControl2 передано значение NULL для параметра ппкмд , то Навигатор DVD не создает объект синхронизации, а жеткмдфромевент возвращает _ ошибку E.

В следующем коде показано, как использовать события состояния команды без объекта синхронизации.

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

Обратите внимание, что без объекта синхронизации невозможно определить, какая команда связана с этим событием. В следующем коде показано, как использовать события с объектом синхронизации. Идея состоит в том, чтобы сохранить объекты синхронизации в списке, а затем сравнить указатели объектов при получении события « _ _ _ Запуск DVD cmd » или « 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-навигатор, установив _ _ флаг сброса флага DVD-диска _ .

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

Этот флаг можно сочетать с любыми указанными выше флагами с помощью побитового или. Побочным результатом очистки является то, что некоторое видео может быть потеряно, поэтому не используйте этот флаг, если необходимо гарантировать, что в видео нет пробелов.

DVD-приложения