/* * module to read video data from vfw. */ #include "config.h" #include #include #include #include #include #include #include "convert.h" #include "videodev-vfw.h" VideoDev_VFW::VideoDev_VFW() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); hwnd = cap = NULL; camid = -1; inframe_pixfmt = 0x0; inframe_w = -1; inframe_h = -1; inframe = NULL; inframe_size = 0; vfw_size = 0; }; VideoDev_VFW::~VideoDev_VFW() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); if (running > 0) CaptureStop(); } /* * check for connected devices and return the result in a list. */ int VideoDev_VFW::GetDeviceList(std::list *list) { char name[256]; char desc[256]; printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); if (list == NULL) return VDEV_STATUS_ERROR; for(int i=0; i < 10; i++) if(capGetDriverDescription(i, name, sizeof(name), desc, sizeof(desc))) { std::string device; device = "VFW " + to_string(i) + " " + (string)name + " [" + (string)desc + "]"; printf ("%s:%d %s Found device '%s'\n", __FILE__, __LINE__, __FUNCTION__, device.c_str()); list->push_back(device); } 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, 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; } if(!capDriverConnect(cap, camid)) { printf ("%s:%d %s Could not connect to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); return VDEV_STATUS_ERROR; } // 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 i = 0; capGetVideoFormat(cap, &bi, sizeof(BITMAPINFO)); 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()); // try to set the configured width/height if(conf_width != -1) { bi.bmiHeader.biWidth = conf_width; bi.bmiHeader.biHeight = conf_height; bi.bmiHeader.biCompression = inframe_pixfmt; if(!capSetVideoFormat(cap, &bi, sizeof(BITMAPINFO))) { printf ("%s:%d %s Could not set capture size %dx%d (%s)\n", __FILE__, __LINE__, __FUNCTION__, conf_width, conf_height, conf_format.c_str()); return VDEV_STATUS_ERROR; } } // find out maximum resolution else { int sizes[][2] = {{320, 240}, {640, 480}, {800, 600}, {1024, 768}, {1280, 720}, {1280, 1024}, {1920, 1080}, {-1, -1}}; while(sizes[i][0] != -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__, 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; }; /* * Close Device * Free videobuffer */ int VideoDev_VFW::Close() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); if(cap) { capDriverDisconnect(cap); DestroyWindow(cap); DestroyWindow(hwnd); hwnd = cap = NULL; } return VDEV_STATUS_OK; }; /***************************************************************************************************** * VideoGrabbing */ LRESULT CALLBACK VFW_frame_callback(HWND h, LPVIDEOHDR v) { 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("%s:%d %s id=%d (%s)\n", __FILE__, __LINE__, __FUNCTION__, nID, lpsz); return TRUE; } /* * prepare inframe for raw picture data, will hold a video frame with 16bit per channel or BGR32/BGR24 * inframe size = 4*W*H * send the start capture signal to the cam */ int VideoDev_VFW::CaptureStart() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); // 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(!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; } 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; } return VDEV_STATUS_OK; }; /* * free inbuffer */ int VideoDev_VFW::CaptureStop() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); 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; }; /* * try to grab one frame and convert it into RGB32. * If something goes wrong return an error code. * Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read. */ // FIXME: SVBGetVideoData needs to be outside of Lock/UnLockMutex - using inside thread inbuffer int VideoDev_VFW::Grab(VideoFrameRaw *vf) { MSG msg; while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (inframe == NULL) return VDEV_STATUS_ERROR; if (GetFrameBufferSize() > 0) { LockMutex(); vf->CopyFrom(inframe_pixfmt, inframe_w, inframe_h, GetFrameBufferSize(), inframe); UnLockMutex(); } return VDEV_STATUS_OK; } int VideoDev_VFW::GetDeviceFormats(string device, std::list *formats) { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); return VDEV_STATUS_OK; } /***************************************************************************************************** * Controls */ /* * set video control identified by id */ int VideoDev_VFW::SetDevCtrl(unsigned int id, int value) { return VDEV_STATUS_OK; }; /* * get video control identified by id */ int VideoDev_VFW::GetDevCtrl(unsigned int id, int *value) { return VDEV_STATUS_OK; };