C++でAVIファイル作成してみた

今回は、C++でAVIファイルを作成してみました。AVIファイルを作成するには次の手順が必要です。
1. ストリーム作成
2. サンプル書き込み
これが主なAVIファイル作成の手順です。

では、早速やってみたいと思います。


```CreateAVI.cpp

#include "stdafx.h"
#include "Win32Project11.h"
#include <windows.h>
#include <vfw.h>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <tchar.h>

#pragma comment (lib, "winmm.lib")
#pragma comment (lib, "vfw32.lib")

#define ID_START 100
#define ID_END 200
#define LENG 1000
#define PIXELS 10
#define WIDTH 160
#define HEIGHT 120
#define LINE ((((WIDTH)*24+31)&~31)/8)
#define SIZEIMAGE (LINE*(HEIGHT))
#define PI 3.1415926535

using namespace std;
HINSTANCE hInst;


LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	TCHAR szWindowClass[] = TEXT("Test");
	
	MSG msg;
	WNDCLASSEX wc;
	HWND hwnd;

	wc.cbClsExtra = 0;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_DESKTOP + 1);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hIcon = NULL;
	wc.hIconSm = NULL;
	wc.hInstance = hInstance;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = szWindowClass;
	wc.lpszMenuName = NULL;
	wc.style = 0;

	if (!RegisterClassEx(&wc))
	{
		MessageBox(NULL, TEXT("処理に失敗しました！"), NULL, NULL);
	}

	hInst = hInstance;
    hwnd = CreateWindowEx(0, szWindowClass, szWindowClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL);
	
	if (!hwnd)
	{
		MessageBox(NULL, TEXT("ウィンドウの作成に失敗しました！"), NULL, NULL);
	}

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	
	return 0;
} 
```
まずは、必要なヘッダーをインクルードして、WINAPI関数で、Windowを作成します。こちらはC++では基本のコードですので説明は省きます。気になる方はC++ Window作成とかでググってみて下さい。


```CreateAVI.cpp

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){

	static HWND hwndButtonStart = NULL;
	static HWND hwndButtonStop = NULL;

	PAVISTREAM PAvistream;
	PAVIFILE PFaile;
    AVISTREAMINFO SInfo;
	BITMAPINFOHEADER BMi;
	BYTE BBit[SIZEIMAGE];
	int i;
	int j;
	int s;

	ZeroMemory(&SInfo, sizeof(AVISTREAMINFO));
	SInfo.fccType = streamtypeVIDEO;
	SInfo.fccHandler = comptypeDIB;
	SInfo.dwScale = 1;
	SInfo.dwRate = 2;
	SInfo.dwLength = 10;
	SInfo.dwQuality = (DWORD)-1;
	SetRect(&SInfo.rcFrame, 0, 0, 32, 32);

	ZeroMemory(&BMi, sizeof(BITMAPINFOHEADER));
	BMi.biSize = sizeof(BITMAPINFOHEADER);
	BMi.biWidth = 32;
	BMi.biHeight = 32;
	BMi.biPlanes = 1;
	BMi.biBitCount = 24;
	BMi.biCompression = BI_RGB;
	
	AVIFileInit();
	
	switch (message)
	{
	case WM_CREATE:
	hwndButtonStart = CreateWindowEx(0, TEXT("BUTTON"), TEXT("キャプチャON"), WS_CHILD | WS_VISIBLE, 10, 20, 130, 30, hwnd, (HMENU)ID_START, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
	hwndButtonStop = CreateWindowEx(0, TEXT("BUTTON"), TEXT("キャプチャOFF"), WS_CHILD | WS_VISIBLE, 10, 70, 130, 30, hwnd, (HMENU)ID_END, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
	break;

	case WM_COMMAND:
  
		if (LOWORD(wParam) == ID_START)
		{
			if (AVIFileOpen(&PFaile, TEXT("TEST.AVI"), OF_CREATE | OF_WRITE, NULL) != 0)
			{
				MessageBox(NULL, TEXT("AVIFILEを開けませんでした！"), NULL, NULL);
			}
			else {


				MessageBox(NULL, TEXT("AVIFILEを開けました！"), NULL, NULL);
			}

			if (AVIFileCreateStream(PFaile, &PAvistream, &SInfo) != 0) {
				MessageBox(NULL, TEXT("ストリームの作成に失敗しました！"), NULL, NULL);
			}
			else {
				MessageBox(NULL, TEXT("ストリームの作成に成功しました！"), NULL, NULL);
			}

			if (AVIStreamSetFormat(PAvistream, 0, &BMi, sizeof(BITMAPINFOHEADER)) != 0)
			{
				MessageBox(NULL, TEXT("ストリームのセットに失敗しました！"), NULL, NULL);
			}
			else {
				MessageBox(NULL, TEXT("ストリームのセットに成功しました！"), NULL, NULL);
			}

			for (i = 0; i < LENG; i++) {
				for (j = 0; j < PIXELS; j++) {
					s = (int)(cos(PI * 2 * j / PIXELS)*min(WIDTH, HEIGHT)*(i*PIXELS + j)
						/ (LENG*PIXELS * 2) + WIDTH / 2) * 3
						+ (int)(sin(PI * 2 * j / PIXELS)*min(WIDTH, HEIGHT)*(i*PIXELS + j)
							/ (LENG*PIXELS * 2) + HEIGHT / 2)*LINE;
					BBit[s] = BBit[s + 1] = BBit[s + 2] = 0xff;
				}

				if (AVIStreamWrite(PAvistream, i, 1, BBit, SIZEIMAGE, AVIIF_KEYFRAME, NULL, NULL) != 0) {
					MessageBox(NULL, TEXT("ストリームの書き込みに失敗しました！"), NULL, NULL);
				}
				else {
					MessageBox(NULL, TEXT("ストリームの書き込みに成功しました！"), NULL, NULL);
					AVIStreamRelease(PAvistream);
					AVIFileRelease(PFaile);
					AVIFileExit();
					return 0;
				}
			   }
			  }

if (LOWORD(wParam) == ID_END){
        MessageBox(NULL, TEXT("オフボタンは実装されていません！"), NULL, NULL);
}
        break;

	   default:
		 return DefWindowProc(hwnd, message, wParam, lParam);
		break;
	}

	return 0;
}
```

基本的な流れとしては、コールバック関数のWndProc関数に処理をガリガリと書いていく感じです。関数の最初に必要な変数等を書いておきます。次は、AVIFileOpen関数でサンプルを書き込む為のAVIファイルを作成します。次に、AVICreateStream関数で先程作成したAVIファイルと関連付けをしてそのファイルにストリームを出力します。AVICreateStream関数の第一引数で、先程作成したAVIファイルが指定出来ます。次にAVIStreamSetFormatでビットイメージをセットし、AVIStreamWriteで書き込んでいくという内容になります。


#まとめ
本当は、AVIファイルの作成だけではなく、デスクトップを簡単にレコード出来る機能も実装しようと思っていたのですが、仕事が忙しく途中で諦めました(笑)、また、時間があればこの続きをやってみようと思います。それでは！