DirectShowによるビデオの再生

ファイルの再生法」などを参考にC言語でビデオを再生するプログラムを書いてみた。
C言語ではC++インターフェイスをそのまま使うことができないので、クラスに相当するポインタとメソッドの間にヘッダファイルで宣言されているメンバのポインタ(lpVtbl)を差し込み、メソッドの第1引数に自分自身のポインタを入れる必要がある。

#include <stdio.h>
#include <dshow.h>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "strmiids.lib")
#define FILENAME L"Z:\\ふしぎ星の☆みつご姫\\ふしぎ星の☆みつご姫.avi"

int main(void){
  IGraphBuilder *pGraph;
  IMediaControl *pControl;
  IMediaEvent *pEvent;
  
  HRESULT hr = CoInitialize(NULL);
  if(FAILED(hr)){
    fprintf(stderr, "エラー - COM ライブラリを初期化できませんでした。");
    exit(1);
  }
  
  hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&pGraph);
  if(FAILED(hr)){
    fprintf(stderr, "エラー - フィルタグラフマネージャを生成できませんでした。");
    exit(1);
  }
  
  hr = pGraph->lpVtbl->QueryInterface(pGraph, &IID_IMediaControl, (void **)&pControl);
  hr = pGraph->lpVtbl->QueryInterface(pGraph, &IID_IMediaEvent, (void **)&pEvent);
  hr = pGraph->lpVtbl->RenderFile(pGraph, FILENAME, NULL);
  if(SUCCEEDED(hr)){
    hr = pControl->lpVtbl->Run(pControl);
    if(SUCCEEDED(hr)){
      long evCode;
      pEvent->lpVtbl->WaitForCompletion(pEvent, INFINITE, &evCode);
      switch(evCode){
        case 0:
          fprintf(stderr, "タイムアウト\n");
          break;
        case EC_COMPLETE:
          fprintf(stderr, "完了\n");
          break;
        case EC_ERRORABORT:
          fprintf(stderr, "エラーによる終了\n");
          break;
        case EC_USERABORT:
          fprintf(stderr, "ユーザー操作による終了\n");
          break;
      }
    }
  }
  
  pControl->lpVtbl->Release(pControl);
  pEvent->lpVtbl->Release(pEvent);
  pGraph->lpVtbl->Release(pGraph);
  CoUninitialize();

  return 0;