diff --git a/videodev-vfw.cc b/videodev-vfw.cc index 8043792..c3f4ff9 100644 --- a/videodev-vfw.cc +++ b/videodev-vfw.cc @@ -17,13 +17,14 @@ VideoDev_VFW::VideoDev_VFW() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - cap = NULL; + hwnd = cap = NULL; camid = -1; inframe_pixfmt = 0x0; inframe_w = -1; inframe_h = -1; inframe = NULL; inframe_size = 0; + vfw_size = 0; }; @@ -54,21 +55,54 @@ int VideoDev_VFW::GetDeviceList(std::list *list) { return VDEV_STATUS_OK; } - - /* * Open Device * prepare the buffer */ int VideoDev_VFW::Open() { + static int first = 1; + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); camid = atoi (conf_device.c_str()); printf ("%s:%d %s Opening VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + // create parent window + //HWND main_hwnd = (HWND)GDK_WINDOW_HWND (gtk_widget_get_window (GTK_WIDGET(main_window))); + HINSTANCE hinst = GetModuleHandle(NULL); + char classNameVfW[] = "VFW-Class"; + + if (first) { + WNDCLASSEX hclass; + hclass.hInstance=hinst; + hclass.lpszClassName=classNameVfW; + hclass.lpfnWndProc=DefWindowProc; + hclass.style=CS_DBLCLKS; + hclass.cbSize=sizeof(WNDCLASSEX); + hclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); + hclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION); + hclass.hCursor=LoadCursor(NULL,IDC_ARROW); + hclass.lpszMenuName=NULL; + hclass.cbClsExtra=0; + hclass.cbWndExtra=0; + hclass.hbrBackground=(HBRUSH)COLOR_BACKGROUND; + + if(!RegisterClassEx(&hclass)) { + printf ("%s:%d %s Could not register VFW class\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_ERROR; + } + first = 0; + } + hwnd = CreateWindowEx(0, classNameVfW, "CameraPreview", WS_POPUPWINDOW|WS_VISIBLE, 0, 0, 3, 3, NULL, NULL, hinst, NULL); + if (hwnd == NULL) { + printf ("%s:%d %s Could not create window (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError()); + return VDEV_STATUS_ERROR; + } + ShowWindow(hwnd, SW_SHOW); + // connect to driver - cap = capCreateCaptureWindow("VFW", WS_CHILD|WS_VISIBLE, 0, 0, 700, 700, HWND_MESSAGE, camid); + cap = capCreateCaptureWindow("VFW", WS_CHILD|WS_VISIBLE, 0, 0, 1, 1, hwnd, camid); if(!cap) { printf ("%s:%d %s Could not open VFW id %d window\n", __FILE__, __LINE__, __FUNCTION__, camid); return VDEV_STATUS_ERROR; @@ -78,16 +112,46 @@ int VideoDev_VFW::Open() { return VDEV_STATUS_ERROR; } - // set capture format and size + // let the callbacks know this class pointer + capSetUserData(cap, this); + + CAPTUREPARMS cp; + if(!capCaptureGetSetup(cap, &cp, sizeof(cp))) { + printf ("%s:%d %s Could not get VFW setup\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_ERROR; + } + cp.dwRequestMicroSecPerFrame = 33333; + cp.fMakeUserHitOKToCapture = 0; + cp.wPercentDropForError = 90; + cp.fYield = TRUE; + cp.wNumVideoRequested = 1; + cp.fCaptureAudio = 0; + cp.vKeyAbort = 0; + cp.fAbortLeftMouse = 0; + cp.fAbortRightMouse = 0; + cp.fLimitEnabled = 0; + if(!capCaptureSetSetup(cap, &cp, sizeof(cp))) { + printf ("%s:%d %s Could not set VFW setup\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_ERROR; + } + + capOverlay(cap, 0); + capPreviewRate(cap, 10); // rate in ms + capPreviewScale(cap, 0); + capPreview(cap, TRUE); + //capCaptureSequenceNoFile(cap); + + // set video source, capture format and size + capDlgVideoSource(cap); capDlgVideoFormat(cap); // get current valid width/height BITMAPINFO bi; - int w, h, i = 0; + int i = 0; capGetVideoFormat(cap, &bi, sizeof(BITMAPINFO)); - w = bi.bmiHeader.biWidth; - h = bi.bmiHeader.biHeight; - printf ("%s:%d %s Current capture size is %dx%d\n", __FILE__, __LINE__, __FUNCTION__, w, h); + inframe_w = bi.bmiHeader.biWidth; + inframe_h = bi.bmiHeader.biHeight; + printf ("%s:%d %s Current capture size is %dx%d\n", __FILE__, __LINE__, __FUNCTION__, inframe_w, inframe_h); conf_format = convert_from_pixelformat(bi.bmiHeader.biCompression); inframe_pixfmt = bi.bmiHeader.biCompression; printf ("%s:%d %s Current capture format is %s\n", __FILE__, __LINE__, __FUNCTION__, conf_format.c_str()); @@ -104,23 +168,28 @@ int VideoDev_VFW::Open() { } // find out maximum resolution else { - int sizes[][2] = {{320, 240}, {640, 480}, {800, 600}, {1024, 768}, {1280, 1024}, {1920, 1080}, {-1, -1}}; + int sizes[][2] = {{320, 240}, {640, 480}, {800, 600}, {1024, 768}, {1280, 720}, {1280, 1024}, {1920, 1080}, {-1, -1}}; while(sizes[i][0] != -1) { - w = bi.bmiHeader.biWidth = sizes[i][0]; - h = bi.bmiHeader.biHeight = sizes[i][1]; + inframe_w = bi.bmiHeader.biWidth = sizes[i][0]; + inframe_h = bi.bmiHeader.biHeight = sizes[i][1]; bi.bmiHeader.biCompression = inframe_pixfmt; if(capSetVideoFormat(cap, &bi, sizeof(BITMAPINFO))) { - printf ("%s:%d %s Resolution %dx%d (%s) works\n", __FILE__, __LINE__, __FUNCTION__, w, h, conf_format.c_str()); - if (w >= conf_width && h >= conf_height) { - conf_width = w; - conf_height = h; + printf ("%s:%d %s Resolution %dx%d (%s) works\n", __FILE__, __LINE__, __FUNCTION__, inframe_w, inframe_h, conf_format.c_str()); + if (inframe_w >= conf_width && inframe_h >= conf_height) { + conf_width = inframe_w; + conf_height = inframe_h; } } i++; } } + // translate this special format to what our convert functions can work with + if(inframe_pixfmt == V4L2_PIX_FMT_YUY2) { + inframe_pixfmt = V4L2_PIX_FMT_YUYV; + } + return VDEV_STATUS_OK; }; @@ -135,7 +204,8 @@ int VideoDev_VFW::Close() { if(cap) { capDriverDisconnect(cap); DestroyWindow(cap); - cap = NULL; + DestroyWindow(hwnd); + hwnd = cap = NULL; } return VDEV_STATUS_OK; }; @@ -146,18 +216,15 @@ int VideoDev_VFW::Close() { * VideoGrabbing */ -int VFW_frame_size; -unsigned char VFW_frame_buffer[640*480*3]; - LRESULT CALLBACK VFW_frame_callback(HWND h, LPVIDEOHDR v) { - VFW_frame_size = v->dwBytesUsed; - printf("frame callback: %d bytes\n", VFW_frame_size); - memcpy(VFW_frame_buffer, v->lpData, VFW_frame_size); + VideoDev_VFW * obj = (VideoDev_VFW *)capGetUserData(h); + obj->SetFrameBufferSize(v->dwBytesUsed); + memcpy(obj->GetFrameBuffer(), v->lpData, obj->GetFrameBufferSize()); return TRUE; } LRESULT VFW_error_callback(HWND h, int nID, LPCSTR lpsz) { - printf("error callback: %d (%s)\n", nID, lpsz); + printf("%s:%d %s id=%d (%s)\n", __FILE__, __LINE__, __FUNCTION__, nID, lpsz); return TRUE; } @@ -170,19 +237,35 @@ int VideoDev_VFW::CaptureStart() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - capPreviewRate(cap, 50); // rate in ms - capPreview(cap, TRUE); + // allocate memory for frame data + if (inframe != NULL) free (inframe); + inframe_size = 4 * inframe_w * inframe_h; + inframe = (unsigned char*) malloc(inframe_size); + + pixelformat = inframe_pixfmt; if(!capSetCallbackOnError(cap, VFW_error_callback)) { printf ("%s:%d %s Could not set error callback to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + return VDEV_STATUS_ERROR; } +#if 0 + if(!capSetCallbackOnVideoStream(cap, VFW_frame_callback)) { + printf ("%s:%d %s Could not set videostream callback to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + return VDEV_STATUS_ERROR; + } + + if(!capSetCallbackOnYield(cap, VFW_frame_callback)) { + printf ("%s:%d %s Cmould not set yield callback to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + return VDEV_STATUS_ERROR; + } +#endif + if(!capSetCallbackOnFrame(cap, VFW_frame_callback)) { printf ("%s:%d %s Could not set frame callback to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + return VDEV_STATUS_ERROR; } - pixelformat = inframe_pixfmt; - return VDEV_STATUS_OK; }; @@ -197,6 +280,16 @@ int VideoDev_VFW::CaptureStop() { capCaptureAbort(cap); capSetCallbackOnError(cap, NULL); capSetCallbackOnFrame(cap, NULL); + capSetCallbackOnVideoStream(cap, NULL); + capSetCallbackOnYield(cap, NULL); + + // free inframe memory + if (inframe) { + free (inframe); + inframe_size = 0; + inframe = NULL; + } + return VDEV_STATUS_OK; }; @@ -208,11 +301,19 @@ int VideoDev_VFW::CaptureStop() { // FIXME: SVBGetVideoData needs to be outside of Lock/UnLockMutex - using inside thread inbuffer int VideoDev_VFW::Grab(VideoFrameRaw *vf) { - //if (inframe == NULL) return VDEV_STATUS_ERROR; + MSG msg; + if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (inframe == NULL) return VDEV_STATUS_ERROR; - LockMutex(); - vf->CopyFrom(inframe_pixfmt, conf_width, conf_height, VFW_frame_size, VFW_frame_buffer); - UnLockMutex(); + if (GetFrameBufferSize() > 0) { + LockMutex(); + vf->CopyFrom(inframe_pixfmt, inframe_w, inframe_h, GetFrameBufferSize(), inframe); + UnLockMutex(); + } return VDEV_STATUS_OK; } diff --git a/videodev-vfw.h b/videodev-vfw.h index 995dee7..0ec3908 100644 --- a/videodev-vfw.h +++ b/videodev-vfw.h @@ -7,13 +7,14 @@ class VideoDev_VFW: public VideoDev { private: unsigned char *inframe; - int inframe_size; + int inframe_size; int inframe_w, inframe_h; int inframe_pixfmt; + int vfw_size; ConvertData cdata; int camid; - HWND cap; + HWND cap, hwnd; int Grab(VideoFrameRaw *vf); int Open(); @@ -30,6 +31,9 @@ public: int GetDeviceList(std::list *list); int GetDeviceFormats(string device, std::list *formats); int GetDeviceResolutions(string device, std::list *formats) { return VDEV_STATUS_OK; }; + unsigned char * GetFrameBuffer(void) { return inframe; }; + void SetFrameBufferSize(int s) { vfw_size = s; }; + int GetFrameBufferSize(void) { return vfw_size; }; }; #endif diff --git a/windows.h b/windows.h index 4f53ba7..bf7c1b2 100644 --- a/windows.h +++ b/windows.h @@ -66,7 +66,7 @@ extern void strfromd (char* dest, int len, char *fmt,...); #define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_YUV2 v4l2_fourcc('Y', 'U', 'V', '2') /* ??? */ +#define V4L2_PIX_FMT_YUY2 v4l2_fourcc('Y', 'U', 'Y', '2') /* ??? */ #define v4l2_fourcc(a, b, c, d)\ ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))