AVIの表示/再生(コーデック対応)

動画ファイル(AVI)を表示/再生する例題です。Video for Windows(VFW)によりAVIファイルの読込みを行っているため、他のOSの移植等は全く考慮していません(一から読込みのは大変だったので..)。AVIから任意の再生位置の画像を取得することができますので、各画像(BMP)に対する画像処理も可能になるかと思います。

コーデック(divx,xvid etc.)による画像の取得も行っていますが、実行するコンピュータにコーデックがインストールされていないと表示されません。目的のコーデックを他のサイトからダウンロードする必要があります。コーデックがインストールされているかどうかを確認したい場合は、[コントロールパネル]-[管理ツール]-[コンピュータの管理]-[デバイスマネージャ]-[サウンド、ビデオ、およびゲームコントローラ]-[オーディオ(ビデオ)CODEC](XPの場合)において目的のコーデックがあるか確認してください。


実行ファイル(aviplay.exe)

 ダウンロード

AVIの表示/再生(コーデック対応)(aviplay.c)
//-----------------------------------------------------------------
// aviplay.cpp:
//      AVI 再生/表示ウィンドウ
//                Last Update: <2005/01/28 11:21:26 A.Murakami>
//-----------------------------------------------------------------
#include <stdio.h>
#include <math.h>
#include <windows.h>
#include <vfw.h>
#include "aviplay.h"
//-----------------------------------------------------------------
#pragma comment(linker,"/subsystem:windows")
#pragma comment(lib,"winmm")
#pragma comment(lib,"vfw32")
//-----------------------------------------------------------------
// グローバル変数定義
//-----------------------------------------------------------------
HINSTANCE hAppInst; HWND hAppWnd;
UINT aviLoad,iWidth,iHeight,iSize;
LPBYTE lpBMP = NULL;
AviInfo avi;
double wm_xscale,wm_yscale;
static HWND hwB0,hwB1,hwB2,hwB3;
//-----------------------------------------------------------------
UINT vRun=FALSE; // 連続再生用
//-----------------------------------------------------------------
void TRACE(char *fmt,...)
{
    char szBuff[BUFSIZ];
    va_list ap;
    va_start(ap,fmt);
    vsprintf(szBuff,fmt,ap);
#ifdef _MSC_VER
    OutputDebugString(szBuff);
#else
    fprintf(stderr,szBuff);
#endif
    va_end(ap);
}
//-----------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
                   LPSTR lpsCmdLine, int nCmdShow)
{
    MSG msg;
    LPCTSTR szClassName = "aviplay"; // 初期化
    aviLoad = FALSE; iWidth = 300; iHeight = 200;
    // ウィンドウ・クラスの登録
    if(!hPrevInst){
        if(!InitApp(hCurInst,szClassName)) return 0;
        hAppInst = hCurInst;
    }
    // ウィンドウ作成
    if(!InitInstance(hCurInst,szClassName,lpsCmdLine,nCmdShow)){
        return 0;
    }
    // AVI 初期化
    AviInit();
    // メッセージループ
    while(GetMessage(&msg,NULL,0,0)){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
//-----------------------------------------------------------------
// ウィンドウ・クラスの登録
//-----------------------------------------------------------------
BOOL InitApp(HINSTANCE hInst, LPCSTR szClassName)
{
    WNDCLASSEX wc;
    wc.cbSize        = sizeof(wc);
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc; // プロシージャ名
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInst;   // インスタンス
    wc.hIcon         = LoadIcon(NULL,IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL,IDC_ARROW);
    wc.hIconSm       = LoadIcon(NULL,IDI_APPLICATION);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = NULL;    // メニュー名
    wc.lpszClassName = (LPCSTR)szClassName;
    return (RegisterClassEx(&wc));
}
//-----------------------------------------------------------------
// ウィンドウの生成
//-----------------------------------------------------------------
BOOL InitInstance(HINSTANCE hInst,LPCSTR szClassName,
                  LPSTR lpsCmdLine,int nCmdShow)
{
    TCHAR lpStr[256]; HWND hWnd;
    // ウィンドウの作成 
    wsprintf(lpStr,"動画ファイル(AVI)再生");
    hWnd = CreateWindow(szClassName,lpStr,   // タイトルバー
                        WS_OVERLAPPEDWINDOW, // ウィンドウ
                        CW_USEDEFAULT,       // X座標
                        CW_USEDEFAULT,       // Y座標
                        15+iWidth,           // 幅
                        65+iHeight,          // 高さ
                        NULL,                // 親ウィンドウのハンドル
                        NULL,                // メニューハンドル 
                        hInst,               // インスタンスハンドル
                        NULL);
    if(!hWnd) return FALSE;
    ShowWindow(hWnd,nCmdShow);
    UpdateWindow(hWnd);
    hAppWnd = hWnd;
    return TRUE;
}
//-----------------------------------------------------------------
// メッセージ情報
//-----------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
    switch(iMsg){
    case WM_CHAR:
        if(wParam=='q') SendMessage(hwnd,WM_DESTROY,0,0); break;
    case WM_CREATE: {
        // ボタン作成
        hwB0 = CreateWindow("Button","開く",WS_CHILD | WS_VISIBLE,
                            5,5,55,25,hwnd,(HMENU)ID_OPEN,hAppInst,NULL);
        hwB1 = CreateWindow("Button","コマ送り",WS_CHILD | WS_VISIBLE,
                            60,5,70,25,hwnd,(HMENU)ID_AVI1,hAppInst,NULL);
        hwB2 = CreateWindow("Button","再生",WS_CHILD | WS_VISIBLE,
                            130,5,55,25,hwnd,(HMENU)ID_AVI2,hAppInst,NULL);
        hwB3 = CreateWindow("Button","保存",WS_CHILD | WS_VISIBLE,
                            185,5,55,25,hwnd,(HMENU)ID_SAVE,hAppInst,NULL);
    } break;
    case WM_COMMAND:
        switch(LOWORD(wParam)){
        case 'q':     // 終了
            SendMessage(hwnd,WM_DESTROY,0,0); break;
        case ID_OPEN: // ファイル選択
            if(vRun) break;
            if(OpenFile(avi.in_path)){ AviOpen(); }
            break;
        case ID_AVI1: // コマ送り
            if(aviLoad) AviNext();
            break;
        case ID_AVI2: // 連続再生
            if(aviLoad) AviView();
            break;
        case ID_SAVE: // 画像保存
            static TCHAR szFn[MAX_PATH];
            if(SaveFile(szFn)){ SaveBMP(szFn,lpBMP); }
            break;
        }
        break;
    case WM_PAINT:
        if(aviLoad){
            HDC hdc; PAINTSTRUCT ps;
            // DIBを画面に描画
            hdc = BeginPaint(hwnd,&ps);
            StretchDIBits(hdc,4,35,
                          (int)(wm_xscale*iWidth),(int)(wm_yscale*iHeight),
                          0,0,iWidth,iHeight,
                          lpBMP+avi.biSize,(LPBITMAPINFO)lpBMP,
                          DIB_RGB_COLORS,SRCCOPY);
            EndPaint(hwnd,&ps);
        }
        break;
    case WM_SIZE: { // ウィンドウ幅の変更
        UINT wx,wy;
        WINDOWPLACEMENT wndpl;
        GetWindowPlacement(hAppWnd,&wndpl);
        wx = wndpl.rcNormalPosition.right - wndpl.rcNormalPosition.left;
        wy = wndpl.rcNormalPosition.bottom - wndpl.rcNormalPosition.top;
        wx -= 14; wy -= 84;
        wm_xscale = wx/(double)iWidth;
        wm_yscale = wy/(double)iHeight;
        // 再描画範囲
        SetRect(&avi.dRgn,
                4,35,4+(int)(iWidth*wm_xscale),35+(int)(iHeight*wm_yscale));
    } break;
    case WM_DESTROY: // メモリの解放
        if(aviLoad) AviClose();
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd,iMsg,wParam,lParam);
}
//-----------------------------------------------------------------
// ウィンドウタイトルの設定
//-----------------------------------------------------------------
void SetWTitle(LPTSTR tstr)
{
    SetWindowText(hAppWnd,tstr);
}
char *getfps(void)
{
    static DWORD last     = 0;
    static DWORD frames   = 0;
    static char  buf[256] = "";
    DWORD  current = timeGetTime();
    frames++;
    if(500 <= current - last) { // 0.5秒毎に更新
        double dt  = (double)(current - last) / 1000.0f;
        double fps = (double)frames / dt;
        last = current;
        frames = 0;
        sprintf(buf,"%.02f fps",fps);
    }
    return buf;
}
//-----------------------------------------------------------------
// 画像情報の設定
//-----------------------------------------------------------------
void set_window(LPBITMAPINFOHEADER bih)
{
    TCHAR tStr[256];
    // 画像情報
    iWidth  = bih->biWidth;
    iHeight = bih->biHeight;
    // ウィンドウ幅の変更
    UINT wx,wy;
    WINDOWPLACEMENT wndpl;
    GetWindowPlacement(hAppWnd,&wndpl);
    wx = wndpl.rcNormalPosition.left;
    wy = wndpl.rcNormalPosition.top;
    MoveWindow(hAppWnd,wx,wy,15+iWidth,65+iHeight,TRUE);
    // キャプション
    wsprintf(tStr,"[%s] frame %d/%d",avi.in_path,1,avi.dwLength);
    SetWTitle(tStr);
    // 描画サイズ
    wm_xscale = wm_yscale = 1.0;
}
//-----------------------------------------------------------------
// [開く]ファイルの選択
//-----------------------------------------------------------------
UINT OpenFile(LPTSTR lpFname)
{
    static OPENFILENAME ofn;
    TCHAR szFt[MAX_PATH];
    lpFname[0] = NULL;
    // ファイル[開く]ダイアログ設定
    ofn.lStructSize       = sizeof(OPENFILENAME);
    ofn.hwndOwner         = hAppWnd;
    ofn.hInstance         = NULL;
    ofn.lpstrFilter       =
        "AVI stream(*.avi)\0*.avi\0"
        "すべてのファイル(*.*)\0*.*\0\0";
    ofn.lpstrCustomFilter = NULL;
    ofn.nMaxCustFilter    = 0;
    ofn.nFilterIndex      = 1;       // フィルタの初期位置
    ofn.lpstrFile         = lpFname; // ファイル名用文字列バッファ
    ofn.nMaxFile          = 255;     // 文字列バッファのサイズ
    ofn.lpstrFileTitle    = szFt;    // タイトル用文字列バッファ
    ofn.nMaxFileTitle     = 255;     // 文字列バッファのサイズ
    ofn.lpstrInitialDir   = NULL;
    ofn.lpstrTitle        = "動画ファイル(AVI)の選択";
    ofn.Flags             = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    ofn.nFileOffset       = 0;
    ofn.nFileExtension    = 0;
    ofn.lpstrDefExt       = "avi";
    ofn.lCustData         = 0;
    ofn.lpfnHook          = NULL;
    ofn.lpTemplateName    = NULL;
    // ダイアログを開く
    if(!GetOpenFileName(&ofn)) return FALSE;
    return TRUE;
}
//-----------------------------------------------------------------
// [保存]ファイルの選択
//-----------------------------------------------------------------
UINT SaveFile(LPTSTR lpFname)
{
    static OPENFILENAME ofn;
    TCHAR szFt[MAX_PATH];
    lpFname[0] = NULL;
    // ファイル[保存]ダイアログ設定
    ofn.lStructSize       = sizeof(OPENFILENAME);
    ofn.hwndOwner         = hAppWnd;
    ofn.hInstance         = NULL;
    ofn.lpstrFilter       =
        "Bitmap(*.bmp)\0*.bmp\0"
        "すべてのファイル(*.*)\0*.*\0\0";
    ofn.lpstrCustomFilter = NULL;
    ofn.nMaxCustFilter    = 0;
    ofn.nFilterIndex      = 1;       // フィルタの初期位置
    ofn.lpstrFile         = lpFname; // ファイル名用文字列バッファ
    ofn.nMaxFile          = 255;     // 文字列バッファのサイズ
    ofn.lpstrFileTitle    = szFt;
    ofn.nMaxFileTitle     = 255;     // 文字列バッファのサイズ
    ofn.lpstrInitialDir   = NULL;
    ofn.lpstrTitle        = "画像(BMP)の保存";
    ofn.Flags             = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
    ofn.nFileOffset       = 0;
    ofn.nFileExtension    = 0;
    ofn.lpstrDefExt       = "bmp";
    ofn.lCustData         = 0;
    ofn.lpfnHook          = NULL;
    ofn.lpTemplateName    = NULL;
    // ダイアログを開く
    if(!GetSaveFileName(&ofn)) return FALSE;
    return TRUE;
}
//-----------------------------------------------------------------
// ビットマップの保存
//-----------------------------------------------------------------
UINT SaveBMP(LPCTSTR lpFname,LPBYTE lpBuf)
{
    HANDLE hdlBmp;
    BITMAPFILEHEADER bfhBmp;
    LPBITMAPINFOHEADER bih = (LPBITMAPINFOHEADER)lpBuf;
    LONG offset = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
    LONG cpsize = bih->biClrUsed*sizeof(RGBQUAD);
    UINT bCnt = bih->biBitCount,bPln = bih->biPlanes;
    DWORD dwdPixelsSize,wSize;
    // 画像サイズ
    dwdPixelsSize = ((bih->biWidth*bCnt+31)&~0x1f)*bPln/8;
    dwdPixelsSize *= bih->biHeight;
    // ファイルを開く
    hdlBmp = CreateFile(lpFname,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,NULL);
    if(hdlBmp==INVALID_HANDLE_VALUE){
        MessageBox(NULL,"書込みに失敗しました",NULL,MB_OK);
        return FALSE;
    }
    // ヘッダ情報
    bfhBmp.bfType      = 'M'*256+'B';
    bfhBmp.bfSize      = offset + cpsize + dwdPixelsSize;
    bfhBmp.bfReserved1 = 0;
    bfhBmp.bfReserved2 = 0;
    bfhBmp.bfOffBits   = offset + cpsize;
    // 書込み
    dwdPixelsSize += sizeof(BITMAPINFOHEADER) + cpsize;
    WriteFile(hdlBmp,&bfhBmp,sizeof(BITMAPFILEHEADER),&wSize,NULL);
    WriteFile(hdlBmp,lpBuf,sizeof(BYTE)*dwdPixelsSize,&wSize,NULL);
    // 後片付け
    CloseHandle(hdlBmp);
    return TRUE;
}
//-----------------------------------------------------------------
// AVI 初期化
//-----------------------------------------------------------------
void AviInit()
{
    avi.in_file  = NULL;
    avi.in_video = NULL;
    avi.in_frame = NULL;
    avi.lpSrcFmt = NULL;
    avi.lpDecFmt = NULL;
    avi.lpSrc    = NULL;
    lpBMP        = NULL;
    avi.codec    = FALSE;
}
//-----------------------------------------------------------------
// AVIのオープン
//-----------------------------------------------------------------
int AviOpen()
{
    AVIFILEINFO pfi;
    LPBITMAPINFOHEADER bih;
    //--------------------------------------------------
    // Video for Windows(VFW) によるAVIのオープン
    //--------------------------------------------------
    if(aviLoad) AviClose();
    AVIFileInit();
    if(AVIFileOpen(&avi.in_file,avi.in_path,OF_READ,NULL)){
        TRACE("open err.\n");
        return FALSE;
    }
    //--------------------------------------------------
    // 映像情報
    //--------------------------------------------------
    AVIFileInfo(avi.in_file,&pfi,sizeof(AVIFILEINFO));
    if(AVIFileGetStream(avi.in_file,&avi.in_video,streamtypeVIDEO,0)){
        TRACE("stream err.\n");
        return FALSE;
    }
    // VIDEO ストリームを開く
    if(avi.in_video) {
        avi.in_frame = NULL;
        AVIStreamInfo(avi.in_video,&avi.info,sizeof(AVISTREAMINFO));
        // read format
        LONG len;
        AVIStreamFormatSize(avi.in_video,0,&len);
        avi.lpSrcFmt = (LPBITMAPINFOHEADER)GlobalAlloc(GPTR,len);
        AVIStreamReadFormat(avi.in_video,0,avi.lpSrcFmt,&len);
        // frame open
        avi.in_frame = AVIStreamGetFrameOpen(avi.in_video,NULL);
        if(avi.in_frame == NULL){
            if(!codecOpen()){
                MessageBox(NULL,"AVI未対応",0,0);
                return FALSE;
            }
        } else avi.codec = FALSE;
    } else return FALSE;
    //--------------------------------------------------
    // 映像情報
    //--------------------------------------------------
    if(avi.codec) bih = avi.lpDecFmt;
    else          bih = avi.lpSrcFmt;
    iWidth  = bih->biWidth;
    iHeight = bih->biHeight;
    avi.dwLength = AVIStreamLength(avi.in_video);
    iSize = ((iWidth*bih->biBitCount+31)&~0x1f)*bih->biPlanes/8*iHeight;
    avi.biSize = bih->biSize + bih->biClrUsed*sizeof(RGBQUAD);
    avi.SPF = (int)(1000.*avi.info.dwScale/(double)avi.info.dwRate);
    //--------------------------------------------------
    // ウィンドウ幅の設定
    //--------------------------------------------------
    set_window(bih);
    SetRect(&avi.dRgn,4,35,4+iWidth,35+iHeight);
    //--------------------------------------------------
    // 画像領域の確保
    //--------------------------------------------------
    if(avi.codec==FALSE){
        if(lpBMP) GlobalFree(lpBMP);
        lpBMP = (LPBYTE)GlobalAlloc(GPTR,avi.biSize+iSize);
    }
    AviReadFrame(0);
    // 1フレーム目の描画
    InvalidateRect(hAppWnd,&avi.dRgn,FALSE);
    //--------------------------------------------------
    // 再生位置,描画 の初期化
    //--------------------------------------------------
    avi.v_index = 0;
    aviLoad = TRUE;
    return TRUE;
}
//-----------------------------------------------------------------
// コーデックによるデコードの開始
//-----------------------------------------------------------------
int codecOpen()
{
    LONG lFmtLength,lFrames,biLeng;
    //--------------------------------------------------
    // get format size
    //--------------------------------------------------
    AVIStreamFormatSize(avi.in_video,0,&lFmtLength);
    if(avi.lpDecFmt) GlobalFree(avi.lpDecFmt);
    avi.lpDecFmt = (LPBITMAPINFOHEADER)GlobalAlloc(GPTR,lFmtLength);
    //--------------------------------------------------
    // read format
    //--------------------------------------------------
    LPBITMAPINFOHEADER s,d;
    s = avi.lpSrcFmt; d = avi.lpDecFmt;
    AVIStreamInfo(avi.in_video,&avi.info,sizeof(AVISTREAMINFO));
    lFrames = AVIStreamLength(avi.in_video);
    //--------------------------------------------------
    // set decode format
    //--------------------------------------------------
    memcpy(d,s,lFmtLength);
    d->biBitCount    = 24;
    d->biCompression = BI_RGB;
    d->biSize        = lFmtLength;
    biLeng = ((d->biWidth*d->biBitCount+31)&~0x1f)*d->biPlanes/8*d->biHeight;
    d->biSizeImage   = biLeng;
    //--------------------------------------------------
    // source size
    //--------------------------------------------------
    biLeng = ((s->biWidth*s->biBitCount+31)&~0x1f)*s->biPlanes/8*s->biHeight;
    avi.lLength    = biLeng;
    if(avi.info.dwSuggestedBufferSize)
        if(avi.info.dwSuggestedBufferSize < (unsigned)avi.lLength)
            avi.lLength = (LONG)avi.info.dwSuggestedBufferSize;
    // alloc size
    if(avi.lpSrc) GlobalFree(avi.lpSrc);
    if(lpBMP)     GlobalFree(lpBMP);
    avi.lpSrc = (LPBYTE)GlobalAlloc(GPTR,s->biSizeImage);
    lpBMP     = (LPBYTE)GlobalAlloc(GPTR,d->biSizeImage+lFmtLength);
    memcpy(lpBMP,d,lFmtLength);
    if(avi.lpSrc == NULL || lpBMP == NULL){ return FALSE; }
    //--------------------------------------------------
    // open the decompressor
    //--------------------------------------------------
    static char tag[4]="",buf[256];
    memcpy(tag,&avi.info.fccHandler,sizeof(DWORD));
    avi.hicd = ICDecompressOpen(ICTYPE_VIDEO,avi.info.fccHandler,s,d);
    if(!avi.hicd){ // cannot find codec
        sprintf(buf,"%s: cannot find codec",tag);
        MessageBox(NULL,buf,"AVI",0);
        return FALSE;
    }
    //--------------------------------------------------
    // start decompressing
    //--------------------------------------------------
    if(ICDecompressBegin(avi.hicd,avi.lpSrcFmt,avi.lpDecFmt))
        return FALSE;
    avi.codec = TRUE;
    return TRUE;
}
//-----------------------------------------------------------------
// フレームの取得
//-----------------------------------------------------------------
void AviReadFrame(int vidx)
{
    avi.v_index ++;
    if(avi.codec == FALSE){
        avi.lpSrc = (LPBYTE)AVIStreamGetFrame(avi.in_frame,vidx);
        CopyMemory(lpBMP,avi.lpSrc,avi.biSize+iSize);
    } else {
        AVIStreamRead(avi.in_video,vidx,1,avi.lpSrc,avi.lLength,NULL,NULL);
        LPBYTE dst = lpBMP + avi.lpDecFmt->biSize;
        ICDecompress(avi.hicd,0,avi.lpSrcFmt,avi.lpSrc,avi.lpDecFmt,dst);
        CopyMemory(lpBMP,avi.lpDecFmt,avi.lpDecFmt->biSize);
    }
}
//-----------------------------------------------------r------------
// AVI を閉じる
//-----------------------------------------------------------------
void AviClose()
{
    if(avi.codec){
        if(avi.lpSrc) { GlobalFree(avi.lpSrc); avi.lpSrc = NULL; }
        if(avi.lpDecFmt) { GlobalFree(avi.lpDecFmt); avi.lpDecFmt = NULL; }
        ICDecompressEnd(avi.hicd);
        ICClose(avi.hicd);
        avi.codec = FALSE;
    }
    if(avi.in_frame) {
        AVIStreamGetFrameClose(avi.in_frame); avi.in_frame = NULL;
    }
    if(avi.in_video) { AVIStreamRelease(avi.in_video); avi.in_video = NULL; }
    if(avi.in_file)  { AVIFileRelease(avi.in_file); avi.in_file = NULL; }
    if(avi.lpSrcFmt) { GlobalFree(avi.lpSrcFmt); avi.lpSrcFmt = NULL; }
    if(lpBMP)        { GlobalFree(lpBMP); lpBMP = NULL; }
    AVIFileExit();
}
//-----------------------------------------------------------------
// コマ送り
//-----------------------------------------------------------------
void AviNext()
{
    int vi,ret;
    TCHAR cbuf[256];
    // 読取/表示
    for(vi=avi.v_index;vi<avi.dwLength;vi++){
        AviReadFrame(vi);
        // 再描画
        InvalidateRect(hAppWnd,&avi.dRgn,FALSE);
        // タイトル
        wsprintf(cbuf,"[%s] frame %d/%d",avi.in_path,vi+1,avi.dwLength);
        SetWTitle(cbuf);
        ret = MessageBox(NULL, 
                         "Next:はい Prev:いいえ 停止:キャンセル","コマ送り",
                         MB_YESNOCANCEL);
        if(ret==IDNO){ vi-=2; if(vi<-1) vi=0; }
        if(ret==IDCANCEL) break;
    }
    if(vi==avi.dwLength-1) avi.v_index = 0;
}
//-----------------------------------------------------------------
// 連続再生
//-----------------------------------------------------------------
void AviView()
{
    if(vRun == FALSE){
        // 描画用スレッドの開始
        DWORD tid;
        vRun = TRUE;
        SetWindowText(hwB2,"停止");
        CreateThread(NULL, 0,
                     (LPTHREAD_START_ROUTINE)th_Proc,
                     NULL,0,&tid);
    } else {
        SetWindowText(hwB2,"再生");
        vRun = FALSE;
    }
}
//-----------------------------------------------------------------
// AVI 連続再生用スレッド
//-----------------------------------------------------------------
DWORD th_Proc()
{
    int vi; TCHAR cbuf[256];
    for(vi=avi.v_index;vi<avi.dwLength;vi++){
        if(vRun == FALSE) break;
        AviReadFrame(vi);
        // 再描画
        InvalidateRect(hAppWnd,&avi.dRgn,FALSE);
        // タイトル
        wsprintf(cbuf,"%s -- frame %d/%d [%s]",
                 avi.in_path,vi+1,avi.dwLength,getfps());
        SetWTitle(cbuf);
        // 待機時間
        Sleep(avi.SPF);
    }
    // 再生終了
    if(vi==avi.dwLength) avi.v_index = 0;
    SetWindowText(hwB2,"再生");
    vRun = FALSE;
    return 0;
}
inserted by FC2 system