Compartir a través de


Sincronizar comandos de DVD

[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

Los comandos de DVD no siempre se completan al instante. Por este motivo, algunos de los métodos de IDvdControl2 son asincrónicos. Estos incluyen métodos de reproducción, como PlayTitle y métodos de navegación de menús, como ShowMenu y ReturnFromSubmenu. Un método asincrónico devuelve inmediatamente, sin esperar a que se complete el comando. Una vez devuelto el método, otros eventos pueden impedir que el comando se complete, incluso si el método se realizó correctamente. DirectShow proporciona varias opciones para sincronizar comandos, que van desde ninguna sincronización hasta la sincronización completa mediante eventos de gráfico de filtro.

Todos los métodos asincrónicos tienen un parámetro dwFlags y un parámetro ppCmd . El parámetro dwFlags especifica el comportamiento de sincronización y el parámetro ppCmd devuelve un puntero a un objeto de sincronización opcional. Los distintos comportamientos resultan en función de los valores que proporcione para estos parámetros.

Sin sincronización

Para una aplicación básica de reproducción de DVD, la mejor opción puede ser simplemente omitir los problemas de sincronización. En ocasiones, un comando puede producir un error o la interfaz de usuario podría retardar ligeramente cuando se actualiza, pero estos errores estarán en el orden de las fracciones de segundos.

Para emitir un comando sin sincronización, establezca la marca DVD_CMD_FLAG_None en el parámetro dwFlags y establezca el parámetro ppCmd en NULL:

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

Bloqueos

Si establece la marca EC_DVD_CMD_FLAG_Block en el parámetro dwFlags , el método se bloquea hasta que se complete el comando:

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

En efecto, esta marca convierte un método asincrónico en un método sincrónico. El inconveniente es que la interfaz de usuario se bloquea si llama al método desde el subproceso de la aplicación.

Synchronization (objeto)

Todos los métodos asincrónicos pueden devolver un objeto de sincronización, que puede usar para esperar a que el comando se inicie o finalice. Para obtener este objeto, pase la dirección de un puntero IDvdCmd en el parámetro ppCmd :

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

Si el método se realiza correctamente, devuelve un nuevo objeto IDvdCmd . El método IDvdCmd::WaitForStart se bloquea hasta que comienza el comando y el método IDvdCmd::WaitForEnd se bloquea hasta que finaliza el comando. El valor devuelto indica el estado del comando.

El código siguiente es funcionalmente equivalente a establecer la marca EC_DVD_CMD_FLAG_Block, mostrada 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();
}

En este caso, el método PlayTitle no se bloquea, pero la aplicación se bloquea llamando a WaitForEnd.

Eventos de estado del comando

Si establece la marca DVD_CMD_FLAG_SendEvents en el parámetro dwFlags , el navegador de DVD envía un evento EC_DVD_CMD_START cuando el comando comienza y un evento de EC_DVD_CMD_END cuando finaliza el comando.

El parámetro lParam2 del evento es el valor devuelto HRESULT para el comando. El parámetro lParam1 del evento proporciona una manera de obtener el objeto de sincronización del comando. Si pasa lParam1 al método IDvdInfo2::GetCmdFromEvent , el método devuelve un puntero a la interfaz IDvdCmd del objeto de sincronización. Puede usar esta interfaz para esperar a que finalice el comando, como se ha descrito anteriormente. Sin embargo, si pasó NULL para el parámetro ppCmd en el método IDvdControl2 original, el navegador de DVD no crea un objeto de sincronización y GetCmdFromEvent devuelve E_FAIL.

En el código siguiente se muestra cómo usar eventos de estado de comandos sin ningún objeto de sincronización.

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

Tenga en cuenta que sin un objeto de sincronización, no puede saber qué comando está asociado al evento. En el código siguiente se muestra cómo usar eventos con el objeto de sincronización. La idea es almacenar los objetos de sincronización en una lista y, a continuación, comparar punteros de objeto al obtener el evento EC_DVD_CMD_START o 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;
} 

Vaciado de los búferes del navegador de DVD

Durante la reproducción, el navegador de DVD almacena en búfer los datos de vídeo. La cantidad de datos almacenados en búfer varía. Cuando el navegador de DVD cambia a un nuevo fragmento de vídeo, los datos que ya están en la canalización no se pierden, por lo que la transición es perfecta. De forma predeterminada, cuando el navegador de DVD emite un comando, no vacía los datos ya en la canalización. Como resultado, puede haber cierta latencia antes de que pueda ver el efecto del comando, en función de la cantidad de datos almacenados en búfer. Para aumentar la capacidad de respuesta, puede forzar que el navegador de DVD se vacíe estableciendo la marca DVD_CMD_FLAG_Flush.

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

Esta marca se puede combinar con cualquiera de las marcas descritas anteriormente, mediante un OR bit a bit. Un efecto secundario del vaciado es que se puede perder algún vídeo, por lo que no use esta marca si necesita garantizar que no haya espacios en el vídeo.

Aplicaciones de DVD