001:
002:
003:
004:
005:
006: #include <stdio.h>
007: #include <math.h>
008: #include <windows.h>
009: #include <vfw.h>
010: #include "aviplay.h"
011:
012: #pragma comment(linker,"/subsystem:windows")
013: #pragma comment(lib,"winmm")
014: #pragma comment(lib,"vfw32")
015:
016:
017:
018: HINSTANCE hAppInst; HWND hAppWnd;
019: UINT aviLoad,iWidth,iHeight,iSize;
020: LPBYTE lpBMP = NULL;
021: AviInfo avi;
022: double wm_xscale,wm_yscale;
023: static HWND hwB0,hwB1,hwB2,hwB3;
024:
025: UINT vRun=FALSE;
026:
027: void TRACE(char *fmt,...)
028: {
029: char szBuff[BUFSIZ];
030: va_list ap;
031: va_start(ap,fmt);
032: vsprintf(szBuff,fmt,ap);
033: #ifdef _MSC_VER
034: OutputDebugString(szBuff);
035: #else
036: fprintf(stderr,szBuff);
037: #endif
038: va_end(ap);
039: }
040:
041: int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
042: LPSTR lpsCmdLine, int nCmdShow)
043: {
044: MSG msg;
045: LPCTSTR szClassName = "aviplay";
046: aviLoad = FALSE; iWidth = 300; iHeight = 200;
047:
048: if(!hPrevInst){
049: if(!InitApp(hCurInst,szClassName)) return 0;
050: hAppInst = hCurInst;
051: }
052:
053: if(!InitInstance(hCurInst,szClassName,lpsCmdLine,nCmdShow)){
054: return 0;
055: }
056:
057: AviInit();
058:
059: while(GetMessage(&msg,NULL,0,0)){
060: TranslateMessage(&msg);
061: DispatchMessage(&msg);
062: }
063: return msg.wParam;
064: }
065:
066:
067:
068: BOOL InitApp(HINSTANCE hInst, LPCSTR szClassName)
069: {
070: WNDCLASSEX wc;
071: wc.cbSize = sizeof(wc);
072: wc.style = CS_HREDRAW | CS_VREDRAW;
073: wc.lpfnWndProc = WndProc;
074: wc.cbClsExtra = 0;
075: wc.cbWndExtra = 0;
076: wc.hInstance = hInst;
077: wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
078: wc.hCursor = LoadCursor(NULL,IDC_ARROW);
079: wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
080: wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
081: wc.lpszMenuName = NULL;
082: wc.lpszClassName = (LPCSTR)szClassName;
083: return (RegisterClassEx(&wc));
084: }
085:
086:
087:
088: BOOL InitInstance(HINSTANCE hInst,LPCSTR szClassName,
089: LPSTR lpsCmdLine,int nCmdShow)
090: {
091: TCHAR lpStr[256]; HWND hWnd;
092:
093: wsprintf(lpStr,"動画ファイル(AVI)再生");
094: hWnd = CreateWindow(szClassName,lpStr,
095: WS_OVERLAPPEDWINDOW,
096: CW_USEDEFAULT,
097: CW_USEDEFAULT,
098: 15+iWidth,
099: 65+iHeight,
100: NULL,
101: NULL,
102: hInst,
103: NULL);
104: if(!hWnd) return FALSE;
105: ShowWindow(hWnd,nCmdShow);
106: UpdateWindow(hWnd);
107: hAppWnd = hWnd;
108: return TRUE;
109: }
110:
111:
112:
113: LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
114: {
115: switch(iMsg){
116: case WM_CHAR:
117: if(wParam=='q') SendMessage(hwnd,WM_DESTROY,0,0); break;
118: case WM_CREATE: {
119:
120: hwB0 = CreateWindow("Button","開く",WS_CHILD | WS_VISIBLE,
121: 5,5,55,25,hwnd,(HMENU)ID_OPEN,hAppInst,NULL);
122: hwB1 = CreateWindow("Button","コマ送り",WS_CHILD | WS_VISIBLE,
123: 60,5,70,25,hwnd,(HMENU)ID_AVI1,hAppInst,NULL);
124: hwB2 = CreateWindow("Button","再生",WS_CHILD | WS_VISIBLE,
125: 130,5,55,25,hwnd,(HMENU)ID_AVI2,hAppInst,NULL);
126: hwB3 = CreateWindow("Button","保存",WS_CHILD | WS_VISIBLE,
127: 185,5,55,25,hwnd,(HMENU)ID_SAVE,hAppInst,NULL);
128: } break;
129: case WM_COMMAND:
130: switch(LOWORD(wParam)){
131: case 'q':
132: SendMessage(hwnd,WM_DESTROY,0,0); break;
133: case ID_OPEN:
134: if(vRun) break;
135: if(OpenFile(avi.in_path)){ AviOpen(); }
136: break;
137: case ID_AVI1:
138: if(aviLoad) AviNext();
139: break;
140: case ID_AVI2:
141: if(aviLoad) AviView();
142: break;
143: case ID_SAVE:
144: static TCHAR szFn[MAX_PATH];
145: if(SaveFile(szFn)){ SaveBMP(szFn,lpBMP); }
146: break;
147: }
148: break;
149: case WM_PAINT:
150: if(aviLoad){
151: HDC hdc; PAINTSTRUCT ps;
152:
153: hdc = BeginPaint(hwnd,&ps);
154: StretchDIBits(hdc,4,35,
155: (int)(wm_xscale*iWidth),(int)(wm_yscale*iHeight),
156: 0,0,iWidth,iHeight,
157: lpBMP+avi.biSize,(LPBITMAPINFO)lpBMP,
158: DIB_RGB_COLORS,SRCCOPY);
159: EndPaint(hwnd,&ps);
160: }
161: break;
162: case WM_SIZE: {
163: UINT wx,wy;
164: WINDOWPLACEMENT wndpl;
165: GetWindowPlacement(hAppWnd,&wndpl);
166: wx = wndpl.rcNormalPosition.right - wndpl.rcNormalPosition.left;
167: wy = wndpl.rcNormalPosition.bottom - wndpl.rcNormalPosition.top;
168: wx -= 14; wy -= 84;
169: wm_xscale = wx/(double)iWidth;
170: wm_yscale = wy/(double)iHeight;
171:
172: SetRect(&avi.dRgn,
173: 4,35,4+(int)(iWidth*wm_xscale),35+(int)(iHeight*wm_yscale));
174: } break;
175: case WM_DESTROY:
176: if(aviLoad) AviClose();
177: PostQuitMessage(0);
178: break;
179: }
180: return DefWindowProc(hwnd,iMsg,wParam,lParam);
181: }
182:
183:
184:
185: void SetWTitle(LPTSTR tstr)
186: {
187: SetWindowText(hAppWnd,tstr);
188: }
189: char *getfps(void)
190: {
191: static DWORD last = 0;
192: static DWORD frames = 0;
193: static char buf[256] = "";
194: DWORD current = timeGetTime();
195: frames++;
196: if(500 <= current - last) {
197: double dt = (double)(current - last) / 1000.0f;
198: double fps = (double)frames / dt;
199: last = current;
200: frames = 0;
201: sprintf(buf,"%.02f fps",fps);
202: }
203: return buf;
204: }
205:
206:
207:
208: void set_window(LPBITMAPINFOHEADER bih)
209: {
210: TCHAR tStr[256];
211:
212: iWidth = bih->biWidth;
213: iHeight = bih->biHeight;
214:
215: UINT wx,wy;
216: WINDOWPLACEMENT wndpl;
217: GetWindowPlacement(hAppWnd,&wndpl);
218: wx = wndpl.rcNormalPosition.left;
219: wy = wndpl.rcNormalPosition.top;
220: MoveWindow(hAppWnd,wx,wy,15+iWidth,65+iHeight,TRUE);
221:
222: wsprintf(tStr,"[%s] frame %d/%d",avi.in_path,1,avi.dwLength);
223: SetWTitle(tStr);
224:
225: wm_xscale = wm_yscale = 1.0;
226: }
227:
228:
229:
230: UINT OpenFile(LPTSTR lpFname)
231: {
232: static OPENFILENAME ofn;
233: TCHAR szFt[MAX_PATH];
234: lpFname[0] = NULL;
235:
236: ofn.lStructSize = sizeof(OPENFILENAME);
237: ofn.hwndOwner = hAppWnd;
238: ofn.hInstance = NULL;
239: ofn.lpstrFilter =
240: "AVI stream(*.avi)\0*.avi\0"
241: "すべてのファイル(*.*)\0*.*\0\0";
242: ofn.lpstrCustomFilter = NULL;
243: ofn.nMaxCustFilter = 0;
244: ofn.nFilterIndex = 1;
245: ofn.lpstrFile = lpFname;
246: ofn.nMaxFile = 255;
247: ofn.lpstrFileTitle = szFt;
248: ofn.nMaxFileTitle = 255;
249: ofn.lpstrInitialDir = NULL;
250: ofn.lpstrTitle = "動画ファイル(AVI)の選択";
251: ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
252: ofn.nFileOffset = 0;
253: ofn.nFileExtension = 0;
254: ofn.lpstrDefExt = "avi";
255: ofn.lCustData = 0;
256: ofn.lpfnHook = NULL;
257: ofn.lpTemplateName = NULL;
258:
259: if(!GetOpenFileName(&ofn)) return FALSE;
260: return TRUE;
261: }
262:
263:
264:
265: UINT SaveFile(LPTSTR lpFname)
266: {
267: static OPENFILENAME ofn;
268: TCHAR szFt[MAX_PATH];
269: lpFname[0] = NULL;
270:
271: ofn.lStructSize = sizeof(OPENFILENAME);
272: ofn.hwndOwner = hAppWnd;
273: ofn.hInstance = NULL;
274: ofn.lpstrFilter =
275: "Bitmap(*.bmp)\0*.bmp\0"
276: "すべてのファイル(*.*)\0*.*\0\0";
277: ofn.lpstrCustomFilter = NULL;
278: ofn.nMaxCustFilter = 0;
279: ofn.nFilterIndex = 1;
280: ofn.lpstrFile = lpFname;
281: ofn.nMaxFile = 255;
282: ofn.lpstrFileTitle = szFt;
283: ofn.nMaxFileTitle = 255;
284: ofn.lpstrInitialDir = NULL;
285: ofn.lpstrTitle = "画像(BMP)の保存";
286: ofn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
287: ofn.nFileOffset = 0;
288: ofn.nFileExtension = 0;
289: ofn.lpstrDefExt = "bmp";
290: ofn.lCustData = 0;
291: ofn.lpfnHook = NULL;
292: ofn.lpTemplateName = NULL;
293:
294: if(!GetSaveFileName(&ofn)) return FALSE;
295: return TRUE;
296: }
297:
298:
299:
300: UINT SaveBMP(LPCTSTR lpFname,LPBYTE lpBuf)
301: {
302: HANDLE hdlBmp;
303: BITMAPFILEHEADER bfhBmp;
304: LPBITMAPINFOHEADER bih = (LPBITMAPINFOHEADER)lpBuf;
305: LONG offset = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
306: LONG cpsize = bih->biClrUsed*sizeof(RGBQUAD);
307: UINT bCnt = bih->biBitCount,bPln = bih->biPlanes;
308: DWORD dwdPixelsSize,wSize;
309:
310: dwdPixelsSize = ((bih->biWidth*bCnt+31)&~0x1f)*bPln/8;
311: dwdPixelsSize *= bih->biHeight;
312:
313: hdlBmp = CreateFile(lpFname,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,
314: FILE_ATTRIBUTE_NORMAL,NULL);
315: if(hdlBmp==INVALID_HANDLE_VALUE){
316: MessageBox(NULL,"書込みに失敗しました",NULL,MB_OK);
317: return FALSE;
318: }
319:
320: bfhBmp.bfType = 'M'*256+'B';
321: bfhBmp.bfSize = offset + cpsize + dwdPixelsSize;
322: bfhBmp.bfReserved1 = 0;
323: bfhBmp.bfReserved2 = 0;
324: bfhBmp.bfOffBits = offset + cpsize;
325:
326: dwdPixelsSize += sizeof(BITMAPINFOHEADER) + cpsize;
327: WriteFile(hdlBmp,&bfhBmp,sizeof(BITMAPFILEHEADER),&wSize,NULL);
328: WriteFile(hdlBmp,lpBuf,sizeof(BYTE)*dwdPixelsSize,&wSize,NULL);
329:
330: CloseHandle(hdlBmp);
331: return TRUE;
332: }
333:
334:
335:
336: void AviInit()
337: {
338: avi.in_file = NULL;
339: avi.in_video = NULL;
340: avi.in_frame = NULL;
341: avi.lpSrcFmt = NULL;
342: avi.lpDecFmt = NULL;
343: avi.lpSrc = NULL;
344: lpBMP = NULL;
345: avi.codec = FALSE;
346: }
347:
348:
349:
350: int AviOpen()
351: {
352: AVIFILEINFO pfi;
353: LPBITMAPINFOHEADER bih;
354:
355:
356:
357: if(aviLoad) AviClose();
358: AVIFileInit();
359: if(AVIFileOpen(&avi.in_file,avi.in_path,OF_READ,NULL)){
360: TRACE("open err.\n");
361: return FALSE;
362: }
363:
364:
365:
366: AVIFileInfo(avi.in_file,&pfi,sizeof(AVIFILEINFO));
367: if(AVIFileGetStream(avi.in_file,&avi.in_video,streamtypeVIDEO,0)){
368: TRACE("stream err.\n");
369: return FALSE;
370: }
371:
372: if(avi.in_video) {
373: avi.in_frame = NULL;
374: AVIStreamInfo(avi.in_video,&avi.info,sizeof(AVISTREAMINFO));
375:
376: LONG len;
377: AVIStreamFormatSize(avi.in_video,0,&len);
378: avi.lpSrcFmt = (LPBITMAPINFOHEADER)GlobalAlloc(GPTR,len);
379: AVIStreamReadFormat(avi.in_video,0,avi.lpSrcFmt,&len);
380:
381: avi.in_frame = AVIStreamGetFrameOpen(avi.in_video,NULL);
382: if(avi.in_frame == NULL){
383: if(!codecOpen()){
384: MessageBox(NULL,"AVI未対応",0,0);
385: return FALSE;
386: }
387: } else avi.codec = FALSE;
388: } else return FALSE;
389:
390:
391:
392: if(avi.codec) bih = avi.lpDecFmt;
393: else bih = avi.lpSrcFmt;
394: iWidth = bih->biWidth;
395: iHeight = bih->biHeight;
396: avi.dwLength = AVIStreamLength(avi.in_video);
397: iSize = ((iWidth*bih->biBitCount+31)&~0x1f)*bih->biPlanes/8*iHeight;
398: avi.biSize = bih->biSize + bih->biClrUsed*sizeof(RGBQUAD);
399: avi.SPF = (int)(1000.*avi.info.dwScale/(double)avi.info.dwRate);
400:
401:
402:
403: set_window(bih);
404: SetRect(&avi.dRgn,4,35,4+iWidth,35+iHeight);
405:
406:
407:
408: if(avi.codec==FALSE){
409: if(lpBMP) GlobalFree(lpBMP);
410: lpBMP = (LPBYTE)GlobalAlloc(GPTR,avi.biSize+iSize);
411: }
412: AviReadFrame(0);
413:
414: InvalidateRect(hAppWnd,&avi.dRgn,FALSE);
415:
416:
417:
418: avi.v_index = 0;
419: aviLoad = TRUE;
420: return TRUE;
421: }
422:
423:
424:
425: int codecOpen()
426: {
427: LONG lFmtLength,lFrames,biLeng;
428:
429:
430:
431: AVIStreamFormatSize(avi.in_video,0,&lFmtLength);
432: if(avi.lpDecFmt) GlobalFree(avi.lpDecFmt);
433: avi.lpDecFmt = (LPBITMAPINFOHEADER)GlobalAlloc(GPTR,lFmtLength);
434:
435:
436:
437: LPBITMAPINFOHEADER s,d;
438: s = avi.lpSrcFmt; d = avi.lpDecFmt;
439: AVIStreamInfo(avi.in_video,&avi.info,sizeof(AVISTREAMINFO));
440: lFrames = AVIStreamLength(avi.in_video);
441:
442:
443:
444: memcpy(d,s,lFmtLength);
445: d->biBitCount = 24;
446: d->biCompression = BI_RGB;
447: d->biSize = lFmtLength;
448: biLeng = ((d->biWidth*d->biBitCount+31)&~0x1f)*d->biPlanes/8*d->biHeight;
449: d->biSizeImage = biLeng;
450:
451:
452:
453: biLeng = ((s->biWidth*s->biBitCount+31)&~0x1f)*s->biPlanes/8*s->biHeight;
454: avi.lLength = biLeng;
455: if(avi.info.dwSuggestedBufferSize)
456: if(avi.info.dwSuggestedBufferSize < (unsigned)avi.lLength)
457: avi.lLength = (LONG)avi.info.dwSuggestedBufferSize;
458:
459: if(avi.lpSrc) GlobalFree(avi.lpSrc);
460: if(lpBMP) GlobalFree(lpBMP);
461: avi.lpSrc = (LPBYTE)GlobalAlloc(GPTR,s->biSizeImage);
462: lpBMP = (LPBYTE)GlobalAlloc(GPTR,d->biSizeImage+lFmtLength);
463: memcpy(lpBMP,d,lFmtLength);
464: if(avi.lpSrc == NULL || lpBMP == NULL){ return FALSE; }
465:
466:
467:
468: static char tag[4]="",buf[256];
469: memcpy(tag,&avi.info.fccHandler,sizeof(DWORD));
470: avi.hicd = ICDecompressOpen(ICTYPE_VIDEO,avi.info.fccHandler,s,d);
471: if(!avi.hicd){
472: sprintf(buf,"%s: cannot find codec",tag);
473: MessageBox(NULL,buf,"AVI",0);
474: return FALSE;
475: }
476:
477:
478:
479: if(ICDecompressBegin(avi.hicd,avi.lpSrcFmt,avi.lpDecFmt))
480: return FALSE;
481: avi.codec = TRUE;
482: return TRUE;
483: }
484:
485:
486:
487: void AviReadFrame(int vidx)
488: {
489: avi.v_index ++;
490: if(avi.codec == FALSE){
491: avi.lpSrc = (LPBYTE)AVIStreamGetFrame(avi.in_frame,vidx);
492: CopyMemory(lpBMP,avi.lpSrc,avi.biSize+iSize);
493: } else {
494: AVIStreamRead(avi.in_video,vidx,1,avi.lpSrc,avi.lLength,NULL,NULL);
495: LPBYTE dst = lpBMP + avi.lpDecFmt->biSize;
496: ICDecompress(avi.hicd,0,avi.lpSrcFmt,avi.lpSrc,avi.lpDecFmt,dst);
497: CopyMemory(lpBMP,avi.lpDecFmt,avi.lpDecFmt->biSize);
498: }
499: }
500:
501:
502:
503: void AviClose()
504: {
505: if(avi.codec){
506: if(avi.lpSrc) { GlobalFree(avi.lpSrc); avi.lpSrc = NULL; }
507: if(avi.lpDecFmt) { GlobalFree(avi.lpDecFmt); avi.lpDecFmt = NULL; }
508: ICDecompressEnd(avi.hicd);
509: ICClose(avi.hicd);
510: avi.codec = FALSE;
511: }
512: if(avi.in_frame) {
513: AVIStreamGetFrameClose(avi.in_frame); avi.in_frame = NULL;
514: }
515: if(avi.in_video) { AVIStreamRelease(avi.in_video); avi.in_video = NULL; }
516: if(avi.in_file) { AVIFileRelease(avi.in_file); avi.in_file = NULL; }
517: if(avi.lpSrcFmt) { GlobalFree(avi.lpSrcFmt); avi.lpSrcFmt = NULL; }
518: if(lpBMP) { GlobalFree(lpBMP); lpBMP = NULL; }
519: AVIFileExit();
520: }
521:
522:
523:
524: void AviNext()
525: {
526: int vi,ret;
527: TCHAR cbuf[256];
528:
529: for(vi=avi.v_index;vi<avi.dwLength;vi++){
530: AviReadFrame(vi);
531:
532: InvalidateRect(hAppWnd,&avi.dRgn,FALSE);
533:
534: wsprintf(cbuf,"[%s] frame %d/%d",avi.in_path,vi+1,avi.dwLength);
535: SetWTitle(cbuf);
536: ret = MessageBox(NULL,
537: "Next:はい Prev:いいえ 停止:キャンセル","コマ送り",
538: MB_YESNOCANCEL);
539: if(ret==IDNO){ vi-=2; if(vi<-1) vi=0; }
540: if(ret==IDCANCEL) break;
541: }
542: if(vi==avi.dwLength-1) avi.v_index = 0;
543: }
544:
545:
546:
547: void AviView()
548: {
549: if(vRun == FALSE){
550:
551: DWORD tid;
552: vRun = TRUE;
553: SetWindowText(hwB2,"停止");
554: CreateThread(NULL, 0,
555: (LPTHREAD_START_ROUTINE)th_Proc,
556: NULL,0,&tid);
557: } else {
558: SetWindowText(hwB2,"再生");
559: vRun = FALSE;
560: }
561: }
562:
563:
564:
565: DWORD th_Proc()
566: {
567: int vi; TCHAR cbuf[256];
568: for(vi=avi.v_index;vi<avi.dwLength;vi++){
569: if(vRun == FALSE) break;
570: AviReadFrame(vi);
571:
572: InvalidateRect(hAppWnd,&avi.dRgn,FALSE);
573:
574: wsprintf(cbuf,"%s -- frame %d/%d [%s]",
575: avi.in_path,vi+1,avi.dwLength,getfps());
576: SetWTitle(cbuf);
577:
578: Sleep(avi.SPF);
579: }
580:
581: if(vi==avi.dwLength) avi.v_index = 0;
582: SetWindowText(hwB2,"再生");
583: vRun = FALSE;
584: return 0;
585: }