メディア コントロール インタフェース (MCI) を用いたメモリ上のムービー再生

プロジェクトダウンロード(VC++2005)

【プログラム主要部分(MemoryAviPlayback_mci.cpp)】


// MemoryAviPlayback_mci.cpp : MCI を使ってメモリ上のAVIファイルを再生する。

#include "stdafx.h"
#include <vfw.h>
#include <mmreg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <crtdbg.h>
#include <TCHAR.h>

#pragma comment (lib, "winmm.lib")
#pragma comment (lib, "vfw32.lib")
#include "MemoryAviPlayback_mci.h"

#define MAX_LOADSTRING 100

static char * g_lpData = NULL;
static long    g_cfileSize;

// グローバル変数:
HINSTANCE hInst;                                // 現在のインターフェイス
// このコード モジュールに含まれる関数の宣言を転送します:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK IOProc(LPMMIOINFO lpMMIOInfo, UINT uMessage, LPARAM lParam1, LPARAM lParam2);

CRITICAL_SECTION    g_csSema;
BOOL    g_bRepeat = FALSE;
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX); 
    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = _T("avi realtime audio stream");
    wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassEx(&wcex);

    InitializeCriticalSection(&g_csSema);
    HWND hWnd;
    hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wcex.lpszClassName,_T("avi realtime audio stream"),
                WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
                CW_USEDEFAULT,0,640,480,NULL,NULL,hInstance,NULL);
    if( !hWnd )
        return FALSE;

    RECT    bounds,client;
    GetWindowRect(hWnd,&bounds);
    GetClientRect(hWnd,&client);
    MoveWindow(hWnd,bounds.left,bounds.top,
        640 * 2 - client.right,
        480 * 2 - client.bottom,
        false );

    ShowWindow( hWnd, nCmdShow );
    UpdateWindow( hWnd );

    //    ファイル読み込み
    struct    _stat    status;
    if (0 == _tstat(_T("test.avi"),&status)){
        g_cfileSize = status.st_size;
        g_lpData = new char[g_cfileSize];
        FILE    *fp = fopen(_T("test.avi"),_T("rb"));
        if (fp != NULL){
            fread(g_lpData,g_cfileSize,1,fp);
            fclose(fp);
        }
        //    mci:カスタムIOProc のインストール
        mmioInstallIOProc(mmioFOURCC('M', 'E', 'V', ' '), (LPMMIOPROC)IOProc,
                            MMIO_INSTALLPROC | MMIO_GLOBALPROC);

        //    再生開始
        mciSendString("open test.MEV+ type avivideo alias vp01",NULL,0,NULL);
        TCHAR    tmp[MAX_PATH];
        _stprintf_s(tmp,MAX_PATH,_T("window vp01 handle %d"),(DWORD)hWnd);
        
        mciSendString(tmp,NULL,0,NULL);
        mciSendString("play vp01 notify",NULL,0,hWnd);
        g_bRepeat = true;
    }else{
        DestroyWindow(hWnd);
    }

    // メイン メッセージ ループ:
    MSG        msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    g_bRepeat = false;
    EnterCriticalSection(&g_csSema);
    if (g_lpData != NULL){
        mciSendString("close vp01",NULL,0,NULL);
        mmioInstallIOProc(mmioFOURCC('M', 'E', 'V', ' '), NULL,MMIO_REMOVEPROC);
        delete    g_lpData;
    }

    LeaveCriticalSection(&g_csSema);
    return (int)msg.wParam;
}

//
//    関数:WndProc
//    説明:ウインドウに渡されたイベントのハンドラ
//
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{

    switch (message){
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        case MM_MCINOTIFY:
            //    とりあえずループ再生専用
            if (g_bRepeat)
                mciSendString("play vp01 from 0 notify",NULL,0,hWnd);
            return DefWindowProc(hWnd, message, wParam, lParam);

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return    0;
}


//
//    mmio: IOProc
//
LRESULT CALLBACK IOProc(LPMMIOINFO lpMMIOInfo, UINT uMessage, LPARAM
lParam1, LPARAM lParam2)
{
  static BOOL alreadyOpened = FALSE;

  switch (uMessage) {
  case MMIOM_OPEN:
      if (alreadyOpened)
          return 0;
      alreadyOpened = TRUE;

      lpMMIOInfo->lDiskOffset = 0;
      return 0;

   case MMIOM_CLOSE:
       return 0;

   case MMIOM_READ:{
            LPARAM    dataRead = 0;
               EnterCriticalSection(&g_csSema);
            if (g_lpData != NULL){
                dataRead = lParam2;
                memcpy((void *)lParam1, g_lpData+lpMMIOInfo->lDiskOffset, lParam2);
                lpMMIOInfo->lDiskOffset += (LONG)lParam2;
                dataRead = lParam2;
            }
            LeaveCriticalSection(&g_csSema);
            return (dataRead);
        }
   case MMIOM_SEEK:
       switch (lParam2) {
       case SEEK_SET:
           lpMMIOInfo->lDiskOffset = (LONG)lParam1;
           break;

       case SEEK_CUR:
           lpMMIOInfo->lDiskOffset += (LONG)lParam1;
           break;

       case SEEK_END:
           lpMMIOInfo->lDiskOffset = g_cfileSize - lParam1;
           break;
       }
       return lpMMIOInfo->lDiskOffset;

   default:
       return -1;
   }
}

 

 Windows マルチメディアAPI では、カスタム入出力プロシージャが登録 できるようになっています。mmioInstallIOProc関数を使って カスタム入出力プロシージャを登録すれば、ファイルからの読み込みのしくみを オーバーライドできるので、こちらで再生すれば、メモリ上の AVI ファイルを 再生できることになります。
 ここでは、簡単に、MCI コマンド(リスト内の青字部分)を使って、AVIファイルを再生させています。
ゲーム等での実装を考えると実用性はありませんが、とりあえず再生できました・・・・。

戻る