Partager via


Écriture du fichier

[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 écrire le fichier, exécutez simplement le graphe de filtre en appelant la méthode IMediaControl::Run . Attendez que la lecture se termine et arrêtez explicitement le graphique en appelant IMediaControl::Stop ; sinon, le fichier n’est pas écrit correctement.

Pour afficher la progression de l’opération d’écriture de fichier, interrogez le filtre Mux pour l’interface IMediaSeeking . Appelez la méthode IMediaSeeking::GetDuration pour récupérer la durée du fichier. Régulièrement pendant l’exécution du graphe, appelez la méthode IMediaSeeking::GetCurrentPosition pour récupérer la position actuelle du graphe dans le flux. La position actuelle divisée par durée donne le pourcentage complet.

Notes

Une application interroge généralement le Gestionnaire de graphes de filtre pour IMediaSeeking, mais l’écriture de fichiers est une exception à cette règle. Le Gestionnaire de graphes de filtre calcule la position actuelle à partir de la position de départ et de la durée d’exécution du graphe, ce qui est précis pour la lecture de fichiers, mais pas pour l’écriture de fichier. Par conséquent, pour obtenir un résultat précis, vous devez récupérer la position à partir du filtre MUX.

 

Le code suivant obtient la durée du fichier, démarre un minuteur pour mettre à jour l’interface utilisateur de l’application et exécute le graphe de filtre. (La vérification des erreurs est omise pour plus de clarté.)

IMediaSeeking *pSeek = NULL;
IMediaEventEx *pEvent = NULL;
IMediaControl *pControl = NULL;
REFERENCE_TIME rtTotal;

// Query for interfaces. Remember to release them later.
hr = pMux->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
hr = pGraph->QueryInterface(IID_IMediaEventEx, (void**)&pEvent);
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);

// Error checking is omitted for clarity.

// Set the DirectShow event notification window.
hr = pEvent->SetNotifyWindow((OAHWND)hwnd, WM_GRAPHNOTIFY, 0);

// Set the range of the progress bar to the file length (in seconds).
hr = pSeek->GetDuration(&rtTotal);
SendDlgItemMessage(hwnd, IDC_PROGRESS1, PBM_SETRANGE, 0, 
   MAKELPARAM(0, rtTotal / 10000000));
// Start the timer.
UINT_PTR res = SetTimer(hwnd, nIDEvent, 100, NULL);
// Run the graph.
pControl->Run();

Lorsque l’application reçoit un événement du minuteur, elle peut mettre à jour l’interface utilisateur avec la position actuelle :

void OnTimer(HWND hDlg, IMediaSeeking *pSeek)
{
    REFERENCE_TIME rtNow;
    HRESULT hr = pSeek->GetCurrentPosition(&rtNow);
    if (SUCCEEDED(hr))
    {
        SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, rtNow/10000000, 0);
    }
}

Lorsque l’application reçoit un événement d’achèvement DirectShow, elle doit arrêter le graphe, comme indiqué dans le code suivant :

// Application window procedure
LRESULT CALLBACK WndProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    /*  ...  */
    case WM_GRAPHNOTIFY:
        DoHandleEvent();
        break;
    /*  ...  */
    }
}

void DoHandleEvent()
{
    long evCode, param1, param2;
    bool bComplete = false;
    if (!pEvent) return;

    // Get all the events, and see we're done.
    while (SUCCEEDED(pEvent->GetEvent(&evCode, &param1, &param2, 0))
    {
        pEvent->FreeEventParams(evCode, param1, param2);
        switch(evCode)
        {
            case EC_USERABORT:
            case EC_ERRORABORT:
            case EC_COMPLETE:
                bComplete = true;
                break;
        }
    }
    if (bComplete)
    {
        pControl->Stop(); // Important! You must stop the graph!

        // Turn off event notification.
        pEvent->SetNotifyWindow(NULL, 0, 0);
        pEvent->Release();
        pEvent = NULL;
        // Reset the progress bar to zero and get rid of the timer.
        SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, 0, 0);
        KillTimer(hwnd, nIDEvent);
    }
}