QuickTime SDK for Windowsで動画再生(2)
前の投稿で、aviが再生されない問題はとりあえずあきらめました・・・。
QuickTime Player自身でも再生できないのでプログラムの問題ではなく、単にQuickTimeの対応フォーマットの問題だと思われるためです。対応できていないフォーマットはとりあえずプログラミングとは別問題なのでまた別の機会に検証することにします。
とりあえず動画の再生のところまではこぎつけたので、とりあえず手順を書いておきます。
1.アプリケーションの先頭部分で、QTMLとQuickTimeの初期化を行う。例えばWinMainの先頭で、
1 2 |
InitializeQTML(0); //QTML初期化 EnterMovies(); //QuickTimeの初期化 |
みたいな感じで書いておく。これらの関数は失敗すると返値に0以外の大体負の値が返るので、それでエラー判定をする。
また、後で10msのタイマーを作成するので、タイマーの精度を上げる記述をしておく。
1 |
timeBeginPeriod(1); |
これに対応して、アプリケーション終了時にタイマーの精度を戻しておく。WinMainの最後のreturnの直前にでも入れておけばOK。
1 |
timeEndPeriod(1); |
2.ウィンドウが作成される時、つまりイベントループのWM_CREATEが来た時にCreatePortAssociationを呼び出し、QTML用のウィンドウを登録する。
1 |
CreatePortAssociation (hWnd, NULL, 0); |
3.ファイルの選択ダイアログ等で、動画ファイルが選択された時や、もしくは固定的な動画ファイル名をどこかで開く場合は、1~2の操作が終わった後、次のような感じで動画ファイルをオープンする。(filename[]に動画ファイルのフルパス名が入っているとする)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
short theFile = 0; FSSpec sfFile; char fullPath[255]; Rect rc; //グラフィックポートのセット(おそらくWindowsでいう描画用のハンドルみたいなもの) SetGWorld((CGrafPtr)GetNativeWindowPort( hwnd ), nil); //動画ファイルパスをワーク用のfullpath配列へコピー strcpy_s(fullPath, fileName); //パスをパスカル文字列に変換 c2pstr (fullPath); //FSSpec形式のファイル情報を取得 FSMakeFSSpec (0, 0L, (ConstStr255Param)fullPath, &sfFile); //動画ファイルをオープン OpenMovieFile (&sfFile, &theFile, fsRdPerm); //動画ファイル情報(ハンドル?)を作成 NewMovieFromFile (&theMovie, theFile, nil, nil, newMovieActive, nil); //動画ファイルを閉じる CloseMovieFile (theFile); //動画ファイル操作を行う矩形を指定(実際には動画ファイルから大きさを取得した方が良いでしょう) rc.top = 0; rc.left = 0; rc.right = 704 rc.bottom = 480; //後々の操作のためにムービーコントローラーのハンドルを取得しておく theMC = NewMovieController (theMovie, (const Rect *)&rc, mcNotVisible); //動画再生開始 StartMovie(theMovie); //更新用タイマーを作成(10ms) SetTimer(hwnd, ID_TIMER_1, 10, (TIMERPROC) NULL); //ID_TIMER_1は適当な数値を#defineしておく。即値でもOK) |
4.ウィンドウプロシージャの最初の方で、WindowsのイベントをQuickTime側へ渡すコードを書いておく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; MSG winMsg; EventRecord qtmlEvent; DWORD msgPos; winMsg.hwnd = hWnd; //ウィンドウハンドル winMsg.message = message; //メッセージタイプ winMsg.wParam = wParam; //Wordパラメータ winMsg.lParam = lParam; //Long-wordパラメータ winMsg.time = GetMessageTime(); //メッセージの時間 msgPos = GetMessagePos(); //マウスポジション winMsg.pt.x = LOWORD(msgPos); //Extract x coordinate winMsg.pt.y = HIWORD(msgPos); //Extract y coordinate //WindowsのイベントをQTMLイベントに変換する NativeEventToMacEvent(&winMsg, &qtmlEvent); //Pass event to QuickTime MCIsPlayerEvent (theMC, &qtmlEvent); ・ ・ ・ |
5.3の時に作成したタイマー用の処理で、WM_TIMERイベントの処理部分に、MoviesTask関数を記述する。
(これで描画の更新をしている???。第2パラメータは最大待ち時間??とりあえず50msを指定)
1 2 3 |
case WM_TIMER: MoviesTask(theMovie, 50); break; |
6.ウィンドウ破棄時のイベント処理(WM_DESTROY)時に、タイマーや作成した色々を破棄するコードを記述。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//タイマー削除 KillTimer(hWnd, ID_TIMER_1); //ムービーコントローラーのハンドルがある場合は解放する if ( theMC ) { DisposeMovieController (theMC); } //ムービーハンドルがある場合は解放する if ( theMovie ) { DisposeMovie (theMovie); } CGrafPtr qtmlPtr; qtmlPtr = (CGrafPtr)GetHWNDPort(hWnd); //このキャストはいい?メンバがかなり違うような・・ // Unregister window with QTML。CreatePortAssociationで登録したものを解放。 DestroyPortAssociation(qtmlPtr); //QuickTimeの終了 ExitMovies(); //QTML終了 TerminateQTML(); //この2行は、WinMain関数のメッセージループを PostQuitMessage(0); //抜けたところに記述してもいけてます |
ファイルの選択ダイアログ等を開いて動画ファイルを指定する場合、メニュー選択時のメッセージのWM_COMMANDで開くダイアログのメッセージ(IDM_OPEN等)を受けた時に、上記のDisposeMovieControllerと、DisposeMovieをif文も含めて記述しておくと、ムービーやムービーコントローラーが取得されているときに解放してからファイルを開くダイアログが出るので、解放し忘れがなくなります。(ドキュメントに記載)
とまあこんな感じで書いたら動画を作成したウィンドウ上で再生させることができるまではできたのですが・・・
QuickTimeSDK for Windowsのドキュメントは本当に概要だけで、細かい制御のことは全くといっていいほど載っていないのでこれ以上進めることができませんでした。
だれか書いてくれてないかなーと思ったのですが、本当にWindowsでQuickTimeSDKを使ったプログラミングを解説とかしてくれてるサイトが見つからない・・・。外国のサイトだとちょこちょこあるようなのですがでもあまり多く見つけられない上、断片的なコードしか載っていないものが多く、またほとんどはMacの古いバージョンでのコードが多かったです。QuickTimeSDK自体がかなり古いので仕方がないっちゃそうなのですが・・・。
それで関数名等で検索しているときに見つかったのがGoogleのオンライン書籍(?)で「QuickTime Toolkit Volume One: Basic Movie Playback and Media Types」というものです。歯抜けではあるものの閲覧することができます。
この書籍はAppleが出版しているのかな?とにかく網羅的に書かれているように見えます。英語ですが、リファレンスに使えるレベルだと思います。ただ、電子書籍版の値段が8300円・・・。ちょっと厳しいです・・・orz
しかしWebで検索して出てくる情報が皆無に近い状態のため、歯抜けであってもこの情報はものすごい役立ちます。
たとえば、上記の手順でムービーコントローラーを取得していますが、このムービーコントローラーって一体何に使えるのか全く分からない上、どう使うかもわからないお手上げ状態だったのですが、上記ドキュメント文中を適当に検索してみると、例えば、動画の再生ウィンドウにコントロールバーを表示させようと思ったら、
1 2 |
//コントロールバーの表示制御 MCSetVisible(theMC, true); |
これでいけるみたいな説明が書いてあり、実際試したらそうなりました。表示を消す場合は上記関数の第2引数をfalseにします。
色々あると思うのですがこれからまた色々調べて書いていこうと思います。