ただ、いつまで続けられるのかはお約束できないのがちょっと問題なのですが...
少なくとも第一陣のこれっきりということは無いようにはしたいな、と思っています。
INDEX
Special Thanks
Avisynthフィルタの動作 2005. 5. 5 (01版) |
---|
まず、APLがオープンすると、スクリプト上のLoadPlugin行で、dllがロード/チェックされ、
AvisynthPluginInit2()がコールバックされます。
ここで、AddFunction()によりプラグイン管理テーブルに関数が登録されることになります。
次に、スクリプト上で関数の記述があれば、上記テーブルに登録されている関数エントリがinvokeされます。
そこで実際にフィルタクラスのインスタンスが生成され、コンストラクタが実行されることになります。
これがスクリプトの最後まで処理されることで、フィルタのチェーンが完成することになります。
チェーンが完成後は、APLからのフレームデータ要求(read)に応じて、チェーンの最後尾のフィルタのGetFrame()
がコールバックされ、その中からその手前のフィルタのGetFrame()が呼び出されるということを繰り返し、
そのGetFrame()要求は先頭のフィルタまで到達し、最後には入力ソースデータに行き着くことになります。
(なお、GetFrame()はフレームb指定でき、各フィルタは複数のフレームデータを要求することもできます。)
逆に画像データは入力データから要求されたフィルタ処理を順次通過して、最後にはAPLに通知されることになります。
APLがクローズすると、各フィルタクラスは破棄され、その時点でデストラクタが呼び出されます。
開発環境を用意する(1) [C++ 編] 2005. 7.16(04版) |
---|
4月のSDK関連の変更にあわせて内容を一新。旧版は右を参照→ 2004. 7. 3 (01版) |
2005. 5. 5 (02版) 2005. 5.19(03版) |
以下の2つをダウンロード、インストールしてください。
1. Visual C++ Toolkit 2003
Microsoft Visual C++ Toolkit 2003
2. Platform SDK (以下のいづれか一つ)
Windows Server 2003 SP1 Platform SDK Web Install
Windows Server 2003 SP1 Platform SDK Full Download
Windows Server 2003 SP1 Platform SDK ISO Install
XPSP2 PSDK Full Download with Local Install
※ 一見XPSP2 PSDKが良さそうに見えますが、これには nmake.exe が入っていません。 ただ以下の.NET framework SDKをインストールするのならその中にnmake.exeは入っています。 またリソースをコンパイルするのなら、コンパイル済リソース(.res)をCOFFオブジェクトに変換する ためのcvtres.exeが必要になってきますが、なんとPSDK SP1の場合、以前のように\win64から コピーしてきても動作しません。 依存するdllが新しくなっており、msvcr71.dllではなくmsvcr80.dllが必要なようです。 つまり残念ながらリソースのコンパイルはできなくなってしまいました。 (リソースコンパイラ rc.exe 自体は存在するのに何故cvtres.exeは無いのだろう?) どうしてもリソースもリンクしたい人は、以下のものもダウンロード/インストールしてください。 3. .NET Framework 通常のWindows Updateなどでインストールできるランタイム版で良いのですが、 SDKの方も欲しい人のためにリンクをあげておきます。 (SDKはそのバージョンのランタイムのインストールも必要とします)
|
----- file : F:\Program Files\Microsoft Visual C++ Toolkit 2003\vcvars32.bat ----- @echo off Set PATH=F:\Program Files\Microsoft Visual C++ Toolkit 2003\bin;%PATH% Set INCLUDE=F:\Program Files\Microsoft Visual C++ Toolkit 2003\include;%INCLUDE% Set LIB=F:\Program Files\Microsoft Visual C++ Toolkit 2003\lib;%LIB% goto skip echo Setting environment for using Microsoft Visual C++ 2003 Toolkit. echo (If you have another version of Visual Studio or Visual C++ installed and wish echo to use its tools from the command line, run vcvars32.bat for that version.) echo. echo Thank you for choosing the Visual C++ Toolkit 2003! Get started quickly by echo building the code samples included in the "Samples" directory. Each sample echo includes a short whitepaper discussing the Visual C++ features, and a batch echo file for building the code. echo. echo Type "cl /?" for brief documentation on compiler options. echo. echo Visit http://msdn.microsoft.com/visualc/using/documentation/default.aspx for echo complete compiler documentation. :skip f: cd \src echo ようこそ Microsoft Visual C++ の世界へ ---------------------------------------------------------------------------------- |
長いので省略して変更部分のみを示します。 ----- file : F:\Program Files\Microsoft Platform SDK\SetEnv.Cmd [line:40]--------- :Chk_OS REM Set OS/platform-specific variables set path=%SystemRoot%\Microsoft.NET\Framework\v1.1.4322;%path% call "%VCToolkitInstallDir%\vcvars32.bat" Set Include=%MSSdk%\Include\mfc;%Include% goto Set_OS :Finish set INCLUDE=f:\src\include;%INCLUDE% Goto end ---------------------------------------------------------------------------------- (.NET Framework v1.1の人は、set path行で、\v1.1.4322;を、 v2.0βの人は、\v2.0.50215を入れてください。 また入れてない人はこの行を削除してください。) なお、パスを通すのが不安な人は cvtres.exeを%VCToolkitInstallDir%\bin\ にコピーしてください) (もし、VC++ Toolkit 2003の方の環境を優先したければ、44行目の:FinishとGoto endの間に call文を移動してください。) |
設定し終えたら、コマンドプロンプトを起動して環境変数がきちんと設定されているか確認しましょう。
F:\Src>set path
とタイプし、Enterキーを押せば設定内容が表示されます。以下同様に、
F:\Src>set include
F:\Src>set lib
以上で基本の環境の構築は終わりです。
|
|
開発環境を用意する(2) [ASM 編] 2004. 7. 3 (01版) |
---|
開発環境を用意する(3) [Avisynth 編] 2004. 7. 3 (01版) |
---|
set INCLUDE=f:\src\include\.;%INCLUDE% |
以上で必要なものは大体揃ったことになりましたね。
おっと、大事なものがまだありません。ソースコードを作成するものが必要です。
テキストエディタと呼ばれる分野のソフトですね。
世の中にはいろいろ存在するので、自分に合ったものを探しておきましょう。
Windows標準のメモ帳(notepad.exe)を使う場合は、文字コードセットはANSIにしておきましょう。
色空間形式(color format)を理解しよう 2004. 7. 3 (01版) |
---|
※1 ただし、Avisynth内では、データ境界(Date Boundary)はDWORD(4bytes)とは限りません。 8/16/32バイトの場合もありますし、それ以上の場合もあります。 この余白は、後の章で説明するpitchで管理することになります。 |
※2 ただし、Avisynth 2.5系では、横幅は4の倍数(multiple of 4)でなければなりません。 |
※3 Avisynth 2.5系では、横幅は4の倍数(multiple of 4)でなければなりません。 |
クリップ(Clip)構造を理解しよう(画像編) 2004. 7. 3 (01版) |
---|
クリップ(Clip)構造を理解しよう(サウンド編) 2004. 7. 3 (01版) |
---|
クリップ(Clip)の各要素 2004. 7. 3 (01版) |
---|
VideoInfo | int width, height |
unsigned int fps_numerator, fps_denominator | |
int num_frames | |
int pixel_type | |
int audio_samples_per_second | |
int sample_type | |
__int64 num_audio_samples | |
int nchannels | |
int image_type | |
bool HasVideo() | |
bool HasAudio() | |
bool IsRGB() | |
bool IsRGB24() | |
bool IsRGB32() | |
bool IsYUV() | |
bool IsYUY2() | |
bool IsYV12() | |
bool IsColorSpace(int c_space) | |
bool Is(int property) | |
bool IsPlanar() | |
bool IsFieldBased() | |
bool IsParityKnown() | |
bool IsBFF() | |
bool IsTFF() | |
bool IsVPlaneFirst() | |
int BytesFromPixels(int pixels) | |
int RowSize() | |
int BMPSize() | |
__int64 AudioSamplesFromFrames(__int64 frames) | |
int FramesFromAudioSamples(__int64 samples) | |
__int64 AudioSamplesFromBytes(__int64 bytes) | |
__int64 BytesFromAudioSamples(__int64 samples) | |
int AudioChannels() | |
int SampleType() | |
int SamplesPerSecond() | |
int BytesPerAudioSample() | |
void SetFieldBased(bool isfieldbased) | |
void Set(int property) | |
void Clear(int property) | |
int BitsPerPixel() | |
int BytesPerChannelSample() | |
void SetFPS(unsigned numerator, unsigned denominator) | |
bool IsSameColorspace(const VideoInfo& vi) | |
スケルトン(1) 2004. 7. 7 (01版) |
---|
F:\Src | +--- include | | | +--- avisynth.h | +--- sample | +--- sample.cpp | +--- makefile
---------------------------- f:\src\sample\sample.cpp : start --------------------------- #include <windows.h> #include "avisynth.h" class Sample : public GenericVideoFilter { public: Sample(PClip _child, IScriptEnvironment* env); ~Sample(); PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); }; Sample::Sample(PClip _child, IScriptEnvironment* env) : GenericVideoFilter(_child) { } Sample::~Sample() { } PVideoFrame __stdcall Sample::GetFrame(int n, IScriptEnvironment* env) { PVideoFrame src = child->GetFrame(n, env); env->MakeWritable(&src); const int pitch = src->GetPitch(); const int rowsize = src->GetRowSize(); const int width = src->GetRowSize()>>1; //case of YUY2 const int height = src->GetHeight(); const int modulo = pitch - src->GetRowSize(); const BYTE* srcp = src->GetReadPtr(); BYTE* dstp = src->GetWritePtr(); return src; } AVSValue __cdecl Create_Sample(AVSValue args, void* user_data, IScriptEnvironment* env) { return new Sample(args[0].AsClip(), env); } extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) { env->AddFunction("Sample", "c", Create_Sample, 0); return "`Sample' Sample plugin"; } ---------------------------- f:\src\sample\sample.cpp : end ---------------------------- |
#include "avisynth.h" |
プラグインの動作に必要な変数や関数、クラスを定義しています。 プラグインは、Avisynth.dllをロードして関数エントリを調べる必要はありません。 Avisynth.dllからコールバックされる形になります。 |
class Sample : public GenericVideoFilter { public: Sample(PClip _child, IScriptEnvironment* env); ~Sample(); PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); }; |
Avisynthがプラグイン作成のために提供しているGenericVideoFilterクラスを 継承して新しい派生クラス Sample を定義します。 これは標準で1つのClipを持っています。 もともとGenericVideoFilterクラスはIClipクラスの派生クラスで、 プラグイン作成の便宜をはかるためのものです。 このクラスを使うことで、不要なメンバ関数を省略することができます。 ただし、IClipクラスから直接派生させた方が良い場合もあります。 例えば、私のプラグインの一つであるBefaですが、入力が音声のみでも動作するように IClipから派生させています。入力引数にClip(VideoFrame)が無い場合、GenericVideoFilterクラスを ベースにしているとVideoFrameが無い為にエラーになってしまうからです。 まあ、あまりこのような必要も無いとは思いますが。 ここでは、publicなメンバ関数として以下の3つをプロトタイプ宣言しています。 ・Sample は、コンストラクタ(初期化処理関数)であり クラスのインスタンスが生成された時に行う初期処理を記述します。 引数は、この場合は クリップのポインタ _child と 環境 env の2つですが、 後述するプラグインの登録時の指定に依存します。 ・~Sampleはデストラクタ(終了処理関数)であり インスタンスが破棄される時に行う終了処理を記述します。(省略可能) ・GetFrameには、実際に行う画像フィルタ処理を記述します。 最後が;(セミコロン)で終わっているのは、ここでは実際の処理は記述せずに メンバ関数のプロトタイプ宣言であるということを示しています。 もちろん、ここで実際の処理内容を記述することもできますが、長くなると クラス構造の見通しが悪くなるので、このようにしています。 ここには記述してはいませんが、他にもオーバーロードできるメンバ関数として以下のものがあります。 void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) bool __stdcall GetParity(int n) void __stdcall SetCacheHints(int cachehints,int frame_range) また、このクラスにはprotectedなメンバ変数として、 PClip child; VideoInfo vi; があります。 (protectedとは、アクセスの指定でありpublicとprivateの中間であり、 クラス外からの参照は不可ですが、派生したクラスからの参照は可能なものです。) |
Sample::Sample(PClip _child, IScriptEnvironment* env) : GenericVideoFilter(_child) { } |
前述したSampleクラスのコンストラクタです。 スコープ演算子::で所属するクラスを指定しています。 なお、引数は、後述する入口関数Create_Sampleでクラスを生成するとき指定したパラメタ が渡されてきます。必要が無ければenvを省略して Sample(PClip _child) としてもかまいません。 コンストラクタは、クラスの初期処理を記述します。動的な領域の獲得や変数の初期化等です。 ここでviの値を変更することで、フレームデータの出力形式を変更することができます。 色空間、フレームレート、幅、高さ等を変更する場合に処理を記述します。 PClip は、 IClipオブジェクトの"smart pointer"であり、参照カウントを自動的にカウントアップダウンして 管理してくれます。最後のPClipを破棄する時点(参照カウントが0)でIClipオブジェクトを自動的に 削除してくれるので、管理を気にする必要がありません。 PClipは通常のポインタと同じく4バイトで、生成時には、値は0に初期化されます。 また値を他に受け渡すことも容易です。 でも再帰的にPClipを参照したり、アロケートしたメモリにPClipを置いてて、メモリを開放することを 忘れたりすることには気をつけましょう。 : GenericVideoFilter(_child) は、 初期化子でありGenericVideoFilterクラスのコンストラクタを呼び出しています。 初期化子はパラメタリストとコード本体の間にカンマで区切って列挙します。 メンバ変数への代入 foo = bar は、foo(bar)というように記述します。 初期化子は、コード本体より先に実行され、高速に処理されます。 なお、GenericVideoFilter(_child)では、 child(_child) { vi = child->GetVideoInfo(); } が実行されます。 |
Sample::~Sample() { } |
Sampleクラスのデストラクタです。 動的に獲得した領域の開放等の処理を記述します。 |
PVideoFrame __stdcall Sample::GetFrame(int n, IScriptEnvironment* env) { PVideoFrame src = child->GetFrame(n, env); env->MakeWritable(&src); return src; } |
フィルタのメイン部分です。 引数として、カレントフレームを示す n とスクリプト環境 env を伴ってコールバックされてきます。 復帰値としては PVideoFrame値を返します。 (これもPClipと同様、ref countを自動管理してくれます。) クラスのインスタンスは、一つのAVSをオープンする毎に作成され、それぞれ区別されます。 異なるインスタンスでは、envも別であるかも知れません。 PVideoFrame src = child->GetFrame(n, env); PClip childは、GenericVideoFilterクラスのコンストラクタで設定されていましたね。 protectedなメンバ変数なので継承クラスSampleからでも参照できます。 フレームNo. n のVideoFrameバッファを参照します。 もし必要なら別のフレームNo.のデータも参照できます。 他のフレームNo.を指定した場合、childでチェーンされている他フィルタも通ってきますが、 内蔵キャッシュが、キャッシュデータを渡してくる場合もあります。 env->MakeWritable(&src); srcで指定されたVideoFrameバッファへの変更(書き込み)を可能にします。 この時点でそのまま再利用可能で無い場合には新たなフレームバッファが生成されます。 つまりこの前後でデータポインタの挿すアドレスが変化する場合があるということに 気をつける必要があります。 デフォルトでは読み込みは許可ですが、書き込みは不可になっています。 in-place filter(再利用できる場合は元々のフレームバッファをそのまま書き換えて使用する) の場合に使用します。 なお、新たにVideoFrameを構築することもできます。 (画像の色空間や幅、高さを変える場合には必要になってきますが、詳細は後ほどします。) PVideoFrame dst = env->NewVideoFrame(vi); //--- この場合はデフォルトで書き込み可能になります。 return dst; VideoFrameは、バッファ内に自動的に作成され、PVideoFrameのref countが無くなった 時点で再利用されるので、意識してメモリをアロケートしたり開放したりする必要はありません。 なおNewVideoFrameで作成されたVideoFrameは初期化されてないので、そのままだとそのメモリ に入っている値となってしまいます。 (ゴミが表示されるという(私が出した)バグの原因になったりします。) const int pitch = src->GetPitch(); ラインピッチを求めています。 ここで注意すべき点として、各フレームでこのpitchは同じとは限らないということです。 つまり、最初に一度値を求めて保存したものを次回から使おうとするのはダメだということです。 (私が、以前 _2DCleanYUY2 で、これをやってしまい、メモリアクセスバイオレーションを 引き起こしたことがありました。) |
AVSValue __cdecl Create_Sample(AVSValue args, void* user_data, IScriptEnvironment* env) { return new Sample(args[0].AsClip(), env); } |
フィルタの入口関数になります。関数名は任意に付けられます。 引数として、パラメタ群argsと、オプショナルデータuser_data、環境envをとります。 new演算子で、Sampleクラスのインスタンスを生成しています。 復帰値は、そのインスタンスのコンストラクタによりAVSValue(IClip *)になります。 AVSValueは、Variant変数で以下の複数の型のどれかになります。 Bool型、Int型、Float型、String型、Clip型、それら型の配列、無(未定義) 型チェックには、 IsBool(),IsInt(),IsFloat(),IsString(),IsClip(),IsArray(),Defined() 型定義には、 AsBool(),AsInt(),AsFloat(),AsString(),AsClip(), ArraySize()または[]による配列 |
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) { env->AddFunction("Sample", "c", Create_Sample, 0); return "`Sample' Sample plugin"; } |
フィルタをAvisynth本体に登録します。 このDLLで、この関数がexportされることになります。 (DEFFILE等で明示的にexportする必要はありません。) 関数名は、AvisynthPluginInit2でなければなりません。※ 複数のAVSスクリプトがオープンされ、異なるenvで2度以上この関数が呼び出されるかも知れません。 (つまりグローバル変数にenvは保存してはいけないということです。) この関数はAddFunctionを呼びだして、フィルタリストにこのフィルタを登録することだけに しておきましょう。 復帰値として、プラグインの説明の文字列を返します。 特に明示しない場合、0(NULL strings)を返してもかまいません。 (実際、どういう場合にこの文字列が使われるのか判らないです。) ※ Avisynth 1.xや2.xでは、AvisynthPluginInitという名前でしたが、 Avisynth 2.5以降でインターフェースが変更されたため、関数名を変更して 1.x/2.xのavisynth.dllから2.5xのプラグインが呼ばれたり、その逆が起こらないようにしています。 env->AddFunction("Sample", "c", Create_Sample, 0); 第一パラメタは、登録するプラグイン名を指定します。 第二パラメタは、パラメタタイプ文字列を指定します。 第三パラメタは、フィルタの入口関数を指定します。 第四パラメタは、必要であれば入口関数に渡されるユーザデータCookieを指定します。 パラメタタイプ文字列は、AVSスクリプトで指定されるパラメタの型チェックをこれで行います。 "c" : Clip "b" : Bool "i" : Integer "f" : Float "s" : String "*" : 配列用 zero or more "+" : 配列用 one or more "." : 任意(引数1つに対して) "[string]" : 名前付け引数 【例】 "c[level]i[msg]s" --- 3つの引数をとる Sample(clip, level=int, msg="string") |
ビルド(make)のしかた 2004. 7. 7 (01版) |
---|
cd sample cl sample.cpp /LD |
でも、単一のソースファイルならこれでもいいですが、ソースファイルが2つ以上
になってくるととたんに大変になってきます。
そこで一連の手続きを記述して、ビルドを簡単に実行できるようにしましょう。
nmake.exeとmakefileを使います。
ソースファイルと同じフォルダに、makefileを作成しましょう。
---------------------------- f:\src\sample\makefile : start --------------------------- NAME = sample INDIR = . OUTDIR = ./release TARGET = $(NAME).dll INCLS = \ ../include/avisynth.h OBJS = \ "$(OUTDIR)/$(NAME).obj" RESFILE = DEFFILE = #----------------------- CC = cl LINK = link RC = rc ASM = ml LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib \ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib COPT = /c /W3 /G6 /GX /O2 /Oi /FAcs /Fa"$(OUTDIR)/" /arch:SSE \ /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fo"$(OUTDIR)/" LOPT = /DLL /nologo /OPT:NOWIN98 /SUBSYSTEM:WINDOWS /machine:I386 \ /implib:$*.lib /out:$@ ASMOPT = /c /coff /Fl"$(OUTDIR)/" /Sa /Fo"$(OUTDIR)/" RCOPT = /r /fo$(RESFILE) #----------------------- ALL:"$(OUTDIR)/$(TARGET)" "$(OUTDIR)/$(TARGET)": "$(OUTDIR)" $(OBJS) $(RESFILE) $(DEFFILE) $(LINK) $(LOPT) @<< $(OBJS) $(LIBS) $(RESFILE) << $(OBJS): $(INCLS) ###$(RESFILE): resource.h "$(OUTDIR)": if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" #----------------------- clean: # -@erase "$(OUTDIR)\$(TARGET)" -@erase "$(OUTDIR)\*.lib" -@erase "$(OUTDIR)\*.exp" -@erase "$(OUTDIR)\*.obj" -@erase "$(OUTDIR)\*.cod" 2>nul -@erase "$(OUTDIR)\*.lst" 2>nul -@erase "$(OUTDIR)\*.res" 2>nul #----------------------- .SUFFIX: .SUFFIX: .cpp .obj .rc .res .asm .c {$(INDIR)}.c{$(OUTDIR)}.obj:: $(CC) $(COPT) $< {$(INDIR)}.cpp{$(OUTDIR)}.obj:: $(CC) $(COPT) $< {$(INDIR)}.rc{$(OUTDIR)}.res:: $(RC) $(RCOPT) $< {$(INDIR)}.asm{$(OUTDIR)}.obj:: $(ASM) $(ASMOPT) $< ---------------------------- f:\src\sample\makefile : end --------------------------- |
>cd sample >nmake または >nmake all |
>nmake clean |
このフィルタを呼び出すAvisynthスクリプトは以下のようになります。
ただし、何もしないフィルタなので画像データに変化はありません。
LoadPlugin("f:\src\sample\release\sample.dll") AVISource("foo.avi") Sample() return last |
では、記述内容を少し説明します。
NAME = sample プロジェクト名を記述します。.dllの拡張子を取った名前です。 INDIR = . ソースファイル群のフォルダを指定ます。 OUTDIR = ./release 出力するフォルダを指定します。 \ は / と記述してもいいです。 . はカレントフォルダ、 .. は親フォルダ、 を意味し、相対パスで指定したい場合に使います。 なお、半角空白が含まれるフォルダ名でも""で括らずに そのまま記述してください。 【例】OUTDIR = G:\Program Files\bar baz TARGET = $(NAME).dll 作成するDLLの名前を指定します。 $(NAME)とは、マクロ NAMEの内容を参照するという意味です。 この場合、NAMEには"sample"が入っているので、 TARGET=sample.dllと同意です。 INCLS = \ ../include/avisynth.h ヘッダ(インクルード)ファイルを列挙します。 末尾の'\' は次行に続くことを指定します。 半角空白を含むファイル名は""で括ってください。 【例】独自のヘッダファイル foo.h bar.h baz.h の 3つを記述する場合は、 INCLS = ../include/avisynth.h foo.h bar.h baz.h と記述します。 ここで列挙したファイルは、OBJSで指定したファイルの 依存ファイルになります。 OBJS = \ "$(OUTDIR)/$(NAME).obj" オブジェクトファイルを列挙します。 オブジェクトとは、ソースファイルから作成される 中間ファイルのことです。 MS C++の場合、C++ソースからもASMソースからも、 .objが作成されます。 【例】foo.obj, bar.obj, baz.objと3つ記述する場合は、 OBJS = "$(OUTDIR)/foo.obj" "$(OUTDIR)/bar.obj" \ "$(OUTDIR)/baz.obj" と記述します。 RESFILE = リソースファイル(.res)を指定します。 .resは.rcソースファイルから生成されます。 【例】RESFILE = "$(OUTDIR)/sample.res" #----------------------- COPT = /c /W3 /G6 /GX /O2 /Oi /FAcs /Fa"$(OUTDIR)/" /arch:SSE \ /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fo"$(OUTDIR)/" これは、PIII CPU向けのコンパイルオプションです。 P4/Athlon向けにしたい場合は、 /G6 を /G7 に、/arch:SSE を /arch:SSE2 に変更してください。 なお、msvcrt.lib が提供されていないため、 /MD オプションは 付けないでください。 #-----------------------生成規則定義部 (左辺):(右辺) (左辺)は(右辺)に依存していることを示します。 ALL:"$(OUTDIR)/$(TARGET)" ターゲット(最終生成物)とその依存関係を指定します。 "$(OUTDIR)/$(TARGET)": "$(OUTDIR)" $(OBJS) $(RESFILE) $(DEFFILE) $(OBJS): $(INCLS) ファイルの依存関係です。 ここでは、全てのオブジェクトは、全てのインクルードファイル に依存しているようにしています。(無駄が多いですが) ファイルの依存関係は、 $(INDIR)/foo.cpp: $(INDIR)/bar.h $(INDIR)/baz.h $(INDIR)/baz.h: $(INDIR)/qux.h などのように正確に列挙してもよいです。 #-----------------------サフィックスルール(推測規則) .SUFFIX: 暗黙のルールをクリア .SUFFIX: .cpp .obj .rc .res .asm .c ルールを適用する拡張子を列挙します。 {$(INDIR)}.cpp{$(OUTDIR)}.obj:: .cpp.obj: は、cpp → obj の暗黙の生成規則を指定します。 $(CC) $(COPT) $< .cpp.obj::は、コマンドプロンプトからプロセスを 毎回起動しないようにします。 #----------------------- nmakeで使えるマクロは、 $(name) nameの内容を展開します。 $@ 生成コマンドの左辺に展開されます。 foo.obj:bar.cpp ならば、 $@は、foo.objになります。 $* 生成コマンドの左辺の拡張子を除いたものに展開されます。 foo.obj:bar.cpp ならば、 $*は、fooになります。 $? 生成コマンドの右辺の更新されたものの一つに展開されます。 foo.obj:bar.cpp baz.cpp,qux.cpp, quux.cpp で、bar.cppとbaz.cppを更新した場合は、 $?は bar.cpp か baz.cpp かになります。 $< 推測ルールで使用され、依存しているファイル(右辺)の一つに展開されます。 なお、$(foo/*/bar&baz)などは使えないようです。 #-----------------------
デバッグ(debug)のしかた 2004. 7.14 (02版) |
---|
2004. 7.11 (01版) |
nmake >result.txt または nmake 1>result.txt |
nmake >>result.txt |
nmake 1>result.txt 2>result2.txt nmake 1>result.txt 2>&1 |
では、実際に見てみましょう。
例えば、sample.cppで、
dstp = src->GetWritePtr();
と書くべきところを、
dstp = src->GetWritePt();
と書いてしまいました。
nmakeしたところ
テキストエディタで result.txt を開いたところ
result.txtのエラー表示行(sample.cpp(27) : )で、タグジャンプしたところ
次に、コンパイルエラーは無くなったけれど、思ったような結果にならなかった場合など
逐次実行時点の変数の値などを確認したい場合が出てきます。
これには、デバッグメーセージ出力が使えます。
この方法は非常に原始的ですが、有効な手段です。
なお、デバッグメッセージへの出力は、DebugViewで見ることができます。
#include <stdio.h> PVideoFrame __stdcall Sample::GetFrame(int n, IScriptEnvironment* env) { //*** in-place filtering *** PVideoFrame src = child->GetFrame(n, env); const BYTE* srcp0 = src->GetReadPtr(); BYTE* dstp0 = src->GetWritePtr(); env->MakeWritable(&src); const int pitch = src->GetPitch(); const int rowsize = src->GetRowSize(); const int height = src->GetHeight(); const int modulo = pitch - src->GetRowSize(); const BYTE* srcp = src->GetReadPtr(); BYTE* dstp = src->GetWritePtr(); { char msg[256]; sprintf(msg, "\nframe=%d --- rowsize=%d height=%d dstp=%08x\n", n, rowsize, height, dstp); OutputDebugString(msg); } return src; } |
参考文献 及び 使用ソフト一覧 |
---|