Steuern eines externen Geräts
[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde von MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation abgelöst. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code mediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet, wenn möglich. Microsoft schlägt vor, dass vorhandener Code, der die Legacy-APIs verwendet, so umgeschrieben wird, dass nach Möglichkeit die neuen APIs verwendet werden.]
Verwenden Sie zum Steuern eines VTR-Geräts (Video Tape Recorder) die IAMExtTransport::p ut_Mode-Methode . Geben Sie den neuen Zustand mithilfe einer der Konstanten an, die im Gerätetransportstatus aufgeführt sind. Verwenden Sie beispielsweise Folgendes, um das Gerät zu beenden:
pTransport->put_Mode(ED_MODE_STOP);
Da es sich bei der VTR um ein physisches Gerät handelt, besteht in der Regel eine Verzögerung zwischen der Ausführung des Befehls und dem Abschluss des Befehls. Ihre Anwendung sollte einen zweiten Workerthread erstellen, der auf den Abschluss des Befehls wartet. Wenn der Befehl abgeschlossen ist, kann der Thread die Benutzeroberfläche aktualisieren. Verwenden Sie einen kritischen Abschnitt, um die Zustandsänderung zu serialisieren.
Einige VTRs können die Anwendung benachrichtigen, wenn sich der Transportstatus des Geräts geändert hat. Wenn das Gerät dieses Feature unterstützt, kann der Workerthread auf die Benachrichtigung warten. Gemäß der "AV/C Tape Recorder/Player Subunit Specification" der 1394 Trade Association ist der Transportzustandsbenachrichtigungsbefehl jedoch optional, d. h. Geräte müssen ihn nicht unterstützen. Wenn ein Gerät keine Benachrichtigung unterstützt, sollten Sie das Gerät in regelmäßigen Abständen nach seinem aktuellen Zustand abfragen.
In diesem Abschnitt wird zunächst der Benachrichtigungsmechanismus und dann die Geräteabrufe beschrieben.
Verwenden der Transportstatusbenachrichtigung
Transportstatusbenachrichtigung funktioniert, indem der Treiber ein Ereignis signalisiert, wenn der Transport in einen neuen Zustand wechselt. Deklarieren Sie in Ihrer Anwendung einen kritischen Abschnitt, ein Ereignis und ein Threadhandle. Der kritische Abschnitt wird verwendet, um den Gerätestatus zu synchronisieren. Das -Ereignis wird verwendet, um den Workerthread anzuhalten, wenn die Anwendung beendet wird:
HANDLE hThread = 0;
HANDLE hThreadEnd = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hThreadEnd == NULL)
{
// Handle error.
}
CRITICAL_SECTION csIssueCmd;
InitializeCriticalSection(&cdIssueCmd);
Nachdem Sie eine instance des Erfassungsfilters erstellt haben, erstellen Sie den Workerthread:
DWORD ThreadId;
hThread = CreateThread(NULL, 0, ThreadProc, 0, 0, &ThreadId);
Rufen Sie im Workerthread zunächst die IAMExtTransport::GetStatus-Methode mit dem Wert ED_NOTIFY_HEVENT_GET auf. Dieser Aufruf gibt ein Handle an ein Ereignis zurück, das beim Abschluss eines Vorgangs signalisiert wird:
// Get the handle to the notification event.
HANDLE hEvent = NULL;
hr = pTransport->GetStatus(ED_NOTIFY_HEVENT_GET, (long*)&hNotify);
Rufen Sie als Nächstes erneut GetState auf, und übergeben Sie den Wert ED_MODE_CHANGE_NOTIFY:
LONG State;
hr = pTransport->GetStatus(ED_MODE_CHANGE_NOTIFY, &State);
Wenn das Gerät Benachrichtigungen unterstützt, gibt die Methode den Wert E_PENDING zurück. (Andernfalls müssen Sie das Gerät abfragen, wie im nächsten Abschnitt beschrieben.) Wenn das Gerät Benachrichtigungen unterstützt, wird das Ereignis immer dann signalisiert, wenn sich der Zustand des VTR-Transports ändert. An diesem Punkt können Sie die Benutzeroberfläche aktualisieren, um den neuen Zustand widerzuspiegeln. Um die nächste Benachrichtigung zu erhalten, setzen Sie das Ereignishandle zurück, und rufen Sie GetStatus mit ED_MODE_CHANGE_NOTIFY erneut auf.
Bevor der Workerthread beendet wird, lassen Sie das Ereignishandle los, indem Sie GetStatus mit dem Flag ED_NOTIFY_HEVENT_RELEASE und der Adresse des Handles aufrufen:
hr = pTransport->GetStatus(ED_NOTIFY_HEVENT_RELEASE, (long*)&hNotify)
Der folgende Code zeigt die vollständige Threadprozedur. Bei der Funktion UpdateTransportState wird angenommen, dass es sich um eine Anwendungsfunktion handelt, die die Benutzeroberfläche aktualisiert. Beachten Sie, dass der Thread auf zwei Ereignisse wartet: das Benachrichtigungsereignis (hNotify) und das Threadabschlussereignis (hThreadEnd). Beachten Sie auch, wo der kritische Abschnitt verwendet wird, um die Gerätezustandsvariable zu schützen.
DWORD WINAPI ThreadProc(void *pParam)
{
HRESULT hr;
HANDLE EventHandles[2];
HANDLE hNotify = NULL;
DWORD WaitStatus;
LONG State;
// Get the notification event handle. This event will be signaled when
// the next state-change operation completes.
hr = pTransport->GetStatus(ED_NOTIFY_HEVENT_GET, (long*)&hNotify);
while (hThread && hNotify && hThreadEnd)
{
EnterCriticalSection(&csIssueCmd);
// Ask the device to notify us when the state changes.
hr = pTransport->GetStatus(ED_MODE_CHANGE_NOTIFY, &State);
LeaveCriticalSection(&csIssueCmd);
if(hr == E_PENDING) // The device supports notification.
{
// Wait for the notification.
EventHandles[0] = hNotify;
EventHandles[1] = hThreadEnd;
WaitStatus = WaitForMultipleObjects(2, EventHandles, FALSE, INFINITE);
if(WAIT_OBJECT_0 == WaitStatus)
{
// We got notified. Query for the new state.
EnterCriticalSection(&csIssueCmd);
hr = m_pTransport->get_Mode(State);
UpdateTransportState(State); // Update the UI.
LeaveCriticalSection(&m_csIssueCmd);
ResetEvent(hNotify);
}
else {
break; // End this thread.
}
}
else {
// The device does not support notification.
PollDevice();
}
} // while
// Cancel notification.
hr = pTransport->GetStatus(ED_NOTIFY_HEVENT_RELEASE, (long*)&hNotify);
return 1;
}
Verwenden Sie auch den kritischen Abschnitt, wenn Sie Befehle für das Gerät ausgeben, wie folgt:
// Issue the "stop" command.
EnterCriticalSection(&csIssueCmd);
if (SUCCEEDED(hr = pTransport->put_Mode(ED_MODE_STOP)))
{
UpdateTransportState(ED_MODE_STOP);
}
LeaveCriticalSection(&csIssueCmd);
Bevor die Anwendung beendet wird, halten Sie den sekundären Thread an, indem Sie das Thread-End-Ereignis festlegen:
if (hThread)
{
// Signaling this event will cause the thread to end.
if (SetEvent(hThreadEnd))
{
// Wait for it to end.
WaitForSingleObjectEx(hThread, INFINITE, FALSE);
}
}
CloseHandle(hThreadEnd);
CloseHandle(hThread);
Abrufen des Verkehrsstatus
Wenn Sie IAMExtTransport::GetStatus mit dem ED_MODE_CHANGE_NOTIFY-Flag aufrufen und der Rückgabewert nicht E_PENDING ist, bedeutet dies, dass das Gerät keine Benachrichtigung unterstützt. In diesem Fall müssen Sie das Gerät abfragen, um seinen Zustand zu ermitteln. Abfragen bedeutet einfach, dass get_Mode in regelmäßigen Abständen aufgerufen wird, um den Transportstatus zu überprüfen. Sie sollten weiterhin einen sekundären Thread und einen kritischen Abschnitt verwenden, wie zuvor beschrieben. Der Thread fragt den Zustand des Geräts in regelmäßigen Abständen ab. Das folgende Beispiel zeigt eine Möglichkeit zum Implementieren des Threads:
DWORD WINAPI ThreadProc(void *pParam)
{
HRESULT hr;
LONG State;
DWORD WaitStatus;
while (hThread && hThreadEnd)
{
EnterCriticalSection(&csIssueCmd);
State = 0;
hr = pTransport->get_Mode(&State);
LeaveCriticalSection(&csIssueCmd);
UpdateTransportState(State);
// Wait for a while, or until the thread ends.
WaitStatus = WaitForSingleObjectEx(hThreadEnd, 200, FALSE);
if (WaitStatus == WAIT_OBJECT_0)
{
break; // Exit thread now.
}
// Otherwise, the wait timed out. Time to poll again.
}
return 1;
}
Zugehörige Themen