ファイルの書き込み
[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、および Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayer、IMFMediaEngine、Audio/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, ¶m1, ¶m2, 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);
}
}