Video For WindowsのAPIについて
余りに有益なので手元に置きたいので、
岩本一樹氏のホームページからの転載です。
最新版(2.0)はこちら
サンプルはVFWAPI20.LZH Video for Windows AVI API 解説 2.0。
繰り返しますが、私はこれを参考にコマいソフトをつくった&転載してるだけで、これは私が書いたものではありません。
私はVFWを氏のように深く理解した訳ではなく、このサンプルの改造程度しか行っていません。なので、私に質問メールを送られてもまずお役に立てません。その辺よろしく。
Video for WindowsのAPIについて(第1版 1999年1月4日)
Windowsの普及でAVIファイルは標準的なフォーマットになりました。ビデ
オキャプチャーボードも普及してきていて、科学的実験や解析に動画を用いたいという
要求は決して少なくはないと思います。そしてそれらの結果をAVIファイルで示した
いという要求もあると思います。
ここでは、WindowsでVideo for Windows(以下VFW)の
APIを用いてAVIファイルを扱う方法を説明します。
第0章 序文
*利用条件
この文書およびサンプルは無償で利用できます。この文書およびサンプルによって生
じたいかなる問題も岩本一樹は補償しません。またこの文書およびサンプルの内容も保
証しません。
*再配布/転載について
営利/非営利を問わず配布できます。改変して配布することもできます。
*付属のサンプルについて
サンプルを改変したり別のプログラムに流用するなど、営利/非営利を問わず利用で
きます。
*著作権
この文書およびサンプルプログラムなどの著作権は岩本一樹に属します。
第1章 AVIの基礎
*ファイルの構造
AVIとはAudio Video Interleaveの略です。AVIファイルはその名の通りオーデ
ィオ(音声)とビデオ(映像)を併せ持つことができるファイル形式です。
その形式はAVIファイルはRIFF(Resource Interchange File Format)形式に
なっています。RIFF形式は様々なリソース(データ)を1つのファイルにするため
のファイルの形式で、将来、新しい形式のリソースが考案されても互換が保たれる構造
になっています。実はWAVEファイルもRIFF形式になっており、VFWのAPI
を用いればWAVEファイルをビデオが無いオーディオのみのAVIファイルとして扱
うことができます。
AVIファイルはストリームという単位に別れています。LZHなどのアーカイブさ
れた1つのファイルの中にいくつかのファイルが存在するように、AVIファイルの中
にはストリームが1つ以上存在します。現在、ストリームは下記の4種類が定義されて
います。
オーディオストリーム
MIDIストリーム
テキストストリーム
ビデオストリーム
また理論上は同じ種類のストリームを複数含めることができます。複数のオーディオ
ストリームを用いて複数の言語で再生したり、複数のビデオストリームを用いて違う視
点(カメラ)から撮影した映像を同時に再生するなどが考えられます。しかし残念なが
ら現在では下記の構成しかありません。
オーディオストリームが1つ(WAVEファイル)
ビデオストリームが1つ
オーディオストリームが1つとビデオストリームが1つ
オーディオストリームの実体はWAVEファイルそのもので、ビデオストリームは連
続するビットマップの集まりです。ご存知かと思いますが、映像は連続する画像の集ま
りです。(教科書のすみに描いたパラパラ漫画を思い出して下さい。それと同じ原理で
す。)AVIファイルではその画像がWindowsプログラマが慣れ親しんだビット
マップになっているのです。
このビットマップは実際には圧縮されている場合がほとんどです。「圧縮」と言って
もビットマップファイルでおなじみのRLE8やRLE4ではありません。Cinepakや
IndeoなどのAVIファイル専用のフォーマットで圧縮されています。このAVIに含
まれるビットマップの圧縮/展開を行うドライバは追加/削除が可能になっており、新
しいフォーマットが開発された場合にはドライバを追加するだけで対応できるようにな
ります。
VFWのAPIを使う限りでは圧縮形式を気にする必要はありません。API側で適
切な圧縮/展開ドライバを自動的に呼び出します。
*VFWの位置づけ
AVIファイルを扱う方法はVFW以外にもあります。最も高レベルなものから順に
列挙すると
MCIWND
MCI
VFW
ACM VCM mmio
汎用的なファイル入出力
があります。MCIはもうお馴染みのだと思いますが、一応簡単に説明します。MCI
はMedia Control Interfaceの略で、AVIファイル、WAVEファイル、MIDIフ
ァイル、CDなどのメディアを「再生」、「停止」などというような抽象的な概念で扱
うことができます。ゆえにMCIを利用すればAVIファイルの再生は容易です。MC
IWNDはウインドウの作成、管理まで行うことができるます。これによりアプリケー
ションはMCIよりもさらに容易にAVIファイルを再生できます。
反面、MCIはAVIファイルからビットマップを取り出す、ビットマップファイル
からAVIファイルを作る、AVIファイルを再圧縮する、AVIファイルを編集する
などの目的には不向きです。
ACM(Audio Compression Manager)とVCM(Video Compression Manager)は
それぞれオーディオ/ビデオの圧縮/展開を行うドライバを直接扱うことができます。
これらをアプリケーションから呼び出す場合、オーディオやビデオのデータはRIFF
形式のファイルである必要もなく、かなり柔軟にデータを扱えます。しかしこの方法で
はファイルの読み込み/書き出し、メモリの確保などはアプリケーションの責任です。
その手続きの多さはMCIの比ではありません。
mmioはRIFF形式のファイルへのアクセスを助けます。ACMやVCMを利用
する場合にはmmioを使うことになると思います。
そして最も低レベルな手段は汎用的なファイル入出力を用いる方法です。ANSI−
Cで定義されたfopenなどを使えばOSをWindowsに限定しないプログラムが組
めます。しかしこの方法ではWindows用に供給される圧縮/展開のドライバが使
えません。今後、新しい圧縮形式が発表されないなどということはありません。それら
に独自で対応するのは事実上不可能です。この場合は結局、未圧縮のAVIファイルに
限定するなどということになると思いますが、それでもかなり困難な手段と言えます。
VFWはACM、VCM、mmioを制御し、AVIファイルがRIFF形式である
ことを意識することなく扱えるようになり、圧縮/展開のドライバ選択などを容易にし
ます。しかしVFWにはAVIファイルを再生する機能はありません。VFWはACM
とVCM、mmioよりも上でMCI下に位置していると考えられます。
なお、ここでいう高レベル/低レベル、上/下などという言い方は優劣を言うのでは
ありません。高レベルなものは低レベルなものを利用しているということです。高レベ
ルな方法で十分ならば、高レベルな方法を選択する方が賢明です。しかし高レベルな方
法で実現できない場合というのもあるので、その時には低レベルな方法を使うべきなの
です。
第2章 AVIファイルからビットマップを取り出す
*AVIファイルからビットマップを取り出す
AVIファイルからビットマップを取り出すプログラムは下記のようになります。
TEST01.C-----------------------------------------------------------------------
#include <stdio.h>
#include <windows.h>
#include <vfw.h>
int bmpsave(const char *fname,LPBITMAPINFOHEADER pbmih)
{
int s,x,y;
BITMAPFILEHEADER bmfh;
FILE *fp;
x=pbmih->biWidth;
y=abs(pbmih->biHeight);
bmfh.bfType=0x4d42;
bmfh.bfReserved1=bmfh.bfReserved2=0;
if (pbmih->biClrUsed==0)
switch (pbmih->biBitCount) {
case 1:bmfh.bfOffBits=8;break;
case 4:bmfh.bfOffBits=64;break;
case 8:bmfh.bfOffBits=1024;break;
case 24:bmfh.bfOffBits=0;break;
case 16:
case 32:bmfh.bfOffBits=pbmih->biCompression==BI_RGB?12:0;
}
else
bmfh.bfOffBits=pbmih->biClrUsed*4;
bmfh.bfOffBits+=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
if (pbmih->biSizeImage==0) {
switch (pbmih->biBitCount) {
case 1:s=(x+7)/8;break;
case 4:s=(x+1)/2;break;
case 8:s=x;break;
case 16:s=x*2;break;
case 24:s=x*3;break;
case 32:s=x*4;
}
bmfh.bfSize=bmfh.bfOffBits+(s+3)/4*4*y;
} else {
bmfh.bfSize=bmfh.bfOffBits+pbmih->biSizeImage;
}
if ((fp=fopen(fname,"wb"))==NULL)
return -1;
if (fwrite(&bmfh,sizeof(BITMAPFILEHEADER),1,fp)!=1
|| fwrite(pbmih,bmfh.bfSize-sizeof(BITMAPFILEHEADER),1,fp)!=1)
return -1;
return fclose(fp);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
LPBITMAPINFOHEADER pbmih;
PAVIFILE pavi;
PAVISTREAM pstm;
PGETFRAME pfrm;
AVIFileInit();
if (AVIFileOpen(&pavi,"TEST.AVI",OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIFileGetStream(pavi,&pstm,0,0)!=0)
return 0;
if ((pfrm=AVIStreamGetFrameOpen(pstm,NULL))==NULL)
return 0;
if ((pbmih=AVIStreamGetFrame(pfrm,0))==NULL)
return 0;
if (bmpsave("TEST00.BMP",pbmih)!=0)
return 0;
if (AVIStreamGetFrameClose(pfrm)!=0)
return 0;
AVIStreamRelease(pstm);
AVIFileRelease(pavi);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
AVIFileInitはVFWのライブラリを初期化します。VFWの機能を利用するアプリ
ケーションは起動された時に必ずこのAPIを1回呼び出します。またこのAPIを呼
び出したアプリケーションは必ず終了する時にAVIFileExitを呼ばなければなりません。
さらに今度はAVIFileOpenでファイル名を指定してAVIファイルを開きます。
PAVIFILEはfopenのFILE構造体のようなものです。今後はAVIファイルへのアクセス
はこれを用います。szFileはファイル名を示す'\0'で終わる文字列へのポインタです。
pclsidhandlerにはNULLを指定します。NULLを指定するとレジストリに登録されている
情報を元にファイルを開きます。なお、オープンしたファイルはクローズしなければな
りません。ファイルを閉じるにはAVIFileReleaseを呼び出します。引数はAVIFileOpen
で取得したファイルインターフェイスポインタだけです。
しかしファイルを開いただけではAVIファイルに含まれるビットマップを取り出す
ことはできません。ファイルの中にあるストリームを開かなくてはならないのです。ス
トリームを開くためにはAVIFileGetStreamを用います。ファイルと同様に開いたストリ
ームは閉じなくてはなりません。ストリームを閉じるAPIはAVIStreamReleaseです。
AVIファイルに含まれるビットマップは圧縮されています。このビットマップを適
切な展開ドライバで無圧縮のビットマップに展開するためにはAVIStreamGetFrameOpen
でGetFrameオブジェクトを取得しなければなりません。このAPIの引数はストリーム
インターフェイスポインタとBITMAPINFOHEADER構造体へのポインタです。AVIファイ
ルがどの様な形式で圧縮されているかをVFWを利用するプログラマが心配する必要は
ありません。VFW側で適切な展開ドライバが選択されます。BITMAPINFOHEADERへのポ
インタはNULLまたはAVIGETFRAMEF_BESTDISPLAYFMTを指定します。APIの仕様上は
BITMAPINFOHEADER構造体を指定して目的のサイズ、解像度のビットマップが取得できる
ように思えます。しかし実際はBITMAPINFOHEADER構造体を指定してもNULLが返されこの
APIは失敗します。指定されたサイズ、解像度のビットマップを取得できる展開ドラ
イバが存在するかも知れませんが、現時点ではそのような親切な機能は実装されていな
いドライバが大半です。ですからビットマップのサイズや解像度の変更は別に作成する
必要があります。
これでようやくGetFrameオブジェクトを利用してビットマップを取得します。ビット
マップを取得するAPIはAVIStreamGetFrameです。パックDIBへのポインタが返さ
れます。AVIStreamGetFrameOpenでBITMAPINFOHEADER構造体を指定しGetFrameオブジェ
クトを取得しない限り、このAPIで取得できるビットマップのフォーマットはあらゆ
る場合が考えられます。極端な話、1×1のモノクロのビットマップが返される可能性
もありますし、1024×768で32ビットという可能性もあります。しかし現実に
は解像度は24ビット(フルカラー)の場合がほとんどです。
もちろんGetFrameオブジェクトも閉じる必要があります。GetFrameオブジェクトを閉
じるAPIはAVIStreamGetFrameCloseです。
AVIファイルからビットマップを取り出すためにはこの幾重にも重なるの開く/閉
じるを理解しなければなりません。ファイルの中にストリームがあるということを考え
ればこの様な構造は必然ですが、最初は戸惑うかも知れませんが慣れるしかありません。
さて先に述べたようにAVIファイルには複数のストリームを含めることができます。
現在は実際には存在しませんがビデオストリームが2つ以上含まれるAVIファイルも
ありえます。これに対応するためにはAVIFileGetStreamのfccTypeとlParamを利用しま
す。
fccTypeにはストリームの種類を、lParamはストリームタイプのカウントです。この
値は0から始まります。「ではlParamの最大値は?」という疑問がすぐに湧くと思いま
す。0から始めてエラーになるまでAVIFileGetStreamを呼び出す方法もありますが、も
っとスマートな方法があります。それはAVIFileInfoを呼び出してAVIFILEINFO構造体に
ファイルの情報を取得する方法です。AVIFILEINFO構造体のdwStreamsはファイルに含ま
れるストリーム数です。これを利用すると下記のようになります。
TEST02.C-----------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
char fname[MAX_PATH];
AVIFILEINFO fi;
AVISTREAMINFO si;
DWORD stm;
LONG i,st,ed;
LPBITMAPINFOHEADER pbmih;
PAVIFILE pavi;
PAVISTREAM pstm=NULL,ptmp;
PGETFRAME pfrm;
WORD video;
AVIFileInit();
if (AVIFileOpen(&pavi,"TEST.AVI",OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIFileInfo(pavi,&fi,sizeof(AVIFILEINFO))!=0)
return 0;
for (stm=0;stm<fi.dwStreams;stm++) {
if (AVIFileGetStream(pavi,&ptmp,0,stm)!=0)
return 0;
if (AVIStreamInfo(ptmp,&si,sizeof(AVISTREAMINFO))!=0)
return 0;
switch (si.fccType) {
case streamtypeVIDEO:
if (pstm==NULL || si.wPriority<video) {
if (pstm!=NULL)
AVIStreamRelease(pstm);
pstm=ptmp;
video=si.wPriority;
}
continue;
}
AVIStreamRelease(ptmp);
}
if (pstm==NULL)
return 0;
if ((pfrm=AVIStreamGetFrameOpen(pstm,NULL))==NULL)
return 0;
st=AVIStreamStart(pstm);
ed=AVIStreamLength(pstm)+st;
for (i=st;i<ed;i++) {
if ((pbmih=AVIStreamGetFrame(pfrm,i))==NULL)
return 0;
wsprintf(fname,"TEST%02d.BMP",i);
if (bmpsave(fname,pbmih)!=0)
return 0;
}
if (AVIStreamGetFrameClose(pfrm)!=0)
return 0;
AVIStreamRelease(pstm);
AVIFileRelease(pavi);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
上記のプログラムではfor文を使いすべてのストリームを開いています。
AVISTREAMINFO構造体のwPriorityの値が小さいストリームほど優先順位が高いストリー
ムです。上記のプログラムでは一番優先順位が高いビデオストリームを開いています。
またAVISTREAMINFO構造体のwLanguageを用いて現在のユーザーの言語に合うストリーム
を開く方法もあります。switch文の分岐を増やせばオーディオストリームを同時に開く
こともできます。
しかし実際にはこんなに複雑なことをする必要はありません。なぜならば今のところ
はAVIファイルのストリームの構成は先に述べた3種類しかないためです。
また、AVIStreamOpenFromFileはAVIFileOpen、AVIFileGetStream、AVIFileReleaseを
呼び出し、ファイル名からストリームを開くことができます。ファイルの中の特定の種
類のストリームを1つだけ開くような場合はこのAPIが有効です。
*サンプルとフレーム、時間
上記の例ではAVIStreamGetFrameの引数にAVIStreamStartの戻り値を渡しています。
AVIStreamStartはビデオストリームの先頭のサンプル番号を返します。通常は0です。
この“サンプル”というのは、ストリームのデータ単位です。ビデオストリームの場合、
1サンプルは1フレーム(1枚のビットマップ)です。
AVIStreamStartの値が0でない場合、再生ソフトはそのサンプル数分だけビデオスト
リームの再生を遅らせなければなりません。例えば秒間30フレームのAVIファイル
でAVIStreamStartの値が60の場合、ビデオストリームは2秒遅れて再生を開始します。
AVIStreamGetFrameに渡す値の最小値はAVIStreamStartの戻り値になります。ちなみに
サンプル番号の最大値はAVIStreamStartとAVIStreamLengthの返す値の合計値−1です。
サンプルと時間の対応はAVIStreamSampleToTimeとAVIStreamTimeToSampleで求められ
ます。しかしこれらはAVISTREAMINFOのメンバーから求めることもできます。
「dwRate÷dwScale」で1秒あたりのサンプル数が求められます。dwScale=1、
dwRate=15の場合、秒間15フレームということになります。注意しなければならない
のはこれらの値はさまざまであるということです。うっかりすると桁あふれや丸め誤差
で実際とは異なる値になってしまうことがあります。秒間30フレームであることをあ
らわすのにdwScale=33333、dwRate=1000000という場合もあればdwScale=1、dwRate=30
という場合もあります。またAVIStreamStartの戻り値はdwStartであり、
AVIStreamLengthの戻り値はdwLengthです。最後のサンプルは「dwLength−dwStart−1」
で計算できます。
独自にサンプルと時間の対応を計算するメリットは、実際には存在しない時間からサ
ンプル番号を求めることができることです。AVIStreanTimeToSampleでAVIファイル
の実際の再生時間を超える値を指定すると最後のサンプル番号を返してしまいます。
オーディオストリームを扱う時には1サンプル当たりのバイト数に気を配る必要があ
ります。オーディオストリームの圧縮形式がPCMで8ビットのモノラルの時、1サン
プルは1バイトです。160×120のビットマップが約56kバイトです。同じ1サ
ンプルでもそのバイト数は大きく異なります。また同じ時間(長さ)のストリームでも
含まれるサンプル数はビデオストリームとオーディオストリームでは大きく異なります。
22050kHzのPCMは1秒間のサンプル数が22050サンプルになりますが、
秒間30フレームのビデオストリームは1秒間に30サンプルです。
*キーフレーム
フレームの中にはキーフレームと呼ばれる特別なフレームが存在します。このキーフ
レームは他のフレームに依存しないフレームのことです。
フレームが圧縮されている場合、フォーマットによっては前のフレームとの差分をと
ることでデータサイズの縮小を図っています。この場合、前のフレームとの違う部分だ
けが、そのフレームの圧縮されたデータとして存在します。ゆえにこのフレームを未圧
縮のビットマップに展開するためには前のフレームの情報も必要になります。
キーフレームとは他のフレームの情報を必要としない独立したフレームのことです。
フォーマットによってはすべてのフレームがキーフレームになります。未圧縮のAVI
ファイルはすべてのフレームがキーフレームです。
キーフレームは圧縮に関する情報であり、キーフレームが映像のシーンの切れ目(カ
ット点)となるわけではありません。キーフレームあっても前のフレームと見た目がほ
とんど同じ場合もありますし、キーフレームでなくてもそのフレームから別の映像に変
化する場合もあります。
第3章 AVIファイルを作る
*ビットマップからAVIファイルを作る
ビットマップからAVIファイルを作るプログラムは下記のようになります。
TEST03.C-----------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <vfw.h>
#define LENG 10
#define WIDTH 160
#define HEIGHT 120
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
char fname[MAX_PATH];
int i,s,fsize;
AVISTREAMINFO si={streamtypeVIDEO,mmioFOURCC('D','I','B',' '),
0,0,0,0,1,30,0,LENG,0,0,(DWORD)-1,0,{0,0,WIDTH,HEIGHT},0,0,"ビデオ"};
FILE *fp;
LPBITMAPINFOHEADER pbmih=NULL;
PAVIFILE pavi;
PAVISTREAM pstm;
AVIFileInit();
if (AVIFileOpen(&pavi,"TEST01.AVI",
OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIFileCreateStream(pavi,&pstm,&si)!=0)
return 0;
for (i=0;i<LENG;i++) {
wsprintf(fname,"TEST%02d.BMP",i);
if ((fp=fopen(fname,"rb"))==NULL)
return 0;
if (fseek(fp,0,SEEK_END)!=0)
return 0;
if ((fsize=ftell(fp))==-1)
return 0;
if (fseek(fp,sizeof(BITMAPFILEHEADER),SEEK_SET)!=0)
return 0;
fsize-=sizeof(BITMAPFILEHEADER);
pbmih=realloc(pbmih,fsize);
if (fread(pbmih,fsize,1,fp)!=1)
return 0;
fclose(fp);
if (pbmih->biClrUsed==0)
switch (pbmih->biBitCount) {
case 1:s=8; break;
case 4:s=64; break;
case 8:s=1024; break;
case 24:s=0; break;
case 16:
case 32:s=pbmih->biCompression==BI_RGB?12:0;break;
default:return 0;
}
else
s=pbmih->biClrUsed*4;
s+=sizeof(BITMAPINFOHEADER);
if (AVIStreamSetFormat(pstm,i,pbmih,s)!=0)
return 0;
if (AVIStreamWrite(pstm,i,1,(LPBYTE)pbmih+s,
fsize-s,AVIIF_KEYFRAME,NULL,NULL)!=0)
return 0;
}
AVIStreamRelease(pstm);
AVIFileRelease(pavi);
AVIFileExit();
if (pbmih!=NULL)
free(pbmih);
return 0;
}
-------------------------------------------------------------------------------
上記のプログラムではAVICreateStreamで新規にストリームを作り、そこに未圧縮の
ビットマップを書き込んでいます。AVICreateStreamの引数のAVISTREAMINFO構造体の
dwLengthにはビットマップの枚数を指定します。通常はrcFrameにはビットマップの幅
と高さを指定します。rcFrameの値を設定することでビットマップの一部だけを表示し
て再生させることもできます。
AVIStreamSetFormatではBITMAPINFOHEADER構造体とパレットを書き込みます。パレッ
トが存在しない場合にはBITMAPINFOHEADER構造体だけを書き込みます。パレットが存在
する場合、BITMAPINFOHEADER構造体と一緒にパレットも書き込みます。
残りのビットマップの本体はAVIStreamWriteで書き込みます。無圧縮のビットマップ
はすべてのフレームがキーフレームになります。AVIStreamWriteの引数で
AVIIF_KEYFRAMEを指定して下さい。
上記の方法で使用できないビットマップは
・RLE8/RLE4で圧縮されている
・16ビットのビットマップ
です。その他のビットマップからならばAVIファイルを作ることは可能で、白黒や1
6色のAVIファイルも作ることができるということです。
*AVIファイルからAVIファイルを作る
AVIファイルのストリームを別のフォーマットで圧縮したり、ビデオストリームと
オーディオストリーム(WAVEファイル)を合わせて1つのAVIファイルを作るな
どさまざまな要求があると思います。
上記の方法を使えば、AVIファイルのビットマップからAVIファイルを作ること
もできます。しかし新しいAVIファイルは未圧縮になってしまいますし、オーディオ
ストリームには対応できません。ストリームをそのまま読み込むには
AVIStreamReadFormatとAVIStreamReadを使います。
下記のプログラムはAVIファイルのビデオストリームとWAVEファイルを1つの
AVIファイルにします。
TEST04.C-----------------------------------------------------------------------
#include <stdlib.h>
#include <windows.h>
#include <vfw.h>
#define WAVBUFFER 4096
int CopyStream(PAVIFILE pavi,PAVISTREAM pstm)
{
AVISTREAMINFO si;
LONG i,st,ed,leng,sample;
LPVOID p;
PAVISTREAM ptmp;
st=AVIStreamStart(pstm);
ed=st+AVIStreamLength(pstm)-1;
if (AVIStreamInfo(pstm,&si,sizeof(AVISTREAMINFO))!=0)
return -1;
if (AVIFileCreateStream(pavi,&ptmp,&si)!=0)
return -1;
if (AVIStreamReadFormat(pstm,st,NULL,&leng)!=0)
return -1;
if ((p=malloc(leng))==NULL)
return -1;
if (AVIStreamReadFormat(pstm,st,p,&leng)!=0)
return -1;
if (AVIStreamSetFormat(ptmp,st,p,leng)!=0)
return -1;
for (i=st;i<=ed;i+=sample) {
if (AVIStreamRead(pstm,i,
AVISTREAMREAD_CONVENIENT,NULL,0,&leng,&sample)!=0)
return -1;
if ((leng<=0 || sample<=0)
&& AVIStreamRead(pstm,i,WAVBUFFER,NULL,0,&leng,&sample)!=0)
return -1;
if ((p=realloc(p,leng))==NULL)
return -1;
if (AVIStreamRead(pstm,i,sample,p,leng,NULL,&sample)!=0)
return -1;
if (AVIStreamWrite(ptmp,i,sample,p,leng,AVIIF_KEYFRAME,NULL,NULL)!=0)
return -1;
}
AVIStreamRelease(ptmp);
free(p);
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
PAVIFILE pavi;
PAVISTREAM pstm;
AVIFileInit();
if (AVIFileOpen(&pavi,"TESTX.AVI",
OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIStreamOpenFromFile(&pstm,"TEST.AVI",streamtypeVIDEO,0,
OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (CopyStream(pavi,pstm)!=0)
return 0;
AVIStreamRelease(pstm);
if (AVIStreamOpenFromFile(&pstm,"TEST.WAV",streamtypeAUDIO,0,
OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (CopyStream(pavi,pstm)!=0)
return 0;
AVIStreamRelease(pstm);
AVIFileRelease(pavi);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
CopyStreamは引数で指定されたファイルに引数で指定されたストリームをコピーしま
す。まずコピー元のストリームの情報を使ってファイルに新しいストリームを作ります。
次にコピー元のストリームのフォーマットを読み込みます。
AVIStreamReadFormatには2つの機能があります。1つはフォーマットを読み込むこ
とですが、もう1つはフォーマットのバイト数を取得する機能です。
AVIStreamReadFormatでフォーマットのバイト数を求めないで固定長のバッファに読み
込むのは危険です。フォーマットのバイト数は可変です。
その後で、ストリームのデータを書き込みます。ここで使われるのがAVIStreamRead
です。このAPIもAVIStreamReadFormatと同様に2つの機能があります。引数の
lpBufferにNULLを指定して呼び出すとplBytesとplSamplesに値を返します。この値に基
づいてバッファを確保し、データを読み込みます。lSampleに
AVISTREAMREAD_CONVENIENTを指定すると適当なサンプル数が取得できます。ただしWA
VEファイルではAVISTREAMREAD_CONVENIENTで適当なサンプル数が求められずに0が返
されます。そのため返された値をチェックして0の場合はlSampleに適当な値を入れて
再度AVIStreamReadを呼び出します。
これを応用して逆の動作(AVIファイルからビデオストリームとオーディオストリ
ームを取り出す)の例は下記のようになります。
TEST05.C-----------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
int i;
PAVIFILE pavi;
PAVISTREAM pstm[2];
AVIFileInit();
if (AVIFileOpen(&pavi,"TESTX.AVI",OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIFileGetStream(pavi,&pstm[0],streamtypeVIDEO,0)!=0)
return 0;
if (AVIFileGetStream(pavi,&pstm[1],streamtypeAUDIO,0)!=0)
return 0;
AVIFileRelease(pavi);
if (AVIFileOpen(&pavi,"TEST.AVI",
OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (CopyStream(pavi,pstm[0])!=0)
return 0;
AVIFileRelease(pavi);
if (AVIFileOpen(&pavi,"TEST.WAV",
OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (CopyStream(pavi,pstm[1])!=0)
return 0;
AVIFileRelease(pavi);
for (i=0;i<2;i++)
AVIStreamRelease(pstm[i]);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
*圧縮フォーマットを変更する
今までの例ではストリームの圧縮形式を自由に変更できませんでした。しかし僅かな
改良で圧縮形式を選択できるようになります。AVIMakeCompressedStream、
AVISaveOptions、AVISaveOptionsFreeの3つのAPIを加えるだけです。
AVISaveOptionsはダイアログボックスを表示してユーザーが圧縮形式を選択できるよ
うにします。選択された値はAVICOMPRESSOPTIONS構造体に返されます。
AVISaveOptionsを使用せずにAVICOMPRESSOPTIONS構造体のメンバを直接設定して
AVIMakeCompressedStreamを呼び出すこともできます。しかしビデオストリームやオー
ディオストリームをの圧縮するドライバは、ユーザーが追加/削除することができます
(コントロールパネルのマルチメディアの詳細設定を参照)。そのため
AVICOMPRESSOPTIONS構造体をプログラムで固定的に設定してしまうと、ドライバがイン
ストールされていない場合に対応できなくなってしまいます。
TEST06.C-----------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
int i,s=0;
AVICOMPRESSOPTIONS opt[2];
LPAVICOMPRESSOPTIONS popt[2];
PAVIFILE pavi;
PAVISTREAM pstm[2],ptmp;
AVIFileInit();
if (AVIFileOpen(&pavi,"TESTX.AVI",OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIFileGetStream(pavi,&pstm[s],streamtypeVIDEO,0)==0)
s++;
if (AVIFileGetStream(pavi,&pstm[s],streamtypeAUDIO,0)==0)
s++;
AVIFileRelease(pavi);
if (s<=0)
return 0;
for (i=0;i<s;i++) {
popt[i]=&opt[i];
memset(popt[i],0,sizeof(AVICOMPRESSOPTIONS));
}
if (AVISaveOptions(NULL,
ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_PREVIEW,
s,pstm,popt)) {
if (AVIFileOpen(&pavi,"TESTX_.AVI",
OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
for (i=0;i<s;i++) {
if (AVIMakeCompressedStream(&ptmp,pstm[i],popt[i],NULL)!=AVIERR_OK)
return 0;
if (CopyStream(pavi,ptmp)!=0)
return 0;
AVIStreamRelease(ptmp);
}
AVIFileRelease(pavi);
}
AVISaveOptionsFree(s,popt);
for (i=0;i<s;i++)
AVIStreamRelease(pstm[i]);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
*AVISaveまたはAVISaveVを使う
AVISaveまたはAVISaveVを利用するとファイルへの保存を簡潔に行うことができます。
AVISaveとAVISaveVはコールバック関数を利用できます。コールバック関数でAVIERR_OK
を返すと処理を継続します。AVIERR_USERABORTを返すと処理を中断します。コールバッ
ク関数の戻り値はAVISaveまたはAVISaveVの戻り値になります。
下記はAVISaveVを利用した例です。下記の例ではダイアログボックスを表示してユー
ザーが処理を中断できるようにしています。
TEST07.C-----------------------------------------------------------------------
#include <string.h>
#include <windows.h>
#include <vfw.h>
#include "resource.h"
HWND hdlg;
LONG userbreak=AVIERR_OK;
LONG FAR PASCAL SaveCallback(int nPercent)
{
SetDlgItemInt(hDlg,IDC_EDIT,nPercent,TRUE);
return userbreak;
}
BOOL CALLBACK AbortDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg) {
case WM_INITDIALOG:
{
RECT rc;
GetWindowRect(hDlg,&rc);
SetWindowPos(hDlg,0,
(GetSystemMetrics(SM_CXSCREEN)-rc.right+rc.left)/2,
(GetSystemMetrics(SM_CYSCREEN)-rc.bottom+rc.top)/2,
0,0,SWP_NOSIZE | SWP_NOZORDER);
}
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam)==IDCANCEL)
userbreak=AVIERR_USERABORT;
return TRUE;
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
int i,s=0;
AVICOMPRESSOPTIONS opt[2];
LPAVICOMPRESSOPTIONS popt[2];
PAVIFILE pavi;
PAVISTREAM pstm[2];
AVIFileInit();
if (AVIFileOpen(&pavi,"TESTX.AVI",OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIFileGetStream(pavi,&pstm[s],streamtypeVIDEO,0)==0)
s++;
if (AVIFileGetStream(pavi,&pstm[s],streamtypeAUDIO,0)==0)
s++;
AVIFileRelease(pavi);
if (s<=0)
return 0;
for (i=0;i<s;i++) {
popt[i]=&opt[i];
memset(popt[i],0,sizeof(AVICOMPRESSOPTIONS));
}
if (AVISaveOptions(NULL,
ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_PREVIEW,
s,pstm,popt)) {
if ((hdlg=CreateDialogParam(hInstance,MAKEINTRESOURCE(DIALOG_1),
NULL,AbortDlgProc,0))==NULL)
return 0;
if (AVISaveV("TESTX_.AVI",NULL,SaveCallback,s,pstm,popt)!=AVIERR_OK)
return 0;
DestroyWindow(hdlg);
}
AVISaveOptionsFree(s,popt);
for (i=0;i<s;i++)
AVIStreamRelease(pstm[i]);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
第3章 その他
*AVIファイルを編集する
AVIStreamReadとAVIStreamWriteを使うことでAVIファイルのフレームの順番を入
れ替えたり、一部のフレームを取り出すことができるように思えます。しかし圧縮形式
によっては、キーフレームとキーフレームではないフレームが存在します。キーフレー
ムではないフレームは前のフレームに依存します。よってキーフレームではないフレー
ムだけを取り出したり、順番を変えると正しく表示されない場合があります。
そこでAVIファイルを編集するために「編集ストリーム」を利用します。編集スト
リームインターフェイスポインタは通常のストリームインターフェイスポインタを元に
してCreateEditableStreamで作ることができます。またCreateEditableStreamで空の編
集ストリームを作ることもできます。下記の例ではフレームの順番を反転しています。
TEST08.C-----------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
AVICOMPRESSOPTIONS opt;
LONG i,leng,pos,start;
LPAVICOMPRESSOPTIONS popt;
PAVISTREAM pstm,psrc,pdst;
if (AVIStreamOpenFromFile(&pstm,"TEST.AVI",streamtypeVIDEO,0,
OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (CreateEditableStream(&psrc,pstm)!=0)
return 0;
AVIStreamRelease(pstm);
if (CreateEditableStream(&pdst,NULL)!=0)
return 0;
st=AVIStreamStart(psrc);
ed=st+AVIStreamLength(psrc)-1;
for (i=st;i<=ed;i++) {
leng=1;
start=i;
if (EditStreamCopy(psrc,&start,&leng,&pstm)!=0)
return 0;
leng=1;
pos=0;
if (EditStreamPaste(pdst,&pos,&leng,pstm,0,-1)!=0)
return 0;
AVIStreamRelease(pstm);
}
AVIStreamRelease(psrc);
popt=&opt;
memset(popt,0,sizeof(AVICOMPRESSOPTIONS));
if (AVISaveOptions(NULL,
ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_PREVIEW,
1,&pdst,&popt)) {
if ((hdlg=CreateDialogParam(hInstance,MAKEINTRESOURCE(DIALOG_1),
NULL,AbortDlgProc,0))==NULL)
return 0;
if (AVISaveV("TESTR.AVI",NULL,SaveCallback,1,&pdst,&popt)!=AVIERR_OK)
return 0;
DestroyWindow(hdlg);
}
AVISaveOptionsFree(1,&popt);
AVIStreamRelease(pdst);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
EditStreamCopyでストリームの一部をコピーし、EditStreamPasteで貼り付けます。
EditStreamPasteで貼り付け元の範囲を指定すれば1回で済むように思いますが、
EditStreamPasteで貼り付け元の範囲を指定することはできないようです。よって
EditStreamPasteの引数の最後の2つは0と−1を指定します。
編集ストリームインターフェイスポインタは通常のストリームインターフェイスポイ
ンタと同じように使うことができます。ストリームインターフェイスポインタを引数に
もつ他のAPIも利用可能です。
*クリップボードを利用する
AVIファイルを編集するためにはクリップボードを利用する必要があると思いま
す。VFWではクリップボードを利用するためのAPIが用意されています。
下記の例ではAVIPutFileOnClipboardを使ってAVIファイルをクリップボードに入れ
ます。クリップボードには同時にDIB、WAVEファイルが入ります。
TEST09.C-----------------------------------------------------------------------
#include <windows.h>
#include <vfw.h>
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
PAVIFILE pavi;
AVIFileInit();
if (AVIFileOpen(&pavi,"TESTX.AVI",OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
AVIPutFileOnClipboard(pavi);
AVIFileRelease(pavi);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
下記の例ではクリップボードからAVIファイルを取り出してファイルに保存しま
す。またクリップボードのファイルを削除します。クリップボードにAVIファイルが
無いときにはビットマップからAVIファイルを作ります。
TEST10.C-----------------------------------------------------------------------
#include <stdlib.h>
#include <windows.h>
#include <vfw.h>
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
AVIFILEINFO fi;
DWORD stm;
LPAVICOMPRESSOPTIONS *popt;
PAVIFILE pavi;
PAVISTREAM *pstm;
AVIFileInit();
if (AVIGetFromClipboard(&pavi)!=0)
return 0;
if (AVIFileInfo(pavi,&fi,sizeof(AVIFILEINFO))!=0)
return 0;
if ((pstm=malloc(fi.dwStreams*sizeof(PAVISTREAM)))==NULL)
return 0;
if ((popt=malloc(fi.dwStreams*sizeof(LPAVICOMPRESSOPTIONS)))==NULL)
return 0;
for (stm=0;stm<fi.dwStreams;stm++) {
if ((popt[stm]=calloc(1,sizeof(AVICOMPRESSOPTIONS)))==NULL)
return 0;
if (AVIFileGetStream(pavi,&pstm[stm],0,stm)!=0)
return 0;
}
if (AVISaveOptions(NULL,
ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_PREVIEW,
fi.dwStreams,pstm,popt)
&& AVISaveV("TESTX_.AVI",NULL,NULL,fi.dwStreams,pstm,popt)!=AVIERR_OK)
return 0;
AVISaveOptionsFree(fi.dwStreams,popt);
for (stm=0;stm<fi.dwStreams;stm++) {
AVIStreamRelease(pstm[stm]);
free(popt[stm]);
}
free(popt);
free(pstm);
AVIFileRelease(pavi);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
しかしTEST09でAVIファイルをクリップボードに入れて、TEST10でクリップボード
から取り出すと、ビデオストリームは先頭のフレーム以外は無くなってしまいます。
VFWのAPIではAVIファイルはそのプログラムの中だけで有効です。
*メモリ上のビットマップから編集ストリームを作る
VFWのAPIにはメモリに読み込んだビットマップファイルから編集ストリームイ
ンターフェイスポインタを作ることはできないように思えます。しかし、
AVIMakeStreamFromClipboardを応用することでメモリに読み込んだビットマップファイ
ルから編集ストリームインターフェイスポインタを作ることができます。この場合、ク
リップボード形式はCF_DIBを指定します。
TEST11.C-----------------------------------------------------------------------
#include <stdlib.h>
#include <windows.h>
#include <vfw.h>
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
long fs;
AVICOMPRESSOPTIONS opt;
FILE *fp;
HGLOBAL hg;
LPVOID p;
PAVISTREAM pstm;
AVIFileInit();
if ((fp=fopen("TEST00.BMP","rb"))==NULL)
return 0;
if (fseek(fp,0,SEEK_END)!=0)
return 0;
if ((fs=ftell(fp))==-1)
return 0;
if (fseek(fp,sizeof(BITMAPFILEHEADER),SEEK_SET)!=0)
return 0;
if ((hg=GlobalAlloc(GMEM_MOVEABLE,fs))==NULL)
return 0;
if ((p=GlobalLock(hg))==NULL)
return 0;
if (fread(p,1,fs,fp)!=fs)
return 0;
GlobalUnlock(hg);
if (fclose(fp)!=0)
return 0;
if (AVIMakeStreamFromClipboard(CF_DIB,hg,&pstm)==0) {
memset(&opt,0,sizeof(AVICOMPRESSOPTIONS));
if (AVISaveOptions(NULL,ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME
| ICMF_CHOOSE_PREVIEW,1,&pstm,&opt)
&& AVISaveV("TEST_.AVI",NULL,NULL,1,&pstm,&opt)!=AVIERR_OK)
return 0;
AVISaveOptionsFree(1,&opt);
AVIStreamRelease(pstm);
}
GlobalFree(hg);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
*ビデオ形式を求める
エクスプローラでAVIファイルのプロパティを見るとビデオの圧縮形式の名前が表
示されます。ビデオの圧縮形式の名前を示す文字列はVFWのAPIでは取得できませ
ん。VCM(Video Compression Manager)を利用する必要があります。
VCMを利用した例は下記のようになります。
TEST12.C-----------------------------------------------------------------------
#include <windows.h>
#include <vfw.h>
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
char str[128];
AVISTREAMINFO si;
HIC hic;
ICINFO icinfo;
PAVISTREAM pstm;
if (AVIStreamOpenFromFile(&pstm,"TEST.AVI",streamtypeVIDEO,0,
OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIStreamInfo(pstm,&si,sizeof(AVISTREAMINFO))!=0)
return 0;
AVIStreamRelease(pstm);
if ((hic=ICOpen(ICTYPE_VIDEO,si.fccHandler,ICMODE_QUERY))!=NULL) {
icinfo.dwSize=sizeof(ICINFO);
if (ICGetInfo(hic,&icinfo,sizeof(ICINFO))>0)
WideCharToMultiByte(CP_ACP,0,icinfo.szDescription,-1,
str,128,NULL,NULL);
else
lstrcpy(str,"未知のフォーマット");
if (ICClose(hic)!=ICERR_OK)
return 0;
} else {
lstrcpy(str,"未知のフォーマット");
}
MessageBox(NULL,str,"TEST",MB_OK);
return 0;
}
-------------------------------------------------------------------------------
*オーディオ形式を求める
ビデオ形式と同様にオーディオの圧縮形式の名前を示す文字列はVFWのAPIでは
取得できません。ACM(Audio Compression Manager)を利用する必要があります。
ACMを利用した例は下記のようになります。
TEST13.C-----------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <vfw.h>
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
char str[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
ACMFORMATTAGDETAILS aftd;
AVISTREAMINFO si;
LONG leng;
LPWAVEFORMATEX pwfx;
PAVISTREAM pstm;
if (AVIStreamOpenFromFile(&pstm,"TESTX.AVI",streamtypeAUDIO,0,
OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
return 0;
if (AVIStreamInfo(pstm,&si,sizeof(AVISTREAMINFO))!=0)
return 0;
if (AVIStreamReadFormat(pstm,si.dwStart,NULL,&leng)!=0)
return 0;
if (leng<sizeof(WAVEFORMATEX)-sizeof(WORD))
return 0;
if ((pwfx=malloc(leng))==NULL)
return 0;
if (AVIStreamReadFormat(pstm,si.dwStart,pwfx,&leng)!=0)
return 0;
memset(&aftd,0,sizeof(ACMFORMATTAGDETAILS));
aftd.cbStruct=sizeof(ACMFORMATTAGDETAILS);
aftd.dwFormatTag=pwfx->wFormatTag;
if (acmFormatTagDetails(NULL,&aftd,ACM_FORMATTAGDETAILSF_FORMATTAG)==0)
lstrcpy(str,aftd.szFormatTag);
else
lstrcpy(str,"未知のフォーマット");
free(pwfx);
MessageBox(NULL,str,"TEST",MB_OK);
return 0;
}
-------------------------------------------------------------------------------
*CLSIDについて
AVIFileOpen、AVIStreamOpenFromFile、AVISaveおよびAVISaveVの引数にはCLSIDへの
ポインタ、pclsidHandlerがあります。今までpclsidHandlerにはNULLを指定してきまし
た。この引数がNULLときには拡張子に基づいてレジストリを検索してCLSIDを求めます。
pclsidHandlerにNULLを指定したときにファイルの拡張子を「.AVI」や「.WAV」以外に
するとCLSIDを求めることができず、APIは失敗します。
pclsidHandlerを直接指定すれば「.AVI」や「.WAV」以外に拡張子を変更してもファ
イルを開くことができます。CLSIDは下記のように定義されています。
-------------------------------------------------------------------------------
typedef struct _GUID {
DWORD Data1
WORD Data2;
WORD Data3;
BYTE Data4[8];
} GUID;
typedef GUID CLSID;
-------------------------------------------------------------------------------
AVIのCLSIDは{00020000-0000-0000-C000-000000000046}です。下記はCLSIDを使っ
てAVIファイルを開く例です。
詳しくはOLE、COMなどを調べて下さい。
TEST14.C-----------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
CLSID clsid={0x00020000,0x0000,0x0000,
{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
LPBITMAPINFOHEADER pbmih;
PAVIFILE pavi;
PAVISTREAM pstm;
PGETFRAME pfrm;
AVIFileInit();
if (AVIFileOpen(&pavi,"TEST.AVI",OF_READ | OF_SHARE_DENY_NONE,&clsid)!=0)
return 0;
if (AVIFileGetStream(pavi,&pstm,0,0)!=0)
return 0;
if ((pfrm=AVIStreamGetFrameOpen(pstm,NULL))==NULL)
return 0;
if ((pbmih=AVIStreamGetFrame(pfrm,0))==NULL)
return 0;
if (bmpsave("TEST00.BMP",pbmih)!=0)
return 0;
if (AVIStreamGetFrameClose(pfrm)!=0)
return 0;
AVIStreamRelease(pstm);
AVIFileRelease(pavi);
AVIFileExit();
return 0;
}
-------------------------------------------------------------------------------
フリーソフトウェアへ戻る
ホームページへ戻る
お手紙はnekora@mapletown.netまで☆