Partager via


Contrôle d’un appareil externe

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement au nouveau code d’utiliser MediaPlayer, IMFMediaEngine et La capture audio/vidéo dans Media Foundation au lieu de DirectShow, lorsque cela est possible. Microsoft suggère que le code existant qui utilise les API héritées soit réécrit pour utiliser les nouvelles API si possible.]

Pour contrôler un appareil de magnétoscope (VTR), utilisez la méthode IAMExtTransport::p ut_Mode . Spécifiez le nouvel état à l’aide de l’une des constantes répertoriées dans État du transport de l’appareil. Par exemple, pour arrêter l’appareil, utilisez les éléments suivants :

pTransport->put_Mode(ED_MODE_STOP); 

Étant donné que le VTR est un appareil physique, il existe généralement un décalage entre l’émission de la commande et le moment où la commande est terminée. Votre application doit créer un deuxième thread de travail qui attend la fin de la commande. Une fois la commande terminée, le thread peut mettre à jour l’interface utilisateur. Utilisez une section critique pour sérialiser le changement d’état.

Certains VTRs peuvent notifier l’application lorsque l’état de transport de l’appareil a changé. Si l’appareil prend en charge cette fonctionnalité, le thread de travail peut attendre la notification. Selon la « spécification de sous-unité av/C tape recorder/player » de la 1394 Trade Association, toutefois, la commande de notification d’état de transport est facultative, ce qui signifie que les appareils ne sont pas nécessaires pour la prendre en charge. Si un appareil ne prend pas en charge la notification, vous devez interroger l’appareil à intervalles réguliers pour connaître son état actuel.

Cette section décrit d’abord le mécanisme de notification, puis décrit l’interrogation de l’appareil.

Utilisation de la notification d’état de transport

La notification d’état de transport fonctionne en demandant au pilote de signaler un événement lorsque le transport passe à un nouvel état. Dans votre application, déclarez une section critique, un événement et un handle de thread. La section critique est utilisée pour synchroniser l’état de l’appareil. L’événement est utilisé pour arrêter le thread de travail lorsque l’application se ferme :

HANDLE hThread = 0;
HANDLE hThreadEnd = CreateEvent(NULL, TRUE, FALSE, NULL); 
if (hThreadEnd == NULL)
{
    // Handle error.
}
CRITICAL_SECTION csIssueCmd;
InitializeCriticalSection(&cdIssueCmd);

Après avoir créé une instance du filtre de capture, créez le thread de travail :

DWORD ThreadId;
hThread = CreateThread(NULL, 0, ThreadProc, 0, 0, &ThreadId);

Dans le thread de travail, commencez par appeler la méthode IAMExtTransport::GetStatus avec la valeur ED_NOTIFY_HEVENT_GET. Cet appel retourne un handle à un événement qui sera signalé à la fin d’une opération :

// Get the handle to the notification event.
HANDLE hEvent = NULL;
hr = pTransport->GetStatus(ED_NOTIFY_HEVENT_GET, (long*)&hNotify);

Ensuite, appelez à nouveau GetState et transmettez la valeur ED_MODE_CHANGE_NOTIFY :

LONG State;
hr = pTransport->GetStatus(ED_MODE_CHANGE_NOTIFY, &State);

Si l’appareil prend en charge la notification, la méthode retourne la valeur E_PENDING. (Sinon, vous devez interroger l’appareil, comme décrit dans la section suivante.) En supposant que l’appareil prend en charge la notification, l’événement est signalé chaque fois que l’état du transport VTR change. À ce stade, vous pouvez mettre à jour l’interface utilisateur pour refléter le nouvel état. Pour obtenir la notification suivante, réinitialisez le handle d’événement et appelez à nouveau GetStatus avec ED_MODE_CHANGE_NOTIFY.

Avant la sortie du thread de travail, relâchez le handle d’événement en appelant GetStatus avec l’indicateur ED_NOTIFY_HEVENT_RELEASE et l’adresse du handle :

hr = pTransport->GetStatus(ED_NOTIFY_HEVENT_RELEASE, (long*)&hNotify)

Le code suivant montre la procédure de thread complète. La fonction UpdateTransportState est supposée être une fonction d’application qui met à jour l’interface utilisateur. Notez que le thread attend deux événements : l’événement de notification (hNotify) et l’événement de fin de thread (hThreadEnd). Notez également où la section critique est utilisée pour protéger la variable d’état de l’appareil.

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

Utilisez également la section critique lorsque vous émettez des commandes sur l’appareil, comme suit :

// Issue the "stop" command.
EnterCriticalSection(&csIssueCmd); 
if (SUCCEEDED(hr = pTransport->put_Mode(ED_MODE_STOP)))
{
    UpdateTransportState(ED_MODE_STOP);
}
LeaveCriticalSection(&csIssueCmd); 

Avant la sortie de l’application, arrêtez le thread secondaire en définissant l’événement de fin de thread :

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

Interrogation de l’état de transport

Si vous appelez IAMExtTransport::GetStatus avec l’indicateur ED_MODE_CHANGE_NOTIFY et que la valeur de retour n’est pas E_PENDING, cela signifie que l’appareil ne prend pas en charge la notification. Dans ce cas, vous devez interroger l’appareil pour déterminer son état. L’interrogation signifie simplement appeler get_Mode à intervalles réguliers pour case activée l’état de transport. Vous devez toujours utiliser un thread secondaire et une section critique, comme décrit précédemment. Le thread interroge l’appareil pour son état à intervalles réguliers. L’exemple suivant montre une façon d’implémenter le thread :

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

Contrôle d’un caméscope DV