Share via


ファイルの書き込み

[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayerIMFMediaEngine、および Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayerIMFMediaEngineAudio/Video Capture を使用することを強くお勧めします。 Microsoft は、従来の API を使用する既存のコードを、可能であれば新しい API を使用するように書き直すよう提案しています。]

ファイルを書き込むには、 IMediaControl::Run メソッドを呼び出してフィルター グラフを実行します。 再生が完了するまで待ち、 IMediaControl::Stop を呼び出してグラフを明示的に停止します。それ以外の場合、ファイルは正しく書き込まれません。

ファイル書き込み操作の進行状況を表示するには、 IMediaSeeking インターフェイスの Mux フィルターに対してクエリを実行します。 IMediaSeeking::GetDuration メソッドを呼び出して、ファイルの期間を取得します。 グラフの実行中に定期的に IMediaSeeking::GetCurrentPosition メソッドを 呼び出して、ストリーム内のグラフの現在位置を取得します。 現在の位置を期間で除算すると、達成率が示されます。

注意

アプリケーションは通常、Filter Graph Manager for IMediaSeeking に対してクエリを実行しますが、ファイルの書き込みは、この規則の例外です。 フィルター グラフ マネージャーは、開始位置から現在の位置と、グラフの実行時間を計算します。これは、ファイルの再生には正確ですが、ファイルの書き込みでは正確ではありません。 したがって、正確な結果を得るには、MUX フィルターから位置を取得する必要があります。

 

次のコードは、ファイルの期間を取得し、アプリケーション UI を更新するためのタイマーを開始し、フィルター グラフを実行します。 (わかりやすくするためにエラー チェックは省略されています)。

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

アプリケーションがタイマー イベントを受信すると、現在の位置で UI を更新できます。

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

アプリケーションが DirectShow 完了イベントを受信すると、次のコードに示すようにグラフが停止されます。

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