Created
May 27, 2011 10:51
-
-
Save kimoto/995031 to your computer and use it in GitHub Desktop.
無圧縮AVIを、任意のコーデックで圧縮するコード
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 無圧縮AVIファイル"input.avi"を | |
* GUIで選択した圧縮形式で圧縮して、"output.avi" に出力するだけのプログラム | |
*/ | |
#include <Windows.h> | |
#include <tchar.h> | |
#include <Vfw.h> | |
#pragma comment(lib, "vfw32.lib") | |
#include <GdiPlus.h> | |
#pragma comment(lib, "gdiplus.lib") | |
using namespace ::Gdiplus; | |
/* | |
* デバッグ情報出力用関数 | |
*/ | |
#define TRACE_BUFFER_SIZE 256 | |
void trace(LPCTSTR format, ...) | |
{ | |
#ifdef _DEBUG | |
va_list arg; | |
va_start(arg, format); | |
TCHAR buffer[TRACE_BUFFER_SIZE]; | |
::_vsnwprintf_s(buffer, TRACE_BUFFER_SIZE, _TRUNCATE, format, arg); | |
::OutputDebugString(buffer); | |
va_end(arg); | |
#endif | |
} | |
/* | |
* エラー出力用のメッセージボックス | |
* 可変引数で任意のフォーマットで出力できます | |
*/ | |
#define ERRMSGBOX_BUFFER_SIZE 256 | |
void ErrorMessageBox(LPCTSTR format, ...) | |
{ | |
va_list arg; | |
va_start(arg, format); | |
TCHAR buffer[ERRMSGBOX_BUFFER_SIZE]; | |
::_vsnwprintf_s(buffer, ERRMSGBOX_BUFFER_SIZE, _TRUNCATE, format, arg); | |
::MessageBox(NULL, buffer, L"Error", MB_OK); | |
va_end(arg); | |
} | |
/* | |
* 最後に発生したエラーコードのエラー内容を | |
* メッセージボックスで表示します | |
*/ | |
void ShowLastError(void){ | |
LPVOID lpMessageBuffer; | |
FormatMessage( | |
FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
FORMAT_MESSAGE_FROM_SYSTEM, | |
NULL, | |
GetLastError(), | |
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // デフォルト ユーザー言語 | |
(LPTSTR) &lpMessageBuffer, | |
0, | |
NULL ); | |
MessageBox(NULL, (LPCWSTR)lpMessageBuffer, TEXT("Error"), MB_OK); | |
//... 文字列が表示されます。 | |
// システムによって確保されたバッファを開放します。 | |
LocalFree( lpMessageBuffer ); | |
} | |
class AVIFile | |
{ | |
private: | |
PAVIFILE pavi; | |
PAVISTREAM pstm; | |
LPBITMAPINFOHEADER pbmih; | |
PGETFRAME pfrm; | |
public: | |
AVIFile(LPCTSTR filename) | |
{ | |
::AVIFileInit(); | |
// AVIファイルのオープン | |
if( ::AVIFileOpen(&this->pavi, filename, OF_READ | OF_SHARE_DENY_NONE, NULL) != 0 ){ | |
trace(L"AVIFileOpen Error!\n"); | |
return; | |
} | |
// AVIファイルから、streamを取得します | |
if( ::AVIFileGetStream(pavi, &pstm, 0, 0) != 0 ){ | |
trace(L"AVIFileGetStream Error!\n"); | |
return; | |
} | |
// stream内にはbmpが圧縮されてるので | |
// 展開する必要があります | |
// そのフォーマットなんかを取得する関数 | |
pfrm = ::AVIStreamGetFrameOpen(pstm, NULL); | |
if(pfrm == NULL){ | |
trace(L"AVIStreamGetFrameOpen Error!\n"); | |
return; | |
} | |
} | |
~AVIFile() { | |
if(pfrm){ | |
if( ::AVIStreamGetFrameClose(pfrm) != 0 ){ | |
::trace(L"AVIStreamGetFrameClose Error!\n"); | |
return; | |
} | |
} | |
if(pstm) | |
::AVIStreamRelease(pstm); | |
if(pavi) | |
::AVIFileRelease(pavi); | |
::AVIFileExit(); | |
} | |
LPBITMAPINFOHEADER getFrame(long pos) | |
{ | |
return (LPBITMAPINFOHEADER)::AVIStreamGetFrame(pfrm, pos); | |
} | |
// 指定されたフレームをHBITMAP形式で返却します | |
// 不要になったら::DeleteObjectしてください | |
HBITMAP getFrameBitmap(long pos) | |
{ | |
LPBITMAPINFOHEADER lpbmi = this->getFrame(pos); | |
HWND hWnd = ::GetDesktopWindow(); | |
HDC hdc = ::GetDC(hWnd); // 汎用のDCを取得 | |
HDC myhdc = ::CreateCompatibleDC(hdc); | |
HBITMAP bitmap = ::CreateCompatibleBitmap(hdc, lpbmi->biWidth, lpbmi->biHeight); | |
HBITMAP oldBitmap = (HBITMAP)::SelectObject(myhdc, bitmap); | |
// 転送 | |
::StretchDIBits(myhdc, 0, 0, lpbmi->biWidth, lpbmi->biHeight, | |
0, 0, lpbmi->biWidth, lpbmi->biHeight, | |
lpbmi + 1, (LPBITMAPINFO)lpbmi, DIB_RGB_COLORS, SRCCOPY); | |
::SelectObject(myhdc, oldBitmap); | |
//::DeleteObject(bitmap); | |
::DeleteDC(myhdc); | |
::ReleaseDC(hWnd, hdc); | |
return bitmap; | |
} | |
long length() | |
{ | |
return ::AVIStreamLength(pstm); | |
} | |
long getStartIndex() | |
{ | |
return ::AVIStreamStart(pstm); | |
} | |
AVIFILEINFO getInfo() | |
{ | |
AVIFILEINFO info; | |
::AVIFileInfo(pavi, &info, sizeof(AVIFILEINFO)); | |
return info; | |
} | |
}; | |
// AVIファイルのすべてのフレームをPNG画像に変換します | |
int APIENTRY _tWinMain(HINSTANCE hInstance, | |
HINSTANCE hPrevInstance, | |
LPTSTR lpCmdLine, | |
int nCmdShow) | |
{ | |
::AVIFileInit(); | |
// 既存の無圧縮AVIを読み込んで | |
// ファイル情報を元に、圧縮方法について選定します | |
AVIFile avifile(L"input.avi"); | |
AVIFILEINFO info = avifile.getInfo(); | |
int width = info.dwWidth; | |
int height = info.dwHeight; | |
int sizeimage = height * ((3 * width + 3) / 4) * 4; | |
BITMAPINFOHEADER bmih={sizeof(BITMAPINFOHEADER),width,height,1,24,BI_RGB,sizeimage,0,0,0,0}; | |
AVISTREAMINFO si; | |
ZeroMemory(&si, sizeof(AVISTREAMINFO)); | |
si.fccType = streamtypeVIDEO; | |
si.fccHandler = comptypeDIB; | |
si.dwScale = info.dwScale; | |
si.dwRate = info.dwRate; | |
si.dwLength = info.dwLength; | |
si.dwQuality = -1; | |
// ユーザーに圧縮フォーマットを選択させます | |
::AVICOMPRESSOPTIONS opt; | |
::COMPVARS cv; | |
memset(&cv, 0, sizeof(COMPVARS)); | |
cv.cbSize = sizeof(COMPVARS); | |
cv.dwFlags = ICMF_COMPVARS_VALID; | |
cv.fccHandler = comptypeDIB; | |
cv.lQ = ICQUALITY_DEFAULT; | |
if( !::ICCompressorChoose(NULL, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, | |
&bmih, NULL, &cv, NULL) ){ | |
::ErrorMessageBox(L"選択されていません"); | |
return 0; | |
} | |
// 選択された圧縮フォーマットに基づく設定を変更します | |
si.fccHandler = cv.fccHandler; | |
opt.fccType = streamtypeVIDEO; | |
opt.fccHandler = cv.fccHandler; | |
opt.dwKeyFrameEvery = cv.lKey; | |
opt.dwQuality = cv.lQ; | |
opt.dwBytesPerSecond = cv.lDataRate; | |
opt.dwFlags=(cv.lDataRate>0?AVICOMPRESSF_DATARATE:0) | |
|(cv.lKey>0?AVICOMPRESSF_KEYFRAMES:0); | |
opt.lpFormat=NULL; | |
opt.cbFormat=0; | |
opt.lpParms=cv.lpState; | |
opt.cbParms=cv.cbState; | |
opt.dwInterleaveEvery=0; | |
// ===================== | |
// AVIの書き込み処理 | |
// ===================== | |
PAVIFILE pavi; | |
PAVISTREAM pstm; | |
// AVIファイルをオープンします | |
if( ::AVIFileOpen(&pavi, L"output.avi", OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE,NULL) != 0) | |
return 0; | |
// AVIファイル書き込み用のVIDEOストリームを作成します | |
if( ::AVIFileCreateStream(pavi, &pstm, &si) != 0) | |
return 0; | |
trace(L"create stream\n"); | |
// 圧縮済みデータ格納用のストリームを作成します(ptmp) | |
PAVISTREAM ptmp; | |
if( ::AVIMakeCompressedStream(&ptmp, pstm, &opt, NULL) != AVIERR_OK) | |
return 0; | |
// 圧縮済みデータ格納用のストリームのデータ情報を設定します | |
if( ::AVIStreamSetFormat(ptmp, 0, &bmih, sizeof(BITMAPINFOHEADER)) != 0){ | |
return 0; | |
} | |
// 入力AVIデータのすべてのフレームを、 | |
// 圧縮済みAVIストリームにすべて書き込みます | |
trace(L"avistream set format\n"); | |
for (long i=0;i<avifile.length();i++) { | |
LPBITMAPINFOHEADER lpbmi = avifile.getFrame(i); | |
if (AVIStreamWrite(ptmp,i,1,lpbmi + 1,lpbmi->biSizeImage,AVIIF_KEYFRAME,NULL,NULL)!=0) | |
return 0; | |
} | |
// 使用済みストリームや、ハンドルをすべて解放します | |
::AVIStreamRelease(ptmp); | |
::AVIStreamRelease(pstm); | |
::AVIFileRelease(pavi); | |
::ICCompressorFree(&cv); | |
::AVIFileExit(); | |
trace(L"exit\n"); | |
::ErrorMessageBox(L"出力しました"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment