土井研/ 自習室/ 動画/ 動画計測(寝屋川OHP)

1.3 AVIファイル

 AVIとはAudio Video Interleave の略です。本来の意味は「ビデオ」と「オーディオ」を「交互に(Interleave)」配置したファイルという意味になります。マックのmovと同様にWinodwsでの代表的なメディアファイルです。AVIファイルはRIFF( Resource Interchange File Format )形式をとっています。RIFFは様々なリソースをひとつのファイルにするためのファイル形式で、新しいフォーマットのリソースが出来ても基本構造の互換が保たれる構造をしています。  

●RIFFファイルの構造

 RIFFファイルは図7のように階層的に構成されている複数のブロックからなっています。このひとつのブロックのことをチャンク(塊)と呼びます。各チャンクには以下の4つの情報をもちます。

チャンクの種類はデータ部にサブチャンクを持つものと持たないものに分けられ、サブチャンクを持つチャンクをRIFFチャンクとLISTチャンクと呼びます。RIFFチャンクとLISTチャンクのデータ部の先頭4バイトはフォームタイプまたはリストタイプという

 RIFFファイルの最上位のチャンクは常にRIFFチャンクです。RIFFチャンクのフォームタイプには'AVI'や'WAVE'というようにファイルに保存されるデータの形式を表す4文字が入っています。LISTチャンクのリストタイプも同様に'hdrl'や'movi'などのようにリストの内容を示す4文字が入っています。RIFFファイルでサブチャンクを持つチャンクは、ファイル先頭のみRIFFチャンクでありそれ以外はすべてLISTチャンクです。


RIFFファイルの構造

 

●AVIファイルの構造

 

 図8のようにAVIファイルは多重の階層構造になっています。この図7の例は、ビデオストリームがひとつとオーディオストリームがひとつのAVIファイルです。この例に沿ってAVIのファイル構造を説明します。

 先頭のRIFFチャンクのフォームタイプは'AVI'です。この下にはLIST(hdrl)チャンク、JUNKサブチャンク、LIST(movi)チャンク、idx1サブチャンクという4つの子があります。

 ・LIST(hdrl)チャンク

   ヘッダ情報を保存しています。「avihサブチャンク」と、ストリームの数だけ「LIST (strl)チャンク」が

   続きます。「avihサブチャンク」はAVIファイル全体の情報を保存しています。

   「LIST(strl)チャンク」は各ストリームの「ヘッダチャンク(strhサブチャンク)」、

   「フォーマットチャンク(strfサブチャンク)」、「オプションデータチャンク(strnサ ブチャンク)」

   の3つのサブチャンクをもちます。「フォーマットチャンク」はオーディオストリ ームの場合は

   WAVEFORMAT(or PCMWAVEFORMAT)構造体、ビデオストリームの場合は BITMAPINFO構造体です。

 ・JUNKサブチャンク データ境界を2048byte単位にするためのダミーデータです。

 ・LIST(movi)チャンク

   実際のオーディオやビデオのデータが入っています。各サブチャンクの識別子の先 頭2文字はストリーム番号、

   後ろ2文字はデータのタイプを示します。主なデータのタイプは、'db'(非圧縮のデ バイスに

   依存しないビットマップ(DIB))、'dc'(圧縮したDIB)、'wb'(WAVEデータ)等です。

   例えば'00db'は「ストリーム番号0の非圧縮DIB」を意味します。これらのデータ チャンクはLIST(rec)チャンクにグループ化されることもあります。

 ・idx1サブチャンク

   各チャンクの再生順にAVIINDEXENTRY構造体が並んでいます。この順にしたが ってチャンクを再生していきます。

   idx1サブチャンクがない場合はファイル内のチャンクの物理的な順番(記録されて いる順) にしたがって再生します。

 

表3 AVIINDEXENTRY構造体

     typedef struct {

      DWORD  ckid;       //チャンク識別子('00db', '00wb'等)

      DWORD  dwFlags;

      DWORD  dwChunkOffset;   //チャンクの位置

      DWORD  dwChunkLength;   //チャンクのサイズ

     } AVIINDEXENTRY;

 

図8 AVIファイルの構造(zu08_avi.bmp)

 

●ビデオストリームの圧縮

 AVIファイル内のビデオストリームは連続するビットマップで表されますが一般に非常にサイズが大きくなるため、ほとんどの場合圧縮されています。圧縮の形式はIntelIndeoやCinepak、DV、MPEGなど多くの形式がありますが、各形式に対応したcodec(圧縮/展開を行なうドライバ)をシステムにインストールすることによってVideoForWindowsで展開が可能になります。

 

2.VideoForWindowsAPIを使ったAVIファイルを扱うプログラミング

 

2.1 AVIファイルを見る

 

 動画を取り巻く環境をざっと勉強しました。次は実際にAVIファイルを見てみることにしましょう。

 リスト1はRIFFファイルをダンプするプログラムです。「開く」ボタンでダンプを行うファイルを指定します。画面左上のリストコントロールにはファイル全体のRIFFチャンクのインデックスが表示されます。インデックスでチャンクを選択し、「Dump」ボタンを押すと選択したチャンクのデータ部を16進で表示します。各チャンク内のデータは非常に大きくなることもありますのでDumpの上限を指定できるようにします。

 このプログラムではRIFFファイルのインタフェースとしてCの基本ファイル関数

fopen()、 fclose()、 fread()、 fseek()、 ftell() を用います。

 

●ウィンドウを開く : WinMain(),dlgproc()

 メインのウィンドウはDialogBoxParam()によってダイアログボックスで構成されます。

ダイアログボックスプロシージャdlgproc()では「Dump」ボタンを押されたときの処理と

「開く」ボタンを押されたときの処理を行います。

 

●チャンクインデックスの表示 : chunk_display(), chunk_1(), set_data()

 ファイルの最初12バイトを読み込み、階層構造になっているRIFFファイルを

chunk_1()で再帰的に検索していきます。検索の際、各チャンクのデータ開始位置・サイズは、共にグローバル変数chunk[MAX_CHUNK_N]とchunk_size[MAX_CHUNK_N]に保存して行きます。chunk_1()は引数にウィンドウハンドルhwnd、RIFFファイルポインタhm, チャンクサイズc_size、階層の深さdpを持ちます。ftell()で現在のファイルの位置をpos0に取得し、チャンクの先頭8バイトを読み込みます。チャンクがLISTチャンクであれば階層の深さを1増やしてchunk_1()を再帰呼び出しします。一方サブチャンクであればデータ部を読み飛ばし(データ部が奇数の場合は「データサイズ+1」バイト分読み飛ばす)、チャンク先頭からの距離とチャンクサイズを比較し当該階層の終端チェックを行います。

 

●選択されたチャンクデータのダンプ表示 : dump_display()

 リストボックスで選択されたチャンク位置までchunk[MAX_CHUNK_N]によって

fseek()でシークします。その上でデータ部を順に読み込み、16進で表示します。

 

リスト1(list1.h、list1.cpp、list1.rc)

 

// riffdump  list1.h

 

#define IDC_BTN1 101

#define IDC_BTN2 102

#define IDC_EDIT1 103

#define IDC_LIST1 104

#define IDC_LIST2 105

#define IDC_TEXT1 106

#define IDC_TEXT2 107

#define   IDC_CK1 110

 

 

 

 

/********************************************************/

/*   riffファイルダンプ                */

/*       list1.cpp   00.06.08 <Ver.1.03>   */

/********************************************************/

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <Windows.h>

#include "list1.h"

#define  MAX_CHUNK_N 20000 // 扱えるチャンクの個数

 

//-------------------------------------------------------------------

int   n_chunk; // 各チャンクの位置とサイズの記録

long  chunk[MAX_CHUNK_N]; // プログラムを簡単にするため

long  chunk_size[MAX_CHUNK_N]; // グローバル変数を使う

 

//-------------------------------------------------------------------

BOOL CALLBACK dlgproc( HWND, UINT, WPARAM, LPARAM );

 

char * file_open( HWND );

void  dump_display( HWND, FILE*, long, long );

void  chunk_display( HWND, char*, FILE* );

int   chunk_1( HWND, FILE*, long, int );

void  set_data( HWND, int, int, char*, int );

 

//-------------------------------------------------------------------

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow )

{

DialogBoxParam( hInstance, "DLG_0", HWND_DESKTOP,

(DLGPROC)dlgproc, (LPARAM)lpszCmdLine);

return TRUE;

}

 

BOOL CALLBACK dlgproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )

{

int i, limit, tmp;

char      *fname;

char str[10];

static FILE *  fp;

static int   ck = 0;

 

switch(msg){

 

case WM_INITDIALOG:

SetDlgItemText( hwnd, IDC_EDIT1, "1000" );

return TRUE;

 

case WM_COMMAND:

switch(LOWORD(wp)){

 

case IDC_BTN1: // 選択されたチャンクのダンプ

i = SendDlgItemMessage( hwnd, IDC_LIST1, LB_GETCURSEL, 0, 0 );

if( i == LB_ERR ) return 0;

GetDlgItemText( hwnd, IDC_EDIT1, str, 10 );

tmp = atoi( str );

limit = ( tmp > chunk_size[i] ) ? chunk_size[i] : tmp;

SendDlgItemMessage( hwnd, IDC_LIST2, LB_RESETCONTENT, 0, 0 );

SendDlgItemMessage( hwnd, IDC_LIST2, WM_SETREDRAW, FALSE, 0 );

dump_display( hwnd, fp, chunk[i], limit );

SendDlgItemMessage( hwnd, IDC_LIST2, WM_SETREDRAW, TRUE , 0 );

return TRUE;

 

case IDC_BTN2: // ファイルを開く処理

fname = file_open( hwnd );

if( fname == NULL )

return TRUE;

if( fp )

fclose( fp );

fp = fopen( fname, "rb" );

SendDlgItemMessage( hwnd, IDC_LIST1, LB_RESETCONTENT, 0, 0 );

SendDlgItemMessage( hwnd, IDC_LIST1, WM_SETREDRAW, FALSE, 0 );

chunk_display( hwnd, fname, fp );

SendDlgItemMessage( hwnd, IDC_LIST1, WM_SETREDRAW, TRUE , 0 );

return TRUE;

 

case IDC_CK1: // 階層無視チェックの処理

if( ck )

ck = 0;

else  

ck = 1;

CheckDlgButton(hwnd, IDC_CK1, ck );

return TRUE;

 

case IDCANCEL:

if( fp )

fclose( fp );

EndDialog(hwnd, -1);

return TRUE;

 

}

}

return FALSE;

}

 

//-------------------------------------------------------- ファイル選択

char* file_open( HWND hwnd )

{

OPENFILENAME fname;

static char fn[256];

char filename[64];

static char filefilter[] = "AVIファイル<RIFF形式>(*.avi)\0*.avi\0"

  "すべてのファイル(*.*)\0*.*\0\0";

 

memset( &fname, 0, sizeof(OPENFILENAME) );

fname.lStructSize  = sizeof(OPENFILENAME);

fname.hwndOwner   = hwnd;

fname.lpstrFilter  = filefilter;

fname.nFilterIndex  = 1;

fname.lpstrFile   = fn;

fname.nMaxFile    = sizeof(fn);

fname.lpstrFileTitle = filename;

fname.nMaxFileTitle = sizeof(filename)-1;

fname.Flags     = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

if( !GetOpenFileName( &fname ) ) 

return NULL;

return fn;

}

 

//---------------------------------------------- ダンプリストの表示

void dump_display( HWND hwnd, FILE *hm, long ofset, long limit )

{

unsigned char cp[20]; // 読み込みバッファの確保

unsigned char c;

char      cbuf[200];

char      *xp;

int      j, cnt, cnt16;

DWORD     ab;

 

fseek( hm, ofset, SEEK_SET ); // 指定されたチャンクまでシーク

cnt = 0; // 行カウンタのリセット

cnt16 = 0 ;

while(1){

ab = fread( cp, 1, 16, hm ); // 16byte読み込み

if( ab == 0 )

break;

cnt16 += 16;

xp = cbuf;

wsprintf( xp, "%04X ", (cnt++) * 16 );

xp = xp + 6;

for( j = 0 ; j < 16 ; j++ ) {

if( j < (int)ab ) wsprintf(xp,"%02X ", cp[j] );

else  wsprintf(xp,"-- ");

xp = xp + 3;

}

for( j = 0 ; j < 16 ; j++ ) {

if( j < (int)ab ) c = cp[j] ;

else       c = '-';

if( iscntrl(c) ) c = '.';

*xp = c;

xp++;

}

*xp = 0; // 終端コードの書き込み

SendDlgItemMessage( hwnd, IDC_LIST2, LB_ADDSTRING, 0, (LPARAM)cbuf );

// リストボックスに追加

if( cnt16 > limit ) 

break;

}

return;

}

 

//------------------------------------------------------------------------

void chunk_display( HWND hwnd, char *fname, FILE *hm )

{

char      cbuf[200];

long f_size;

char c[12];

int sw; // 階層無視のスイッチ

n_chunk = 0; // 最初のチャンク

fread( c, 1, 12, hm ); // チャンクの先頭を12バイト読む

if( strncmp( c, "RIFF", 4 ) ) {

MessageBox( hwnd, "RIFFフォーマットではありません", "ERROR", MB_OK );

SendDlgItemMessage( hwnd, IDC_LIST1, LB_RESETCONTENT, 0, 0 );

SendDlgItemMessage( hwnd, IDC_LIST2, LB_RESETCONTENT, 0, 0 );

return;

}

f_size = *(int *)(c + 4);

wsprintf( cbuf, "RIFF-DUMP [%s] %ld(%XH)byte", fname, f_size + 8, f_size +8);

SetWindowText( hwnd, cbuf );

if( IsDlgButtonChecked(hwnd, IDC_CK1) )

sw = -2; // 階層無視のチェックがされている

else

sw = 0;

set_data( hwnd, 0, 0, c, sw ); // オフセット0、RIFFチャンク

chunk_1( hwnd, hm, f_size, sw );

 

}

 

//-------------------------- RIFF、LISTチャンクのデータ部分の検索、再帰呼び出し

//                c_sizeはフォームタイプ4バイト分を含むので

// データ部分の大きさは c_size - 4 となる

int chunk_1( HWND hwnd, FILE *hm, long c_size, int dp )

{

int   i,ss,

pos0, // データ部分の先頭をポイント

pos1; // 現在の位置をポイント

char  ccc[5];

char  c[12];

 

if( dp > 10 ){

MessageBox(hwnd, "階層が深すぎます", "ERROR", MB_OK);

return 1; // 異常終了

}

pos0 = pos1 = ftell( hm ); // このチャンクのデータ部分のトップの

// ファイル全体からのオフセット

while( pos1 - pos0 < c_size - 4 ) {

fread( c, 1, 8, hm ); // サブチャンクの先頭8バイトを読む

for( i = 0 ; i < 4 ; i++ ) 

ccc[i] = c[i];

ccc[4] = 0;

ss = *(int *)(c + 4); // データサイズを取り出す

if( !strncmp( ccc, "RIFF", 4 ) || !strncmp( ccc, "LIST", 4 )) {

// RIFF、LISTチャンクの処理

fread( &(c[8]), 1, 4, hm );

set_data( hwnd, 0, pos1, c, dp+1 );

if( dp >= 0 ){ // 階層を無視しないなら

if( chunk_1( hwnd, hm, ss, dp+1) ){ // 再帰呼び出し

return 1; // エラーを引継ぐ

}

}

}

else { // サブチャンクの処理

set_data( hwnd, 1, pos1, c, dp+1 );

if( ss % 2 ) // データサイズが奇数ならば

ss++; // 1バイト読み飛ばす

fseek( hm, ss, SEEK_CUR ); // データ部分の読み飛ばし

}

pos1 = ftell( hm ); // 現在の位置を取り出す

}

return 0; // 正常終了

}

//-------------------------- チャンク名の書き出しと位置、サイズの記録

void set_data( HWND hwnd, int type, int pos, char *chunk_type, int dp)

{

int   i;

int c_size;

char cbuf[200];

char *xp;

 

c_size = *(int *)(chunk_type + 4 ); // チャンクサイズの取り出し

xp = cbuf;

wsprintf( xp, "%08X : ", pos );

xp = xp + 11;

if( dp < 0 ) // dpが負なら階層を無視した表示

dp = 0;

for( i = 0 ; i < dp * 2 ; i++ ){ 

*xp = ' '; xp++;

}

i = wsprintf( xp, "%c%c%c%c : %d", 

chunk_type[0], chunk_type[1], chunk_type[2], chunk_type[3], 

c_size ); 

if( type == 0 ){ // 0 はRIFF、LISTチャンク

wsprintf( xp + i, " : %c%c%c%c",

chunk_type[8], chunk_type[9], chunk_type[10], chunk_type[11] ); 

}

SendDlgItemMessage( hwnd, IDC_LIST1, LB_ADDSTRING, 0, (LPARAM)cbuf );

chunk[n_chunk] = pos; // チャンクの位置、サイズの記録

chunk_size[n_chunk] = c_size + 8;

n_chunk++;

if( n_chunk > MAX_CHUNK_N ){

MessageBox( hwnd, "チャンク数が多すぎます", "ERROR", MB_OK);

exit( 0 );

}

}

 

#include <windows.h>

#include "list1.h"

 

DLG_0 DIALOG DISCARDABLE 100, 30, 320, 300

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "RIFF-DUMP"

FONT 11, "MS ゴシック" // プロポーショナルでないフォント

BEGIN

 LTEXT "Dumpの上限", IDC_TEXT1, 200, 60, 40, 15

 LTEXT "byte", IDC_TEXT2, 237, 78, 40, 13

 EDITTEXT IDC_EDIT1, 200, 75, 35, 13

 PUSHBUTTON "Dump", IDC_BTN1, 260, 70, 40, 20

 PUSHBUTTON "開く", IDC_BTN2, 260, 20, 40, 20

 CHECKBOX   "階層を無視" IDC_CK1 200, 25, 50, 10

 LISTBOX IDC_LIST1, 10, 10, 170, 100, WS_VSCROLL | LBS_NOTIFY  

 LISTBOX IDC_LIST2, 10, 120, 300, 182, WS_VSCROLL | LBS_NOTIFY

END

 

    

図9 リスト1の実行画面:Type2DV-AVIファイルをダンプする

2.3 圧縮されたフレームを取り出す

 

 次に今回のテーマのデジタルビデオのキャプチャによって作られる、DV-AVIファイルからのフレームの切り出し方法を紹介します。先にも解説したようにDV-AVIファイルはVideoForWindowsで読み出すことのできるType2DV-AVI形式と一般的なAVIファイルの構造と異なるType1DV-AVI形式(AVI2と呼ばれる場合もある)があります。現状ではこれらは混在して使われている状況で、VideoForWindowsによる処理を行うのであれば、

Type2DV-AVI形式のファイルが出力できるキャプチャシステムを選択する必要があります。

 DV-AVIファイルの各フレームは圧縮されているので画像処理のためにフレームの各ビットを取り出すには解凍の作業が必要です。VideoForWindowsにはこの解凍作業を行うAVIが用意されています。リスト3ではこの解凍の関数も含めVideoForWindowsのAVIファイル操作の関数を利用して組み立てます。

 VideoForWindowsのAVIファイル操作の関数では、ファイル全体と各フレームデータとの間にストリームという概念を導入します。mmio系の関数も含め通常のファイルアクセスでは、ファイルをオープンして、そのファイルハンドルを用いてみ書きするという手順をとりますが、VideoForWindowsによるAVIファイルのアクセスでは、ファイルをオープンしてストリームを取り出し、そのストリームのハンドルでデータをアクセスするという手順をとります。

 リスト3はユーザインターフェースはリスト2を流用し、ファイルアクセス部分をmmio系のAPIからAVI系のAPIに変更しています。AVI系のAPIではファイル全体の情報をAVIFILEINFO構造体、ストリームの情報をAVISTREAMINFO構造体に持ちますが、この内容はAVIファイルのavihチャンクのMainAVIHeader構造体とビデオストリーム用のLIST(strl)チャンクのAVIStreamHeader構造体が持つ内容に対応しています。 

 

リスト3 圧縮AVIファイルの表示(list3.cpp、ヘッダ、リソースはリスト2と同じ)

図11 リスト3の実行画面(zu11_l3.bmp)

 

表6 AVIファイルのオープンに関連する関数(hyo6.txt)

┌──────────────────────────────────────────────┐    

│HRESULT AVIFileOpen  ( PAVFILE* ppfile, LPCTSTR szFile, UINT mode, CLSID* pclsidHandler ) │  

│HRESULT AVIFileInfo  ( PAVFILE pfile, LPAVFILEINFO pfi, LONG lSize )           │   

│ULONG  AVIFileRelease( PAVFILE pfile )                          │     

├──────────────────────────────────────────────┤      

│パラメータ 、戻り値                                    │     

├───────┬──────────────────────────────────────┤      

│ppfile    │新しいAVIファイルハンドルへのポインタ                    │      

├───────┼──────────────────────────────────────┤      

│pfile     │AVIファイルハンドル                             │      

├───────┼──────────────────────────────────────┤      

│szFile    │オープンするファイル名                           │     

├───────┼──────────────────────────────────────┤     

│mode     │アクセスモード。デフォルトはOF_READ                     │    

│       │OF_CEREATE      新規作成                        │     

│       │OF_READ       読み取り専用でオープン                 │     

│       │OF_READWRITE     読み取り/書き込み許可でオープン            │    

│       │OF_SHARE_DENY_NONE  非排他的にオープン。他のプロセスは読み取り/書き込み  │  

│       │  許可でこのファイルをオープンできる。         │    

│       │OF_SHARE_DENY_READ  非排他的にオープン。他のプロセスは読み取り専用でこの  │    

│       │  ファイルをオープンできる               │     

│       │OF_SHARE_DENY_WRITE 非排他的にオープン。他のプロセスは書き込み許可でこの  │   

│       │  ファイルをオープンできる               │    

│       │OF_SHARE_EXCLUSIVE  他のプロセスからのアクセスを禁止して、オープン     │   

│       │OF_WRITE       書き込み許可でオープン                 │   

├───────┼──────────────────────────────────────┤    

│pclaidHandler │使用する標準・カスタムハンドラのクラス識別子へのポインタ。         │     

│       │NULLでは適切なハンドラが選択される。                    │     

├───────┼──────────────────────────────────────┤    

│pfi      │情報を受け取るAVIFILEINFO構造体へのポインタ                 │  

│       │                                      │    

│       │AVIFILEINFO構造体                              │     

│       │typedef struct _AVIFILEINFO {                        │     

│       │ DWORD dwMaxBytesPerSec;    近似の最大データレート          │     

│       │ DWORD dwFlags;         アプリケーションフラグ          │   

│       │ DWORD dwCaps;         機能フラグ                │   

│       │ DWORD dwStreams;        ファイル内のストリーム数         │    

│       │ DWORD dwSuggestedBufferSize;  このファイルを読み取るときの       │     

│       │   推奨バッファサイズ             │     

│       │ DWORD dwWidth;         イメージの横幅(ピクセル数)       │      

│       │ DWORD dwHeight;        イメージの縦幅(ピクセル数)       │     

│       │ DWORD dwScale;         ファイル全体に適用される時間単位     │      

│       │ DWORD dwRate;         dwRate / dwScale = 秒あたりのサンプル数  │     

│       │ DWORD dwLength;        ファイルの長さ(dwRateおよびdwScaleで指定)│      

│       │ DWORD dwEditCount;       追加または削除したストリーム数      │      

│       │ char  szFileType[64];     ファイルタイプを説明する文字列      │      

│       │} AVIFILEINFO;                               │   

├───────┼──────────────────────────────────────┤    

│lSize     │ AVIFILEINFO構造体のサイズ                         │    

├───────┼──────────────────────────────────────┤     

│戻り値    │AVIFileOpen()とAVIFileInfo()では正常終了した場合は0、それ以外はエラー   │    

│       │AVIFileRelease()ではファイルの参照カウント                 │    

├───────┴──────────────────────────────────────┤     

│解説                                            │    

├──────────────────────────────────────────────┤     

│AVIFileOpen()はAVIファイルを開く                              │   

│AVIFileInfo()はAVIファイルの情報を取得する                         │   

│AVIFileRelease()はAVIファイルインタフェースハンドルの参照カウントをひとつ減らし、      │    

│カウントが0になるとファイルを閉じる                            │    

└──────────────────────────────────────────────┘      

表7 AVIストリームを操作する関数(hyo7.txt)

┌───────────────────────────────────────────────┐

│HRESULT AVIStreamOpenFromFile( PAVISTREAM * ppavi, LPCTSTR szFile, DWORD fccType,       │

│  LONG lParam, UINT mode, CLSID * pclsidHandler )         │

│HRESULT AVIFileGetStream( PAVFILE pfile, PAVISTREAM * ppavi, DWORD fccType, LONG lParam )   │         

│HRESULT AVIStreamInfo  ( PAVISTREAM pavi, AVISTREAMINFO * psi, LONG lSize )         │         

│HRESULT AVIStreamAddRef ( PAVISTREAM pavi )                          │         

│HRESULT AVIStreamRead  ( PAVISTREAM pavi, LONG lStart, LONG lSamples, LPVOID lpBuffer,    │         

   LONG cbBuffer,LONG * plBytes, LONG * plSmaples )       │         

│HRESULT AVIStreamRelease( PAVISTREAM pavi )                          │         

├───────────────────────────────────────────────┤   

│パラメータ 、戻り値                                      │ 

├───────┬───────────────────────────────────────┤ 

│szFile    │オープンするファイル名                            │

├───────┼───────────────────────────────────────┤ 

│mode     │アクセスモード                                │

├───────┼───────────────────────────────────────┤

│pclaidHandler │使用する標準・カスタムハンドラのクラス識別子へのポインタ           │

├───────┼───────────────────────────────────────┤

│pfile     │AVIファイルハンドル                              │

├───────┼───────────────────────────────────────┤

│ppavi     │AVIストリームハンドルへのポインタ                       │

├───────┼───────────────────────────────────────┤

│pavi     │AVIストリームハンドル                             │

├───────┼───────────────────────────────────────┤

│fccType    │開くストリームのタイプを指示する4文字コード。タイプを指定しない場合は0    │

│       │ streamtypeAUDIO  オーディオストリーム("auds")             │

│       │ streamtypeMIDI   MIDIストリーム("mids")                │

│       │ streamtypeTEXT   テキストストリーム("txts")              │

│       │ streamtypeVIDEO  ビデオストリーム("vids")               │

├───────┼───────────────────────────────────────┤

│lParam    │ストリームタイプのカウント                          │

├───────┼───────────────────────────────────────┤

│psi      │ストリーム情報を受け取るAVISTREAMINFO構造体のポインタ             │

│       │                                       │

│       │AVISTREAMINFO構造体                              │   

│       │typedef struct _AVISTREAMINFO{                        │   

│       │ DWORD fcctype;         ストリームタイプを示す4文字コード     │        

│       │ DWORD fccHandler;       ビデオストリームの圧縮ハンドラを示す    │        

│       │   4文字コード                │         

│       │ DWORD dwFlags;         ストリームフラグ              │         

│       │ DWORD dwCaps;         機能フラグ                 │         

│       │ WORD  wPriority;        ストリーム優先順位             │         

│       │ WORD  wLanguage;        ストリーム言語               │       

│       │ DWORD dwScale;         ストリーム用の時間単位           │         

│       │ DWORD dwRate;         dwRate / dwScale = 秒あたりのサンプル数   │         

│       │ DWORD dwStart;         通常は0                  │         

│       │ DWORD dwLength;        ストリームの長さ(dwRateおよびdwScaleで指定)│         

│       │ DWORD dwInitialFrames;     オーディオスキュー             │         

│       │ DWORD dwSuggestedBufferSize;  ストリームの推奨バッファサイズ       │         

│       │ DWORD dwQuality;        ビデオデータストリームの品質インジケータ  │         

│       │ DWORD dwSampleSize;      1つのデータサンプルのバイトサイズ     │         

│       │ RECT  rcFrame;         ビデオデスティネーション矩形のサイズ    │         

│       │ DWORD dwEditCount;       ストリームを編集した回数          │         

│       │ DWORD dwFormatChangeCount;   ストリームフォーマットの変更回数      │         

│       │ char  szName[64];       ストリームの説明文             │         

│       │} AVISTREAMINFO                                │         

├───────┼───────────────────────────────────────┤         

│lSize     │AVISTREAMINFO構造体のサイズ                          │         

├───────┼───────────────────────────────────────┤         

│lStart    │読み取る一つ目のサンプル                           │         

├───────┼───────────────────────────────────────┤         

│lSamples   │読み取るサンプルの数                             │         

├───────┼───────────────────────────────────────┤       

│lpBuffer   │読み取ったデータを受け取るバッファのポインタ                 │      

├───────┼───────────────────────────────────────┤      

│cbBuffer   │lpBufferで指定したバッファサイズ                       │       

├───────┼───────────────────────────────────────┤       

│plBytes    │lpBufferに格納されるデータのバイト数を受け取るポインタ            │        

├───────┼───────────────────────────────────────┤       

│plSamples   │lpBufferに格納されるサンプルのバイト数を受け取るポインタ           │      

├───────┼───────────────────────────────────────┤       

│戻り値    │AVIFileGetStream(),AVIStreamInfo(),AVIStreamRead()では正常終了した場合は0、 │       

│       │それ以外はエラー                               │       

│       │AVIStreamAddRef(),AVIStreamRelease()ではストリームの現在の参照カウント    │    

├───────┴───────────────────────────────────────┤     

│解説                                             │        

├───────────────────────────────────────────────┤     

│AVIStreamOpenFromFile()はAVIファイル名からストリームをオープンする              │

│AVIFileGetStream()はAVIファイルハンドルからストリームを取得する                │     

│AVIStreamInfo()はストリームヘッダ情報を取得する                        │      

│AVIStreamAddRef()はストリームの参照カウントを1増やす                     │      

│AVIStreamRead()はストリームからデータを読出す                         │      

│AVIStreamRelease()はストリームの参照カウントを1減らし、0になった場合ストリームを閉じる   │       

└───────────────────────────────────────────────┘

 

表8 圧縮フレームを操作する関数(hyo8.txt)

┌─────────────────────────────────────────────┐       

│PGETFRAME AVIStreamGetFrameOpen ( PAVISTREAM pavi, LPBITMAPINFOHEADER lpbiWanted )    │       

│LPVOID  AVIStreamGetFrame   ( PGETFRAME pget, LONG lPos )              │    

│HRESULT  AVIStreamGetFrameClose( PGETFRAME pget )                    │     

├─────────────────────────────────────────────┤     

│パラメータ 、戻り値                                    │     

├──────┬──────────────────────────────────────┤      

│pavi    │AVIストリームハンドル                            │      

├──────┼──────────────────────────────────────┤      

│lpbiWanted │目的のビデオフォーマットを示すBITMAPINFOHEADER構造体へのポインタ      │      

├──────┼──────────────────────────────────────┤      

│pget    │GetFrameオブジェクトへのポインタ                      │      

├──────┼──────────────────────────────────────┤      

│lPos    │ストリーム内のフレーム位置                         │      

├──────┼──────────────────────────────────────┤    

│戻り値   │AVIStreamGetFrameOpen()ではGetFrameオブジェクト。ストリームを指定の     │        

│      │フォーマットに解凍するプログラムがない場合はNULL。             │    

│      │AVIStreamGetFrame()ではパックDIB(BITMAIINFOHEADER構造体)形式に直した    │       

│      │フレームデータへのポインタ、解凍できなかった場合はNULL 。          │        

│      │AVIStreamGetFrameClose()では正常終了した場合は0、それ以外はエラー     │        

├──────┴──────────────────────────────────────┤      

│解説                                           │     

├─────────────────────────────────────────────┤     

│AVIStreamGetFrameOpen()は指定のビデオストリームからビデオフレームを解凍する準備をする。  │     

│AVIStreamGetFrame()は解凍ビデオフレームへのポインタを取得する。              │     

│AVIStreamGetFrameClose()はビデオフレーム解凍中に割り当てたリソースを解放する。      │      

└─────────────────────────────────────────────┘

パソコンによる動画計測とその周辺 / 1.動画処理のための準備 / VFWく
VFW,プログラム2