DVD 명령 동기화
[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드가 DirectShow 대신 Media Foundation에서 MediaPlayer, IMFMediaEngine 및 오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]
DVD 명령이 항상 즉시 완료되는 것은 아닙니다. 이러한 이유로 IDvdControl2 의 일부 메서드는 비동기적입니다. 여기에는 PlayTitle과 같은 재생 메서드와 ShowMenu 및 ReturnFromSubmenu와 같은 메뉴 탐색 메서드가 포함됩니다. 비동기 메서드는 명령이 완료 될 때까지 기다리지 않고 즉시 반환됩니다. 메서드가 반환되면 메서드가 성공하더라도 다른 이벤트가 명령이 완료되지 않을 수 있습니다. DirectShow는 필터 그래프 이벤트를 사용하여 동기화 없음에서 전체 동기화에 이르기까지 명령을 동기화하기 위한 몇 가지 옵션을 제공합니다.
모든 비동기 메서드에는 dwFlags 매개 변수와 ppCmd 매개 변수가 있습니다. dwFlags 매개 변수는 동기화 동작을 지정하고 ppCmd 매개 변수는 선택적 동기화 개체에 대한 포인터를 반환합니다. 이러한 매개 변수에 대해 제공하는 값에 따라 동작이 달라집니다.
동기화 없음
기본 DVD 재생 애플리케이션의 경우 동기화 문제를 무시하는 것이 가장 좋은 옵션일 수 있습니다. 경우에 따라 명령이 실패하거나 UI가 업데이트될 때 약간 지연될 수 있지만 이러한 오류는 초 단위로 표시됩니다.
동기화 없이 명령을 실행하려면 dwFlags 매개 변수에서 DVD_CMD_FLAG_None 플래그를 설정하고 ppCmd 매개 변수를 NULL로 설정합니다.
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, NULL);
차단
dwFlags 매개 변수에서 EC_DVD_CMD_FLAG_Block 플래그를 설정하면 명령이 완료될 때까지 메서드가 차단됩니다.
hr = pDVDControl2->PlayTitle(uTitle, EC_DVD_CMD_FLAG_Block, NULL);
실제로 이 플래그는 비동기 메서드를 동기 메서드로 바꿉니다. 단점은 애플리케이션 스레드에서 메서드를 호출하는 경우 UI가 차단된다는 것입니다.
동기화 개체
모든 비동기 메서드는 명령이 시작되거나 끝날 때까지 기다리는 데 사용할 수 있는 동기화 개체를 반환할 수 있습니다. 이 개체를 얻으려면 ppCmd 매개 변수에서 IDvdCmd 포인터의 주소를 전달합니다.
IDvdCmd *pCmdObj = NULL;
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_None, &pCmdObj);
메서드가 성공하면 새 IDvdCmd 개체를 반환합니다. IDvdCmd::WaitForStart 메서드는 명령이 시작될 때까지 차단되고, IDvdCmd::WaitForEnd 메서드는 명령이 끝날 때까지 차단됩니다. 반환 값은 명령의 상태 나타냅니다.
다음 코드는 이전에 표시된 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();
}
이 경우 PlayTitle 메서드는 차단되지 않지만 WaitForEnd를 호출하여 애플리케이션이 차단됩니다.
명령 상태 이벤트
dwFlags 매개 변수에서 DVD_CMD_FLAG_SendEvents 플래그를 설정하면 명령이 시작될 때 DVD 탐색기가 EC_DVD_CMD_START 이벤트를 보내고 명령이 종료되면 EC_DVD_CMD_END 이벤트를 보냅니다.
이벤트의 lParam2 매개 변수는 명령에 대한 HRESULT 반환 값입니다. 이벤트의 lParam1 매개 변수는 명령에 대한 동기화 개체를 가져오는 방법을 제공합니다. iDvdInfo2::GetCmdFromEvent 메서드에 lParam1을 전달하면 메서드는 동기화 개체의 IDvdCmd 인터페이스에 대한 포인터를 반환합니다. 앞에서 설명한 대로 이 인터페이스를 사용하여 명령이 완료될 때까지 기다릴 수 있습니다. 그러나 원래 IDvdControl2 메서드에서 ppCmd 매개 변수에 대해 NULL을 전달한 경우 DVD 탐색기는 동기화 개체를 만들지 않으며 GetCmdFromEvent는 E_FAIL 반환합니다.
다음 코드에서는 동기화 개체 없이 명령 상태 이벤트를 사용하는 방법을 보여 줍니다.
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;
}
동기화 개체가 없으면 이벤트와 연결된 명령을 알 수 없습니다. 다음 코드에서는 동기화 개체와 함께 이벤트를 사용하는 방법을 보여 줍니다. 동기화 개체를 목록에 저장한 다음 , EC_DVD_CMD_START또는 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_CMD_FLAG_Flush 플래그를 설정하여 DVD 탐색기를 강제로 플러시할 수 있습니다.
hr = pDVDControl2->PlayTitle(uTitle, DVD_CMD_FLAG_Flush, NULL);
이 플래그는 비트 OR을 사용하여 이전에 설명한 플래그와 결합할 수 있습니다. 플러시의 부작용은 일부 비디오가 손실될 수 있으므로 비디오에 간격이 없도록 보장해야 하는 경우 이 플래그를 사용하지 마세요.
관련 항목