GUNの備忘録

なんでも忘れないように書いておくよ

*

Building QuickTime Capability Into a Windows Application

注:この文章はApple社より提供されている「QuickTime Guide for Windows」をあくまでも自分用に和訳したものです。英語が得意ではないのでかなりの確率で間違っている可能性がありますので理解できない場合は原文を読むことをお勧めします。

■QuickTimeの機能をWindowsアプリケーションへ構築する

Windowsアプリケーションプログラム構造へQuickTimeルーチンを組み込むことは比較的簡単です。あなたはシンプルなQuickTimeの機能をWindowsのプログラムに構築するためにここに概説された次の基本ステップに従う必要があります。括弧で囲まれた名前は関連するQTMLルーチンです。
1.プログラムの開始時にQuickTime Media Layer(InitializeQTML)とQuickTime(EnterMovies)を初期化します。
2.あなたのムービーウィンドウとQuickDrawのグラフィックポートを関連付けます(CreatePortAssociation)。
3.ムービーファイルを開き(OpenMovieFile)、ムービーを展開します。(NewMovieFromFile)。
4.スクリーン上へムービーを表示するためのムービーコントローラを作成します(NewMovieController)。
5.ウィンドウプロシージャの中で到着したメッセージをQTMLイベントへコンバートします(WinEventToMacEvent)、そしてそれらを処理するためにムービーコントローラへ渡します。(MCIsPlayerEvent)
6.必要ななくなればムービーとそのコントローラを破棄します(DisposeMovie/DisposeMovieController)。
7.ウィンドウを破棄するときにあなたが作成したムービーウィンドウのグラフィックポートを破棄します(DestroyPortAssociation)。
8.プログラム終了時にQuickTimeとQuickTimeMediaLayerを終了します(ExitMovies/TerminateQTML)。
リスト2-1のイラストは、これらのステップをどのように標準的なWindowsアプリケーションプログラムへフィットさせるかの骨組みです。

基本的なQTMLルーチン

このセクションではそれらの基礎となるQTMLのコンセプトの背景を通し、WindowsアプリケーションへQuickTimeの機能を構築するための基本的なQuickTIme Media Layer(QTML)ルーチンについて述べます。

QTMLとQuickTimeの初期化と終了

プログラムでQuickTime操作を行う前にはQuickTime Media Layerを初期化し、その次にQuickTime自身を初期化しなければなりません。まずはじめにInitializeQTMLと呼ばれるルーチンを予備、次にEnterMoviesを呼ぶことにより成し遂げます。

InitializeQTMLはほかのQuickTimeコールを呼ぶ前のプログラムのかなり初期に呼び出さなければなりません。
メインウィンドウを作成すr前のWinMain内で呼ぶことを推奨します。この関数は次のように定義されています。

flagパラメータはQuickTimeの振る舞いを特定するため、次の値が指定できます。

項目 定義
kInitQTMLUseDefault 通常使用
kInitQTMLUseGDIFlag DirectDrawやDCIサービスを使用せずにGDIを使用する
kInitQTMLNoSoundFlag サウンドマネージャを初期化しない。すべてのムービーでサウンドが使用不可となります。
kInitializeQTMLDisableDirectSound QTMLによるDirectSoundの使用を不可にします。
kInitializeQTMLUseExclusiveFullScreenModeFlag フルスクリーンモードで操作します。QuickTime3.0以降で使用します。

 

ほとんどの場合、本パラメータはkInitQTMLUseDefaultをセットしたいと思うでしょう、しかし通常ではないケースのために他のオプションがあります。これらは単独で使用するか組み合わせて使います。
関数が成功した場合は0、失敗した場合は0以外を返します。この値を調べ、失敗した場合はQuickTimeが使用できないことをユーザーへ伝えるためにメッセージボックスを表示するなどのように対応を行います。あなたのプログラムの性質により、プログラムを終了させるか、QucikTimeに関する機能を無効にして継続するかを選択する必要があるかもしれません。
プログラムを記述しているときにもしInitializeQTMLが既によばれているかどうかコンテキストからわからない場合、ルーチンの初めにInitializQTMLを追加し、そしてTerminateQTMLをルーチンの最後に呼びます。InitializeQTMLはTerminateQTMLと対応が取れていれば、1回以上呼び出されても不都合はありません。もしInitializeQTMLが既によばれていた場合、サブシーケンスコールはカウンターのインクリメントを行いません。TerminateQTMLを呼ぶとカウンタがデクリメントされます(0でない場合)。ネストされた最初のInitializeQTMLを予備、そして最後のネストされたTerminateQTMLが実際に働くのでこれらのネストされたコールはなんのペナルティーもありません。
EnterMovies関数はQuickTimeの内部データ構造のための空間を確保し、それらを初期化します。プログラムはInitializeQTMLを四だあとすぐにこの関数を呼ぶべきです。関数に引数はなく、エラーコードが返されます。

再び返値を調べ、失敗した場合はしかるべき処理を行います。プログラムの最後に、InitializeQTMLとEnterMoviesに対応した終了ルーチンであるExitMoviesとTerminateQTMLを呼ぶべきです。これらの関数は引数、返値はありません。

リスト2-2はこれらの初期化と終了を標準的なWinMainルーチンに適用したものです。

リスト2-2 QuickTimeを使用したウィンドウズプログラムのメインルーチン

グラフィックポートを使う

MacOSが元であるので、QuickTimeはスクリーンを描画するのにQuickDrawグラフィックルーチンを使用します。
QuickDrawはWindowsのGraphics Device Interface(GDI)に対し、Macintoshを構成する。Windows下で動いているときQuickTime Media Layerの互換インターフェースはそれらの描画操作のための内部的なQuickDrawコールを使用するQuickTimeルーチンを許可する。だからQuickTimeを正しく使用するため、QuickDrawについて少し理解する必要があります。
基本的なQuickDrawデータ構造はグラフィックポート(Windowsのデバイスコンテキスト)です。これはQucikDrawの描画操作をコントロールするために必要なすべてのパラメータを特定するための完全な描画環境です。ポートは大きさ、ライン描画用のペン色とパターン(Windowsでいうブラシ)、領域フィル、背景、テキスト表示のためのフォント、サイズとスタイル、クリッピング境界のようなものを含みます。このすべての情報はCGrafPtrタイプのポインタで示されるCGrafPortタイプデータ構造の中に保持されています。
C言語でのCGrafPortとCGrafPtrはクラシックな白黒バージョンであるGrafPortとGrafPtrから見分けるために生まれました。GrafPortとGrafPtrは現在廃れていて、どの通常はGrafPort又はGrafPtrを期待するQTMLルーチンはCGrafPortやCGrafPtrも受け付けます。
グラフィックポートの主な目的はQuickDrawのグラフィック操作を行う環境として勤めることです。WindowsのGDIルーチンと異なり、いつでも詳細パラメータとしてデバイスコンテキストを受け付けます。ほとんどのQTMLのQuickDrawルーチンは暗黙的にカレントポートに対して操作を行います。いつの場合でも1つのグラフィックポートがカレントポートとなります。
QTMLルーチンのGetPort

は、カレントポートのポインタを返し、MacSetPortは、

は、カレントポートを変更します。
このルーチンのMacOSでのオリジナル名はSetPortですが、WindowsAPIに存在する名前と競合するためMacSetPortに変更されました。
グラフィックポートは画面のウィンドウに密着しています、QuickDrawの描画操作に使用するカレントポートは通常ウィンドウです。Windows環境で実行している場合、動画を表示する用途でQuickTimeルーチンのために動画ウィンドウに紐付いたMacOSスタイルのグラフィックポートと付き合わなければなりません。次のセクションではどうやってそれを行うかについて述べます。

再定義されたAPI名
Macintoshアプリケーションプログラミングインターフェースで定義されたいくつかの名前はWindowsAPIと競合しています。これらのケースはQTMLのヘッダーファイルQTMLMapNames.hで名前の先頭にMacを付加して再定義することにより競合を回避しています。
表2-2では、1列目にMacintoshでのオリジナルの機能又は構造名、2列目に再定義または新しくマップされた名前を記載しています。

表2-2 再定義されたAPI名 <注:原文ではTable2-1となっていますが、上記説明で2-2になっているので2-2にしています)

オリジナルAPI名 マップされた名前
AnimatePalette MacAnimatePalette
AppendMenu MacAppendMenu
CloseDriver MacCloseDriver
CloseWindow MacCloseWindow
CompareString MacCompareString
CopyRgn MacCopyRgn
DeleteMenu MacDeleteMenu
DrawMenuBar MacDrawMenuBar
DrawText MacDrawText
EqualRect MacEqualRect
EqualRgn MacEqualRgn
FillRect MacFillRect
FillRgn MacFillRgn
FindWindow MacFindWindow
FlushInstructionCache MacFlushInstructionCache
FrameRect MacFrameRect
FrameRgn MacFrameRgn
GetClassInfo MacGetClassInfo
GetCurrentThread MacGetCurrentThread
GetCursor MacGetCursor
GetDoubleClickTime MacGetDoubleClickTime
GetFileSize MacGetFileSize
GetItem MacGetItem
GetMenu MacGetMenu
GetNextWindow MacGetNextWindow
GetParent MacGetParent
GetPath MacGetPath
GetPixel MacGetPixel
InsertMenu MacInsertMenu
InsertMenuItem MacInsertMenuItem
InsetRect MacInsetRect
InvertRect MacInvertRect
InvertRgn MacInvertRgn
IsWindowVisible MacIsWindowVisible
LineTo MacLineTo
LoadResource MacLoadResource
MoveWindow MacMoveWindow
OffsetRect MacOffsetRect
OffsetRgn MacOffsetRgn
OpenDriver MacOpenDriver
PaintRgn MacPaintRgn
Polygon MacPolygon
PtInRect MacPtInRect
Region MacRegion
ReplaceText MacReplaceText
ResizePalette MacResizePalette
SendMessage MacSendMessage
SetCursor MacSetCursor
SetItem MacSetItem
SetPort MacSetPort
SetRect MacSetRect
SetRectRgn MacSetRectRgn
ShowCursor MacShowCursor
ShowWindow MacShowWindow
StartSound MacStartSound
StopSound MacStopSound
TokenType MacTokenType
UnionRect MacUnionRect
UnionRgn MacUnionRgn
XorRgn MacXorRgn

ウィンドウレコード

ほとんどの描画ではウィンドウの画面上での一をとるので、グラフィックポートはQTMLウィンドウレコードの基礎にもなっています(CWindowRecrod)。
ここで気を付けるポイントはその最初のフィールド(port)をグラフィックポートに対するポインターではないもので保持することです。しかし実際には完全なグラフィックポート構造がウィンドウレコードには直接埋め込まれています。マシーンレベルでは、ウィンドウレコードはグラフィックポートにいくつかの項目(ウィンドウの特徴情報)を後ろに追加拡張したものといえます。実際カラーウィンドウのポインタ(CWindowPtr)はグラフィックポートのポインタ(CGrafPtr)と等しいとみなされます。

これはグラフィックポートを使用する場面でどちらのコンテキストでも許されます。2種類のポインタが同じデータタイプである時から、多くのグラフィックポートを必要としているQuickDrawルーチンはウィンドウのポインタも受け付けるでしょう。
WindowsプラットフォームではしかしながらQTMLポインタ(CWindowPtr)よりもむしろWindowsスタイルのハンドル(HWND)でデザインされています。QuickTimeのウィンドウへの描画を許可するために、最初にあなたはQTMLのルーチンCreatePortAssociationを呼び出し登録をしなければなりません。

これはグラフィックポートとQTMLによって確保された内部構造の中にウィンドウをもった付属データを作成します。最初のパラメータ(theWnd)は、ウィンドウスタイルのウィンドウハンドル(HWND)を指定します。第2パラメータ(storage)には必要であればCGrafPortのためのストレージを与えることができます。一般的にはいつもnilでとおし、メモリ確保の呼び出しを許可するでしょう。(もしあなたがこのパラメータにnullを指定した場合、QTMLはスペースを確保します)。
一般的にはリスト2-3のようにWM_CREATEメッセージに応答する部分のウィンドウプロシージャよりCreatePortAssociationを呼び出すことにより動画用のウィンドウを登録します。
リスト2-3 ポートアソシエーションの作成

一度ウィンドウを登録するとその後はGetHWNDPortでQTMLスタイルのウィンドウポインタを取得することができるようになります。

逆にウィンドウポインタからウィンドウハンドルを取り直す変換関数もあります。

別のウィンドウを使うときは、DestroyPortAssociationを使用し、グラフィックポートを解放できます。

ウィンドウプロシージャにおいてこれを行うのによい場所はWM_CLOSEかWM_DESTROYメッセージの処理部分です。リスト2-4はどのようにポートアソシエーションを解除するかの例です。
 
リスト2-4 ポートアソシエーションの解除

グラフィックワールド(GWorlds)とそれらをどう働かせるか

QuickTimeの画像表示方法に影響するグラフィック環境のもう一つの様相は、それらを提供するグラフィックデバイスの性質です。これらはデバイスのピクセル解像度、カラー深度(bit数)、そしてカラーテーブルの容量といった事柄含みます。デバイスの性質はグラフィックスデバイスレコード(graphics device record)に要約されます。
 
通常プログラムでの描画操作の結果は実行時のユーザーのコンピュータに接続されたディスプレイデバイスの能力に依存します。同じシステム上に接続された1つ以上のデバイスに対して行うことができます:QTMLは各デバイスの性質により描画する画面を見つけ出し、結果を表示するでしょう。これらは通常プログラムを実行する上で透過的に自動で行われます。
 
時々、もしかするとプログラムは描画操作するためのグラフィック環境を制御する上でより多くの権限を取得する必要がでることがあります。もしQuickTimeの動画を作成する場合、グラフィックデバイスへの動画を出したくない場合があります。むしろ動画コンテンツとデバイスの性質(デプスやカラー等)とは独立させたいはずです。その場合、ユーザーのコンピューターに動画が表示される時、QuickTimeは自動的に表示可能なデバイスへ接続し、与えられたデバイス上で表示されるでしょう。
 
これを成し遂げるための方法は独立したデバイスのグラフィックスワールドに関する動画を定義することです。これはQuickTimeがその描画を行うグラフィックス環境を互いに完全に決定するグラフィックポートとデバイスレコードをつなぎ合わせます。前項で記述したウィンドウレコードのように、グラフィックワールドのデータ構造はいくつかのフィールドをグラフィックポートの後ろに拡張したものとなっています。厳密にはQTMLのプライベートなものとなっています:グラフィックワールドは常にGWorldPtr型のポインタを暗黙的に参照されています。なぜならその下の構造はグラフィックポートが元となっているためです。しかしこのポインタはグラフィックポートのポインタと同様に扱われます。
 

 
これは(ウィンドウポートの時と再び同じとなりますが)グラフィックワールドはグラフィックポートと同じとして扱われるため、描画操作のためのカレントポートをセットするMacSetPort関数の引数として使用できます。
 
グラフィックワールドのデバイスレコードは既存の物理的なグラフィックデバイスに似せることができます。しかしそれは必要ではありませんが:あなたが選択した様々なグラフィックの性質をもつ”offscreen”デバイスを記述できます。QTML関数NewGWorldに欲しいパラメータとして与えた特別のoffscreenグラフィックワールドを作ります。

 
とりわけ、flagsに指定するnoNewDeviceフラグがクリアであるとき、この関数はaGDeviceパラメータを無視し、この関数は新しいデバイス固有のデバイスレコードを作成します。それからこのデバイスレコードと(スクリーンへ直接よりもむしろ)メモリベースのイメージバッファへ描画するためのグラフィックポートを結びつけます。そしてその結果offscreenGWorld へグラフィックワールドへのポインタを返すでしょう。
 
グラフィックワールドを作成するためにNewGWorld関数を使用するとき、そのイメージバッファとしてMacintoshスタイルのビットマップ上に描画をセットアップするでしょう。もしその代わりにウィンドウスタイルのbitmapでそれを働かせたい場合、Windowsバージョン専用のQuickTimeAPIを使用することができます。
 

newHBITMAPとnewHDCパラメータはどちらもnullまたはウィンドウビットマップハンドルとデバイスコンテキストのどちらかでないといけません。どちらもnullの場合、この関数は完全なグラフィックワールドを確保し、ビットマップハンドルとデバイスコンテキストが与えられた場合は、その構造をラップします。これは画像の圧縮やCopyBitsなどのQuickTime操作のためのもととしてWindowsのネイティブな描画環境を使用可能にします。もしWindowsのビットマップが与えられた場合、それはWindowsの関数CreateDIBSectionにより作成されたDIBでなければなりません。
 

 

公開日:
最終更新日:2014/05/30