2007年4月24日火曜日

全画面表示

スライドショーは全画面表示にしたいのだけど、やりかたがわからない。

ShowWindow(hWnd, SW_SHOWMAXIMIZED);

で全画面になると思っていたけど、そうならなかった。
画面上部のタイトルバーと、下部のメニューバーは表示されてしまう。
メニューバーの表示を消すのにメニューの登録コードを全部削ったらメニューの表示はされなくなった。でもたまにSIPの選択部分だけ表示されたりする
あと、メニューがないのでソフトキーの受け取り方も分からない....

2007年4月23日月曜日

UIを作る

スライドショーの動きは出来てきたので、ユーザーインターフェイスを作ろうと思う
とりあえずカーソルキーで表示を進めたり、戻したりが出来るようにする

カーソルキーの状態はWM_KEYDOWNメッセージで取得することが出来る
wParamに押されたキーのコードが入る
カーソルの真ん中のボタンのコードが分からなかったので押して調べてみたらPROCESSKEYの後にVK_RETURNが届いた
VK_RETURNを処理しとけばいいかな


#define VK_RETURN 0x0D
#define VK_LEFT 0x25
#define VK_UP 0x26
#define VK_RIGHT 0x27
#define VK_DOWN 0x28
#define VK_PROCESSKEY 0xE5

2007年4月22日日曜日

Athlon64X2を買ってきた

このまえのAthlonの値下げ以来気になっていた64X2を買った
Intelも値下げするそうだが、長年AMDを信奉してきたのでAthlonを買うことにした。AMDにはがんばって欲しい。と言っても買ったのは3800+で98000円だけど

マザーボードはASUS M2A-VM HDMI 12800円を買った。メモリは1GByte7000円位のノーブランド。
ハードディスク、DVDドライブ、筐体と電源は使ってないmATX用のがあったので、総額3万円くらいですんだよ!

と思ったら、手持ちの電源のコネクタがMBに合わない...いつのまにATX電源のpin数が20Pinから24Pinに変わっていたらしい。知らなかった
あわててPCショップに電源を買いに行ったら、20Pinから24Pinの変換ケーブルを売っていたので購入。610円で済んだ。家の近所にPCショップがあってよかった。値段もほぼ秋葉価格なので、最近はあ秋葉に行くこともなくなってしまった。

2007年4月19日木曜日

Threadを使う

写真の表示がスムーズに動くようになったので、写真の切り替えがもたつかないようにマルチスレッド化した。
写真の表示中に、裏で次の写真ファイルを読み込む処理をする。

Threadの開始は

HANDLE LoaderHandle = CreateThread(NULL,0,LoaderThreead,0,0,(LPDWORD)&ThreadID);

最初の NULL はセキュリティ属性、指定しないのでNULL
次はThreadのスタックサイズ、指定しないので0
3番目は実行する関数名、LoaderThreead
4番目は実行関数に渡すパラメータ、指定しないので0
5番目はThreadをすぐ実行するか?サスペンドした状態のThreadを作るか?を指定する。すぐに実行する場合は0を指定、CREATE_SUSPENDEDで停止状態のThreadが作られる
停止中のThreadはResumeThreadで再開できる。実行中のThreadをSuspendThreadで停止することも出来る

LoaderThreead関数が終了するとThreadも終了するが、CloseHandle()をしないとThreadのオブジェクトが残ってメモリリークとなる


マルチスレッド化したのでレンダリング処理(RenderThread)と写真のロード処理(LoaderThread)が独立して動くようになるので、2つのthread間で協調して動かせるようにEventを使った

具体的には、

  1. RenderThreadは次の写真が必要になるとLoaderThreadが写真のロード処理が完了するまでThreadを停止して待つ
  2. LoaderThreadは写真のロードが完了したことをRenderThreadに伝え、さらに次の写真を読み込む要求がRenderThreadから来るまでThreadを停止して待つ
  3. RenderThreadは写真の表示の合間に次の写真をロードするようにLoaderThreadに要求を出す


といった具合にお互いの状態を連絡しあって処理をする事を同期処理というらしい

この同期にEventという仕組みがOSに用意されている。Eventの説明は検索するといっぱいヒットするので省略

Eventを使うメリットは処理待ちの間Threadが停止するので、ポーリングするより余計なCPUパワーを消費しないで済むことだと思う


Eventを使用するにはCreateEventでイベントを作成してHANDLEを取得する

m_LoadRequest = CreateEvent(NULL, FALSE, FALSE, TEXT("LOADREQUEST"));


Threadと同様にハンドルをクローズする必要がある

CloseHandle(m_LoadRequest);


Eventを待つときは

WaitForSingleObject(m_LoadRequest,INFINITE);


Eventをセットするときは


SetEvent(m_LoadRequest);


今回はイベントを自動リセットとしたのでResetEventを呼ぶ必要は無い

ThreadとEvent関連のソース抜粋


bool m_threadEnd;
HANDLE m_RenderHandle;
HANDLE m_LoaderHandle;
HANDLE m_UpdateEvent;
HANDLE m_LoadCmplete;
HANDLE m_LoadRequest;

void OnCreate(HWND hWnd)
{
WORD ThreadID;

gFrame = 0;
gNextFrame = 0;
pictnow = NULL;
pictload = NULL;

m_LoadRequest = CreateEvent(NULL, FALSE, FALSE, TEXT("LOADREQUEST")); // 自動リセット reset状態
m_LoadCmplete = CreateEvent(NULL, FALSE, FALSE, TEXT("LOADEREVENT")); // 自動リセット reset状態
m_UpdateEvent = CreateEvent(NULL, FALSE, TRUE , TEXT("UPDATEEVENT")); // 自動リセット
m_LoaderHandle = CreateThread(NULL,0,LoaderThreead,0,0,(LPDWORD)&ThreadID);
m_RenderHandle = CreateThread(NULL,0,RenderThreead,0,0,(LPDWORD)&ThreadID);
SetThreadPriority(m_RenderHandle,THREAD_PRIORITY_TIME_CRITICAL);
}

void OnDestroy(HWND hWnd)
{
m_threadEnd = TRUE;
// 停止中のスレッドに終了を伝える為にeventをセットする
SetEvent(m_UpdateEvent);
SetEvent(m_LoadRequest);
// ローダースレッドが処理を完了するまで待つ
WaitForSingleObject(m_LoadCmplete,INFINITE);
CloseHandle(m_LoadCmplete);
CloseHandle(m_LoaderHandle);
CloseHandle(m_RenderHandle);
CloseHandle(m_UpdateEvent);
CloseHandle(m_LoadRequest);
}

DWORD WINAPI RenderThreead(LPVOID lpParameter)
{
int frame = -1;
int render_frame = -1;

while(m_threadEnd!=TRUE)
{
// 描画するフレームを決定
if(frame<gFrame)
{
// フレーム更新
frame = gFrame;
}
else
{
// 更新前だが次のフレームを用意しておく
frame = gFrame +1;
}


if(frame>render_frame)
{
render_frame = frame;
if((pictnow==NULL)||(pictnow->IsEnd(frame)))
{
SetThreadPriority(m_LoaderHandle,THREAD_PRIORITY_ABOVE_NORMAL);
WaitForSingleObject(m_LoadCmplete,INFINITE);
if(pictnow)
delete pictnow;
if(pictload==NULL)
break;
pictnow = pictload;
pictload = NULL;

// ローダーを再開する(再開前にスレッドの優先度を下げておく)
SetThreadPriority(m_LoaderHandle,THREAD_PRIORITY_IDLE);
SetEvent(m_LoadRequest);
}
pictnow->Draw(pScreen->m_Buf,pScreen->m_dspW,pScreen->m_dspH,render_frame);
}
else
{
WaitForSingleObject(m_UpdateEvent,INFINITE);
}
}
return 0;
}

DWORD WINAPI LoaderThreead(LPVOID lpParameter)
{
while(m_threadEnd!=TRUE)
{
// 写真のファイル名を取得
TCHAR *fname = FindFile();
if(fname ==NULL)
{
// 取得できなかった
// SendMessage();
pictload = NULL;
break;
}

// ファイルを読み込む
pictload = new CPicture();
if(!pictload->LoadPicture(fname,gNextFrame))
{
// ファイルが読めなかった
continue;
}

// 次のファイルの開始フレームを決定
gNextFrame = pictload->frame_end;

// RenderThread にロード完了したことを伝える
SetEvent(m_LoadCmplete);

// さらに次のファイルを読み込みを開始できるまで待つ
WaitForSingleObject(m_LoadRequest,INFINITE);

}

// スレッド終了待ちを解除するため
SetEvent(m_LoadCmplete);
return 0;
}

2007年4月16日月曜日

画面への描画

結局画面への描画はこんな感じになった




class CScreen
{
public:
CScreen(void);
~CScreen(void);

HDC m_DC;
HBITMAP m_Bmp;
PBYTE m_Buf;
int m_dspW;
int m_dspH;
int m_WidthByte;

void Blt(HDC hdc, int w, int h);

};

CScreen::CScreen(void)
{
HDC dc = GetDC(NULL);
m_DC = CreateCompatibleDC(dc);
ReleaseDC(NULL,dc);

m_dspW = 480;
m_dspH = 640;
m_WidthByte = (m_dspW*2+1)&0xfffffffe;
m_Buf = (PBYTE) new WORD[m_WidthByte*m_dspH];

}

CScreen::~CScreen(void)
{
DeleteObject(m_DC);
delete [] m_Buf;
}

void CScreen::Blt(HDC hdc, int w, int h)
{
HGDIOBJ oldObj;
m_Bmp = CreateBitmap(m_dspW, m_dspH, 1, 16, m_Buf);

oldObj = SelectObject(m_DC, m_Bmp);
BitBlt(hdc,0,0,w,h,m_DC,0,0,SRCCOPY);
SelectObject(m_DC, oldObj);
DeleteObject(m_Bmp);
}


m_bufをオフスクリーン用のバッファとして、予め画像データを作成しておく

とりあえず画面にバッファの内容を表示することは出来た。
しかし、バッファの画像処理操作は結構遅い、VCのコンパイルオプションでバッファセキュリティチェックを”いいえ”にするとある程度改善されるようだ

Windows Live for m... 入れた



Windows Live for Windows Mobile 入れてみた
3日でアンインストールした
メッセンジャーする相手がいなかった...
Posted by Picasa

2007年4月14日土曜日

SetBitmapBitsを使った

CreateCompatibleBitmapとSetBitmapBitsを使ってメモリ上に表示イメージを作成して表示デバイスにbltするようにしてみた。ものすごく遅い...なんか嫌になってきた

StretchBltを使わないように拡大縮小も自前で用意してみたつもりなんだけど余計遅くなっただけかも。

src_buf -> m_buf -> m_hbmp > hdc
と転送が繰り返されているように思う

src_buf -> m_buf -> hdc
ぐらいにしたい


bool CPicture::Draw(HDC hdc, RECT rc, int frame)
{
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;

// 表示用のバッファ領域を作成する
if(m_hBmp == NULL)
{
m_hBmp = CreateCompatibleBitmap(hdc,w,h);

m_WidthByte = (w*2+1)&0xfffffffe;
m_buf = (LPBYTE) new WORD[m_WidthByte*h];
}

// イメージ内の表示領域を取得する
KEY src = GetValue(frame);

int srcX = src.sx;
int srcY = src.sy;
int srceX = src.ex;
int srceY = src.ey;
int srcW = src.ex - src.sx;
int srcH = src.ey - src.sy;


int ddx,ddy;
int sy = srcY;
unsigned short rgb;

// 拡大縮小とフェードインアウト画像処理
WORD *dpx;
ddy = h;
for(int y=0;y<h;y++)
{
int sidx = (m_Height-sy)*m_Width + srcX;
dpx = (WORD*)(m_WidthByte*y + m_buf);
ddx = w;
ddy -= srcH;
while(ddy<=0)
{
sy += 1;
ddy+= h;
}

for(int x=0;x<w;x++)
{
if(sidx<m_Width*m_Height)
{
unsigned char r = (src_buf[sidx].rgbRed * src.fader)>>8;
unsigned char g = (src_buf[sidx].rgbGreen * src.fader)>>8;
unsigned char b = (src_buf[sidx].rgbBlue * src.fader)>>8;
rgb = ((r << 8) & 0xf800)
| ((g << 3) & 0x07e0)
| ((b >> 3) & 0x001f);
}
else
{
rgb = 0;
}
*dpx=rgb;

dpx++;
ddx -= srcW;
while(ddx<=0)
{
sidx+=1;
ddx += w;
}
}
}
// バッファのイメージをbitmapにコピーする
SetBitmapBits(m_hBmp,m_WidthByte*h,m_buf);

// ディスプレイにbitmapをコピーする
HDC hBmpDC = CreateCompatibleDC(hdc);
SelectObject(hBmpDC, m_hBmp);
BitBlt(hdc,0,0,w,h,hBmpDC,0,0,SRCCOPY);
DeleteObject(hBmpDC);


return true;
}


HBITMAPに関係するもの

Win32API と WindowsMobileのAPIにはある程度の互換性があるが、Mobile向けには用意されていないAPIもいくつかあるようだ

Mobile でも使用できるHBITMAP に関係のある関数をwingdi.hから抜粋してみた


WINGDIAPI HBRUSH WINAPI CreatePatternBrush(HBITMAP);
WINGDIAPI HBITMAP WINAPI CreateBitmap(int,int,UINT,UINT,CONST VOID *);
WINGDIAPI HBITMAP WINAPI CreateCompatibleBitmap(HDC,int,int);
WINGDIAPI LONG WINAPI SetBitmapBits(HBITMAP,DWORD,CONST VOID*);
WINGDIAPI BOOL WINAPI MaskBlt(HDC,int,int,int,int,HDC,int,int,HBITMAP,int,int,DWORD);
WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC,CONST BITMAPINFO *,UINT,VOID **,HANDLE,DWORD);
WINGDIAPI int WINAPI GetDIBits(HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT);
WINGDIAPI LONG WINAPI GetBitmapBits(HBITMAP, LONG, LPVOID);


使えそうなのは
  • CreateBitmap(int,int,UINT,UINT,CONST VOID *);
  • CreateCompatibleBitmap(HDC,int,int);
  • SetBitmapBits(HBITMAP,DWORD,CONST VOID*);
  • CreateDIBSection(HDC,CONST BITMAPINFO *,UINT,VOID **,HANDLE,DWORD);
  • GetDIBits(HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT);
  • GetBitmapBits(HBITMAP, LONG, LPVOID);
かな?

CreateBitmapはモノクロのbitmapを作成するときに使うらしい、カラーのデバイス依存のbitmap作成ならCreateCompatibleBitmapを使用する
デバイスに依存しないビットマップはCreateDIBSectionで作成する

bitmapのピクセルデータビット列への操作は、デバイス依存の場合はGetBitmapBits、SetBitmapBitsで行う。GetDIBitsはデバイス依存のbitmapをデバイスに依存しないbitmapへコピーする


これで昨日のソースを書き換えられそうな気がする


GetBitmapBits ,GetDIBits はMobileでは使えなかった....

2007年4月12日木曜日

スライドショーをPocketPCで...

Microsoft Windows フォトストーリーのビデオファイルの出力先としてPocketPCが選べる
PocketPCでスライドを見る事があるかどうかは???だけど面白いと思う

わざわざ時間をかけて動画ファイルへのレンダリングをしないで、画像ファイルから直接動きのあるスライドショーできるようなアプリがあったら良いかな?と思って作ってみることにした

やってみると色々問題があってうまくいかない
jpgファイルを読み込んで表示するまではよいのだけど、フェードインフェードアウト等の効果をつけるのに画像データを直接いじくる必要があって、この処理をすると遅くて使い物にならなくなってしまった

CreateDIBSectionでDIBイメージを作って画像データをいじくろうと思ったのだけど、CreateDIBSectionで作った画像を画面にBltするだけでエラク遅くなってしまう

DIBからDDBの変換に時間がかかってしまうみたい

DDBのまま画像をデータを処理できれば良いのだけど...

jpgファイルはこんな感じで読み込む

m_hBmp = SHLoadImageFile(fname);
BITMAP bmp;
GetObject(m_hBmp,sizeof(bmp),&bmp);

m_Width = bmp.bmWidth;
m_Height = bmp.bmHeight;
m_WidthByte = bmp.bmWidthBytes;
m_buf = (LPBYTE)(bmp.bmBits);


読み込まれたビットマップはDDBで、Zero3ではRGB565となると思う
RGB888でアクセスしたいのでDIB形式のbitmapを作ってbltした


BITMAPINFO BmpInfo;
BmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
BmpInfo.bmiHeader.biWidth=m_Width;
BmpInfo.bmiHeader.biHeight=m_Height;
BmpInfo.bmiHeader.biPlanes=1;
BmpInfo.bmiHeader.biBitCount=32;
BmpInfo.bmiHeader.biCompression=BI_RGB;
RGBQUAD *DIBBuf;

HBITMAP hDIBBmp = CreateDIBSection(NULL,&BmpInfo,DIB_RGB_COLORS,(void**)&DIBBuf,NULL,0);

HDC hDDBDC = CreateCompatibleDC(0);
SelectObject(hDDBDC, m_hBmp);

HDC hDIBDC = CreateCompatibleDC(0);
SelectObject(hDIBDC, hDIBBmp);

src_buf =(RGBQUAD*)HeapAlloc(GetProcessHeap(), 0,m_Width*m_Height*4);

BitBlt(hDIBDC ,0,0,m_Width,m_Height, hDDBDC,0,0,SRCCOPY);

memcpy(src_buf,DIBBuf,m_Width*m_Height*4);

DeleteObject(hDDBDC);
DeleteObject(hDIBBmp);
DeleteObject(hDIBDC);



なんか回りくどい事をしているような気がする

src_buf にRGBQUADの画像データが入ってるので
m_buf に加工したデータをコピーして画面上にBitBltかStretchBltする

StretchBltすると拡大とか縮小して表示できる

2007年4月10日火曜日

スライドショーを作る

最近旅行とか卒園式とかの行事で撮った写真をスライドショー的に見れるDVDを作ったりなんかした。
今までデジカメで撮った写真ってあまり活用してなかったので、DVDにしたら見るかな~と思った

で、DVDにするには何通りか方法がある、
一番簡単なのは専用ソフトを使うこと。

デジカメde!! ムービーシアター 2なんかが簡単でよい感じのものが作れる。
でもソフトの値段が高いので、購入するまでは至らなかった

次に簡単なのはMicrosoft Windows フォトストーリーを使う。
これも簡単に動きのあるスライドショーが作れるし、ソフトが無料で手に入る。
けど、出来上がりにちょっと満足できなかった

あとは、Adobe Premiere Elements 3.0 日本版 Windows版 とかPhotoShopを使う
Premiere elements2.0 は持っているので追加投資なしで完成度の高いものが出来るけど、作業手順が多くて結構めんどう

PhotoShop elements でも出来そうだけど試さなかった

結局めんどうだったけど自由にエフェクトをかけたり出来るPremiere Elementsを使った

頻繁にDVDを作るようならデジカメde!! ムービーシアターを買おうと思う

2007年4月5日木曜日

えーっと
ブログを引っ越してから全然エントリーしてなかったので、なんか書いてみようと思う。

まずは、今後のためにもブログの目的をハッキリしておこう
去年から何となく、書き始めたけど

  1. 子供が描いた絵を記録する
  2. プログラムとかについて調べたりしたことを記録する
  3. その他適当なこと
以上が目的と言うかナンかです
1の子供の描いた絵の記録は半年前から別ブログにして、2と3の残りの目的の為に使うことにしたのがこのブログ

なんて、書いても誰も見てないと思うけどね