Share via


Sincronizando comandos de DVD

[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

Os comandos de DVD nem sempre são concluídos instantaneamente. Por esse motivo, alguns dos métodos em IDvdControl2 são assíncronos. Isso inclui métodos de reprodução, como PlayTitle, e métodos de navegação de menu, como ShowMenu e ReturnFromSubmenu. Um método assíncrono retorna imediatamente, sem aguardar a conclusão do comando. Depois que o método retorna, outros eventos podem impedir que o comando seja concluído, mesmo que o método tenha sido bem-sucedido. O DirectShow fornece várias opções para sincronizar comandos, desde nenhuma sincronização até sincronização completa usando eventos de grafo de filtro.

Todos os métodos assíncronos têm um parâmetro dwFlags e um parâmetro ppCmd . O parâmetro dwFlags especifica o comportamento de sincronização e o parâmetro ppCmd retorna um ponteiro para um objeto de sincronização opcional. Comportamentos diferentes resultam dependendo de quais valores você dá para esses parâmetros.

Sem sincronização

Para um aplicativo básico de reprodução de DVD, a melhor opção pode ser simplesmente ignorar problemas de sincronização. Ocasionalmente, um comando pode falhar ou a interface do usuário pode ficar um pouco atrasada quando for atualizada, mas esses erros estarão na ordem de frações de segundos.

Para emitir um comando sem sincronização, defina o sinalizador DVD_CMD_FLAG_None no parâmetro dwFlags e defina o parâmetro ppCmd como NULL:

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

Bloqueio

Se você definir o sinalizador EC_DVD_CMD_FLAG_Block no parâmetro dwFlags , o método será bloqueado até que o comando seja concluído:

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

Na verdade, esse sinalizador transforma um método assíncrono em um método síncrono. A desvantagem é que sua interface do usuário será bloqueada se você chamar o método do thread do aplicativo.

Objeto synchronization

Todos os métodos assíncronos podem retornar um objeto de sincronização, que você pode usar para aguardar o início ou término do comando. Para obter esse objeto, passe o endereço de um ponteiro IDvdCmd no parâmetro ppCmd :

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

Se o método for bem-sucedido, ele retornará um novo objeto IDvdCmd . O método IDvdCmd::WaitForStart é bloqueado até que o comando comece e o método IDvdCmd::WaitForEnd é bloqueado até que o comando termine. O valor retornado indica o status do comando.

O código a seguir é funcionalmente equivalente a definir o sinalizador EC_DVD_CMD_FLAG_Block, mostrado anteriormente.

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

Nesse caso, o método PlayTitle não bloqueia, mas o aplicativo é bloqueado chamando WaitForEnd.

Eventos de status de comando

Se você definir o sinalizador DVD_CMD_FLAG_SendEvents no parâmetro dwFlags , o Navegador de DVD enviará um evento EC_DVD_CMD_START quando o comando começar e um evento EC_DVD_CMD_END quando o comando terminar.

O parâmetro lParam2 do evento é o valor retornado HRESULT para o comando . O parâmetro lParam1 do evento fornece uma maneira de obter o objeto de sincronização para o comando. Se você passar lParam1 para o método IDvdInfo2::GetCmdFromEvent , o método retornará um ponteiro para a interface IDvdCmd do objeto de sincronização. Você pode usar essa interface para aguardar a conclusão do comando, conforme descrito anteriormente. No entanto, se você passou NULL para o parâmetro ppCmd no método IDvdControl2 original, o Navegador de DVD não criará um objeto de sincronização e GetCmdFromEvent retornará E_FAIL.

O código a seguir mostra como usar o comando status eventos sem nenhum objeto de sincronização.

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

Observe que, sem um objeto de sincronização, você não pode informar qual comando está associado ao evento. O código a seguir mostra como usar eventos com o objeto de sincronização. A ideia é armazenar os objetos de sincronização em uma lista e, em seguida, comparar ponteiros de objeto quando você receber o evento EC_DVD_CMD_START ou 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;
} 

Liberando buffers do Navegador de DVD

Durante a reprodução, o Navegador de DVD armazena em buffer dados de vídeo. A quantidade de dados armazenados em buffer varia. Quando o Navegador de DVD alterna para uma nova parte do vídeo, os dados que já estão no pipeline não são perdidos, portanto, a transição é perfeita. Por padrão, quando o Navegador de DVD emite um comando, ele não libera dados já no pipeline. Como resultado, pode haver alguma latência antes que você possa ver o efeito do comando, dependendo de quantos dados são armazenados em buffer. Para aumentar a capacidade de resposta, você pode forçar o Navegador de DVD a liberar definindo o sinalizador DVD_CMD_FLAG_Flush.

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

Esse sinalizador pode ser combinado com qualquer um dos sinalizadores descritos anteriormente, usando um OR bit a bit. Um efeito colateral da liberação é que alguns vídeos podem ser perdidos, portanto, não use esse sinalizador se você precisar garantir que não há lacunas no vídeo.

Aplicativos de DVD