C++でAVIを出力する実験をしています。無圧縮なので高解像度の本編では使えないですが、動画内のアクセントとなるアニメーションや特殊効果程度なら応用例があると考えます。WindowsのGDIでグラフなどを描画するスキルが有ればそれをそのまま動画制作に応用可能です。以下のソースはG++でコンパイルできます。(Windows APIを使ってるので残念ながらWindows専用です。)
- #define _UNICODE //ワイド文字列 (Unicode) 対応
- #include <windows.h>
- #include <vfw.h>
- #include <sstream>
- #include <string>
- /********************************************************************
- 実行すると100までカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
- g++ .\avisample001.cpp -mwindows -lvfw32 -municode -o avisample001
- *********************************************************************/
- int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
- {
- const int width = 640; //画面サイズフレームレートなどを設定
- const int height = 560;
- const int fps = 60;
- const int frames = 1200;
- PAVIFILE pfile;
- PAVISTREAM pavi;
- AVISTREAMINFO si;
- LPAVISTREAMINFO lpsi = &si;
- LPVOID lpBits;
- BITMAPINFOHEADER bmiHeader;
- AVIFileInit();
- if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
- MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
- AVIFileExit();
- return 0;}
- ZeroMemory(&si, sizeof(AVISTREAMINFO));
- si.fccType = streamtypeVIDEO;
- si.fccHandler = comptypeDIB;
- si.dwScale = 1;
- si.dwRate = fps;
- si.dwLength = 0;
- si.dwQuality = (DWORD)-1;
- SetRect(&si.rcFrame, 0, 0, width, height);
- if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
- MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
- AVIFileRelease(pfile);
- AVIFileExit();
- return 0;}
- ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
- bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmiHeader.biWidth = lpsi->rcFrame.right;
- bmiHeader.biHeight = lpsi->rcFrame.bottom;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = 24;
- bmiHeader.biCompression = BI_RGB;
- bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
- AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
- //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
- HDC hdc = CreateCompatibleDC(NULL);
- HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
- HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
- SetTextColor(hdc, RGB(255, 255, 255));
- HGDIOBJ hFont = CreateFontW(100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
- CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"UI Gothic");
- HGDIOBJ hFontOld = SelectObject(hdc, hFont);
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
- HBRUSH hPrevBrush =(HBRUSH)SelectObject(hdc,hBrush);
- SetBkMode(hdc, TRANSPARENT);
- bool isTop = true; //裏表フラグ
- for (int fCnt = 0; fCnt < frames; fCnt++) {
- FillRect(hdc, &lpsi->rcFrame, (HBRUSH)GetStockObject(BLACK_BRUSH)); //背景を黒で塗る
- std::wstringstream wss;
- wss << fCnt;
- std::wstring buf = wss.str();
- const int size = width < height?width:height; //高さと幅の短い方を選ぶ
- const int c_width = size/10; //円の幅を調整
- const int div = 59; //円を分割する数
- const float step = (float)360 / div; //分割された度数
- const float seg = step / 2; //空白部と実部の割合(数字が大きいほど実部が減る)
- const int c_x = width / 2; //円の中心座標
- const int c_y = height /2;
- const int radius = size / 2 - size / 20; //余白
- const int l_begin = isTop?0:fCnt%(div+1);
- const int l_end = isTop?fCnt%(div+1):div;
- for (int j = l_begin;j<l_end;j++){
- BeginPath(hdc);
- AngleArc(hdc,c_x,c_y,radius,step*j,0);
- EndPath(hdc);
- BeginPath(hdc);
- AngleArc(hdc,c_x,c_y,radius,step*j,seg);
- AngleArc(hdc,c_x,c_y,radius-c_width,step*j+seg,-seg);
- CloseFigure(hdc);
- EndPath(hdc);
- FillPath(hdc);
- }
- DrawText(hdc, buf.c_str(), -1, &lpsi->rcFrame, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
- if(fCnt%(div+1) == div){
- isTop = !isTop; //裏表逆転
- }
- }
- SelectObject(hdc,hPrevBrush);
- DeleteObject(hBrush);
- SelectObject(hdc, hFontOld);
- DeleteObject(hFont);
- SelectObject(hdc, hbmpMemPrev);
- DeleteObject(hbmpMem);
- DeleteDC(hdc);
- AVIStreamRelease(pavi);
- AVIFileRelease(pfile);
- AVIFileExit();
- MessageBox(NULL, L"Done.", L"OK", MB_OK);
- return 0;
- }