|
|
@ -1,5 +1,6 @@
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* module to read video data from vfw.
|
|
|
|
* Module to grab video data from VfW interface. The interface is
|
|
|
|
|
|
|
|
* poorly documented for which some odd comments maybe found here.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "config.h"
|
|
|
@ -15,26 +16,36 @@
|
|
|
|
#include "convert.h"
|
|
|
|
#include "convert.h"
|
|
|
|
#include "videodev-vfw.h"
|
|
|
|
#include "videodev-vfw.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char classNameVfW[] = "VFW-Class";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Constructor
|
|
|
|
|
|
|
|
*/
|
|
|
|
VideoDev_VFW::VideoDev_VFW() {
|
|
|
|
VideoDev_VFW::VideoDev_VFW() {
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
hwnd = cap = NULL;
|
|
|
|
hwnd = cap = NULL;
|
|
|
|
camid = -1;
|
|
|
|
camid = -1;
|
|
|
|
inframe_pixfmt = 0x0;
|
|
|
|
inframe_pixfmt = 0x0;
|
|
|
|
inframe_w = -1;
|
|
|
|
inframe_w = -1;
|
|
|
|
inframe_h = -1;
|
|
|
|
inframe_h = -1;
|
|
|
|
inframe = NULL;
|
|
|
|
inframe = NULL;
|
|
|
|
inframe_size = 0;
|
|
|
|
inframe_size = 0;
|
|
|
|
vfw_size = 0;
|
|
|
|
vfw_size = 0;
|
|
|
|
|
|
|
|
hclass = NULL;
|
|
|
|
|
|
|
|
hinst = NULL;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Destructor
|
|
|
|
|
|
|
|
*/
|
|
|
|
VideoDev_VFW::~VideoDev_VFW() {
|
|
|
|
VideoDev_VFW::~VideoDev_VFW() {
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (running > 0) CaptureStop();
|
|
|
|
if (running > 0)
|
|
|
|
|
|
|
|
CaptureStop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* check for connected devices and return the result in a list.
|
|
|
|
* Check for connected devices and returns the result in a list.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int VideoDev_VFW::GetDeviceList(std::list<std::string> *list) {
|
|
|
|
int VideoDev_VFW::GetDeviceList(std::list<std::string> *list) {
|
|
|
|
|
|
|
|
|
|
|
@ -43,9 +54,11 @@ int VideoDev_VFW::GetDeviceList(std::list<std::string> *list) {
|
|
|
|
|
|
|
|
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (list == NULL) return VDEV_STATUS_ERROR;
|
|
|
|
if (list == NULL) return VDEV_STATUS_ERROR;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// go through a list of 10 (maximum number defined by VfW)
|
|
|
|
for(int i=0; i < 10; i++)
|
|
|
|
for(int i=0; i < 10; i++)
|
|
|
|
if(capGetDriverDescription(i, name, sizeof(name), desc, sizeof(desc))) {
|
|
|
|
if(capGetDriverDescription(i, name, sizeof(name), desc, sizeof(desc))) {
|
|
|
|
|
|
|
|
// create a driver for the return list
|
|
|
|
std::string device;
|
|
|
|
std::string device;
|
|
|
|
device = "VFW " + to_string(i) + " " + (string)name + " [" + (string)desc + "]";
|
|
|
|
device = "VFW " + to_string(i) + " " + (string)name + " [" + (string)desc + "]";
|
|
|
|
printf ("%s:%d %s Found device '%s'\n", __FILE__, __LINE__, __FUNCTION__, device.c_str());
|
|
|
|
printf ("%s:%d %s Found device '%s'\n", __FILE__, __LINE__, __FUNCTION__, device.c_str());
|
|
|
@ -56,57 +69,118 @@ int VideoDev_VFW::GetDeviceList(std::list<std::string> *list) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Open Device
|
|
|
|
* Destroy and unregister window class.
|
|
|
|
* prepare the buffer
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int VideoDev_VFW::Open() {
|
|
|
|
int VideoDev_VFW::DestroyClass() {
|
|
|
|
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
|
|
|
if (hclass) {
|
|
|
|
|
|
|
|
if(!UnregisterClass(classNameVfW, hinst)) {
|
|
|
|
|
|
|
|
printf ("%s:%d %s Could not unregister VFW class\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
free (hclass);
|
|
|
|
|
|
|
|
hclass = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Create and register window class.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
int VideoDev_VFW::CreateClass() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
|
|
|
if (hclass) return 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hclass = (WNDCLASSEX *)malloc(sizeof(WNDCLASSEX));
|
|
|
|
|
|
|
|
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 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* The callback is run when an error in the capture driver occurred.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int first = 1;
|
|
|
|
/*
|
|
|
|
|
|
|
|
* The callback is run when a status update in the capture driver occurred.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
LRESULT VFW_status_callback (HWND h, int nID, LPCSTR lpsz) {
|
|
|
|
|
|
|
|
printf("%s:%d %s id=%d (%s)\n", __FILE__, __LINE__, __FUNCTION__, nID, lpsz);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define USE_PREVIEW 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Opens the device.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
int VideoDev_VFW::Open() {
|
|
|
|
|
|
|
|
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// extract camera id from device name
|
|
|
|
camid = atoi (conf_device.c_str());
|
|
|
|
camid = atoi (conf_device.c_str());
|
|
|
|
printf ("%s:%d %s Opening VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
printf ("%s:%d %s Opening VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
|
|
|
|
|
|
|
|
// create parent window
|
|
|
|
// find application instance handle for later use
|
|
|
|
//HWND main_hwnd = (HWND)GDK_WINDOW_HWND (gtk_widget_get_window (GTK_WIDGET(main_window)));
|
|
|
|
hinst = GetModuleHandle(NULL);
|
|
|
|
HINSTANCE hinst = GetModuleHandle(NULL);
|
|
|
|
|
|
|
|
char classNameVfW[] = "VFW-Class";
|
|
|
|
// create and register window class
|
|
|
|
|
|
|
|
if (!CreateClass())
|
|
|
|
if (first) {
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
WNDCLASSEX hclass;
|
|
|
|
|
|
|
|
hclass.hInstance=hinst;
|
|
|
|
// now create the parent window for capture devicey
|
|
|
|
hclass.lpszClassName=classNameVfW;
|
|
|
|
// some notes:
|
|
|
|
hclass.lpfnWndProc=DefWindowProc;
|
|
|
|
// - the minimum possible size of 3x3
|
|
|
|
hclass.style=CS_DBLCLKS;
|
|
|
|
// - the WS_POPUPWINDOW removes window decorations
|
|
|
|
hclass.cbSize=sizeof(WNDCLASSEX);
|
|
|
|
// - it does not need a parent window
|
|
|
|
hclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
|
|
|
|
// - the window MUST be visible, otherwise video grabbing does not work (no callbacks run)
|
|
|
|
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);
|
|
|
|
hwnd = CreateWindowEx(0, classNameVfW, "CameraPreview", WS_POPUPWINDOW|WS_VISIBLE, 0, 0, 3, 3, NULL, NULL, hinst, NULL);
|
|
|
|
if (hwnd == NULL) {
|
|
|
|
if (!hwnd) {
|
|
|
|
printf ("%s:%d %s Could not create window (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
|
|
printf ("%s:%d %s Could not create window (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ShowWindow(hwnd, SW_SHOW);
|
|
|
|
if(!ShowWindow(hwnd, SW_SHOW)) {
|
|
|
|
|
|
|
|
printf ("%s:%d %s Could not show window (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
|
|
// connect to driver
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create capture driver window handle, also here minim size is 1x1
|
|
|
|
cap = capCreateCaptureWindow("VFW", WS_CHILD|WS_VISIBLE, 0, 0, 1, 1, hwnd, camid);
|
|
|
|
cap = capCreateCaptureWindow("VFW", WS_CHILD|WS_VISIBLE, 0, 0, 1, 1, hwnd, camid);
|
|
|
|
if(!cap) {
|
|
|
|
if(!cap) {
|
|
|
|
printf ("%s:%d %s Could not open VFW id %d window\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
printf ("%s:%d %s Could not open VFW id %d window\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!capSetCallbackOnStatus(cap, VFW_status_callback)) {
|
|
|
|
|
|
|
|
printf ("%s:%d %s Could not set status callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
|
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!capSetCallbackOnError(cap, VFW_error_callback)) {
|
|
|
|
|
|
|
|
printf ("%s:%d %s Could not set error callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
|
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// connect to driver
|
|
|
|
if(!capDriverConnect(cap, camid)) {
|
|
|
|
if(!capDriverConnect(cap, camid)) {
|
|
|
|
printf ("%s:%d %s Could not connect to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
printf ("%s:%d %s Could not connect to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
@ -115,9 +189,13 @@ int VideoDev_VFW::Open() {
|
|
|
|
// let the callbacks know this class pointer
|
|
|
|
// let the callbacks know this class pointer
|
|
|
|
capSetUserData(cap, this);
|
|
|
|
capSetUserData(cap, this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// set video source, capture format and size
|
|
|
|
|
|
|
|
capDlgVideoSource(cap);
|
|
|
|
|
|
|
|
capDlgVideoFormat(cap);
|
|
|
|
|
|
|
|
|
|
|
|
CAPTUREPARMS cp;
|
|
|
|
CAPTUREPARMS cp;
|
|
|
|
if(!capCaptureGetSetup(cap, &cp, sizeof(cp))) {
|
|
|
|
if(!capCaptureGetSetup(cap, &cp, sizeof(cp))) {
|
|
|
|
printf ("%s:%d %s Could not get VFW setup\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s Could not get VFW capture setup\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cp.dwRequestMicroSecPerFrame = 33333;
|
|
|
|
cp.dwRequestMicroSecPerFrame = 33333;
|
|
|
@ -131,20 +209,10 @@ int VideoDev_VFW::Open() {
|
|
|
|
cp.fAbortRightMouse = 0;
|
|
|
|
cp.fAbortRightMouse = 0;
|
|
|
|
cp.fLimitEnabled = 0;
|
|
|
|
cp.fLimitEnabled = 0;
|
|
|
|
if(!capCaptureSetSetup(cap, &cp, sizeof(cp))) {
|
|
|
|
if(!capCaptureSetSetup(cap, &cp, sizeof(cp))) {
|
|
|
|
printf ("%s:%d %s Could not set VFW setup\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s Could not set VFW capture setup\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
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
|
|
|
|
// get current valid width/height
|
|
|
|
BITMAPINFO bi;
|
|
|
|
BITMAPINFO bi;
|
|
|
|
int i = 0;
|
|
|
|
int i = 0;
|
|
|
@ -158,14 +226,15 @@ int VideoDev_VFW::Open() {
|
|
|
|
|
|
|
|
|
|
|
|
// try to set the configured width/height
|
|
|
|
// try to set the configured width/height
|
|
|
|
if(conf_width != -1) {
|
|
|
|
if(conf_width != -1) {
|
|
|
|
bi.bmiHeader.biWidth = conf_width;
|
|
|
|
inframe_w = bi.bmiHeader.biWidth = conf_width;
|
|
|
|
bi.bmiHeader.biHeight = conf_height;
|
|
|
|
inframe_h = bi.bmiHeader.biHeight = conf_height;
|
|
|
|
bi.bmiHeader.biCompression = inframe_pixfmt;
|
|
|
|
bi.bmiHeader.biCompression = inframe_pixfmt;
|
|
|
|
if(!capSetVideoFormat(cap, &bi, sizeof(BITMAPINFO))) {
|
|
|
|
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());
|
|
|
|
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;
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// find out maximum resolution
|
|
|
|
// find out maximum resolution
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
int sizes[][2] = {{320, 240}, {640, 480}, {800, 600}, {1024, 768}, {1280, 720}, {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}};
|
|
|
@ -175,18 +244,18 @@ int VideoDev_VFW::Open() {
|
|
|
|
inframe_h = bi.bmiHeader.biHeight = sizes[i][1];
|
|
|
|
inframe_h = bi.bmiHeader.biHeight = sizes[i][1];
|
|
|
|
bi.bmiHeader.biCompression = inframe_pixfmt;
|
|
|
|
bi.bmiHeader.biCompression = inframe_pixfmt;
|
|
|
|
if(capSetVideoFormat(cap, &bi, sizeof(BITMAPINFO))) {
|
|
|
|
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());
|
|
|
|
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) {
|
|
|
|
if (inframe_w >= conf_width && inframe_h >= conf_height) {
|
|
|
|
conf_width = inframe_w;
|
|
|
|
conf_width = inframe_w;
|
|
|
|
conf_height = inframe_h;
|
|
|
|
conf_height = inframe_h;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// translate this special format to what our convert functions can work with
|
|
|
|
// translate this special format to what our convert functions can work with
|
|
|
|
if(inframe_pixfmt == V4L2_PIX_FMT_YUY2) {
|
|
|
|
if (inframe_pixfmt == V4L2_PIX_FMT_YUY2) {
|
|
|
|
inframe_pixfmt = V4L2_PIX_FMT_YUYV;
|
|
|
|
inframe_pixfmt = V4L2_PIX_FMT_YUYV;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -195,8 +264,7 @@ int VideoDev_VFW::Open() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Close Device
|
|
|
|
* Close the device.
|
|
|
|
* Free videobuffer
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int VideoDev_VFW::Close() {
|
|
|
|
int VideoDev_VFW::Close() {
|
|
|
|
|
|
|
|
|
|
|
@ -207,6 +275,7 @@ int VideoDev_VFW::Close() {
|
|
|
|
DestroyWindow(hwnd);
|
|
|
|
DestroyWindow(hwnd);
|
|
|
|
hwnd = cap = NULL;
|
|
|
|
hwnd = cap = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DestroyClass();
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -216,22 +285,21 @@ int VideoDev_VFW::Close() {
|
|
|
|
* VideoGrabbing
|
|
|
|
* VideoGrabbing
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
LRESULT CALLBACK VFW_frame_callback(HWND h, LPVIDEOHDR v) {
|
|
|
|
/*
|
|
|
|
|
|
|
|
* The callback is run when a new frame is available. It copies the
|
|
|
|
|
|
|
|
* available data into the framebuffer of the class instance.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
LRESULT CALLBACK VFW_frame_callback (HWND h, LPVIDEOHDR v) {
|
|
|
|
VideoDev_VFW * obj = (VideoDev_VFW *)capGetUserData(h);
|
|
|
|
VideoDev_VFW * obj = (VideoDev_VFW *)capGetUserData(h);
|
|
|
|
obj->SetFrameBufferSize(v->dwBytesUsed);
|
|
|
|
obj->SetFrameBufferSize(v->dwBytesUsed);
|
|
|
|
memcpy(obj->GetFrameBuffer(), v->lpData, obj->GetFrameBufferSize());
|
|
|
|
memcpy(obj->GetFrameBuffer(), v->lpData, obj->GetFrameBufferSize());
|
|
|
|
return TRUE;
|
|
|
|
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
|
|
|
|
* Prepare inframe for raw picture data, will hold a video frame with
|
|
|
|
* inframe size = 4*W*H
|
|
|
|
* maximum size of inframe size = 4*W*H. Setup capture
|
|
|
|
* send the start capture signal to the cam
|
|
|
|
* callbacks. Then send the start capture signal to the camera.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int VideoDev_VFW::CaptureStart() {
|
|
|
|
int VideoDev_VFW::CaptureStart() {
|
|
|
|
|
|
|
|
|
|
|
@ -240,41 +308,53 @@ int VideoDev_VFW::CaptureStart() {
|
|
|
|
// allocate memory for frame data
|
|
|
|
// allocate memory for frame data
|
|
|
|
if (inframe != NULL) free (inframe);
|
|
|
|
if (inframe != NULL) free (inframe);
|
|
|
|
inframe_size = 4 * inframe_w * inframe_h;
|
|
|
|
inframe_size = 4 * inframe_w * inframe_h;
|
|
|
|
inframe = (unsigned char*) malloc(inframe_size);
|
|
|
|
inframe = (unsigned char *) malloc(inframe_size);
|
|
|
|
|
|
|
|
|
|
|
|
pixelformat = inframe_pixfmt;
|
|
|
|
pixelformat = inframe_pixfmt;
|
|
|
|
|
|
|
|
|
|
|
|
if(!capSetCallbackOnError(cap, VFW_error_callback)) {
|
|
|
|
// disable overlay
|
|
|
|
printf ("%s:%d %s Could not set error callback to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
capOverlay(cap, FALSE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if USE_PREVIEW
|
|
|
|
|
|
|
|
// use preview window for grabbing
|
|
|
|
|
|
|
|
capPreviewRate (cap, 10); // rate in ms
|
|
|
|
|
|
|
|
capPreviewScale (cap, FALSE);
|
|
|
|
|
|
|
|
capPreview (cap, TRUE);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
// otherwise use other capture
|
|
|
|
|
|
|
|
capPreview (cap, FALSE);
|
|
|
|
|
|
|
|
if(!capCaptureSequenceNoFile (cap)) {
|
|
|
|
|
|
|
|
printf ("%s:%d %s Could not start capture (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!capSetCallbackOnFrame(cap, VFW_frame_callback)) {
|
|
|
|
|
|
|
|
printf ("%s:%d %s Could not set frame callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(!capSetCallbackOnVideoStream(cap, VFW_frame_callback)) {
|
|
|
|
if(!capSetCallbackOnVideoStream(cap, VFW_frame_callback)) {
|
|
|
|
printf ("%s:%d %s Could not set videostream callback to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
printf ("%s:%d %s Could not set videostream callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
//return VDEV_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(!capSetCallbackOnYield(cap, VFW_frame_callback)) {
|
|
|
|
if(!capSetCallbackOnYield(cap, VFW_frame_callback)) {
|
|
|
|
printf ("%s:%d %s Cmould not set yield callback to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
|
|
printf ("%s:%d %s Could not set yield callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
//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;
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* free inbuffer
|
|
|
|
* Stop capture and free framebuffer.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int VideoDev_VFW::CaptureStop() {
|
|
|
|
int VideoDev_VFW::CaptureStop() {
|
|
|
|
|
|
|
|
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
|
|
|
|
|
|
|
capCaptureAbort(cap);
|
|
|
|
capCaptureAbort(cap);
|
|
|
|
capSetCallbackOnError(cap, NULL);
|
|
|
|
capSetCallbackOnError(cap, NULL);
|
|
|
|
capSetCallbackOnFrame(cap, NULL);
|
|
|
|
capSetCallbackOnFrame(cap, NULL);
|
|
|
@ -292,35 +372,47 @@ int VideoDev_VFW::CaptureStop() {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* try to grab one frame and convert it into RGB32.
|
|
|
|
* This function needed to continue running the capture window.
|
|
|
|
* 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
|
|
|
|
void VideoDev_VFW::HandleMessages() {
|
|
|
|
int VideoDev_VFW::Grab(VideoFrameRaw *vf) {
|
|
|
|
MSG msg;
|
|
|
|
|
|
|
|
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
|
|
|
|
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MSG msg;
|
|
|
|
|
|
|
|
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
|
|
|
|
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (inframe == NULL) return VDEV_STATUS_ERROR;
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Try to grab one frame and copy it into raw video buffer. 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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
int VideoDev_VFW::Grab(VideoFrameRaw *vf) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HandleMessages();
|
|
|
|
|
|
|
|
if (inframe == NULL) return VDEV_STATUS_ERROR;
|
|
|
|
|
|
|
|
|
|
|
|
if (GetFrameBufferSize() > 0) {
|
|
|
|
if (GetFrameBufferSize() > 0) {
|
|
|
|
LockMutex();
|
|
|
|
LockMutex();
|
|
|
|
vf->CopyFrom(inframe_pixfmt, inframe_w, inframe_h, GetFrameBufferSize(), inframe);
|
|
|
|
vf->CopyFrom(inframe_pixfmt, inframe_w, inframe_h, GetFrameBufferSize(), inframe);
|
|
|
|
UnLockMutex();
|
|
|
|
UnLockMutex();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
return VDEV_STATUS_AGAIN;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* For VfW this seems difficult / impossible to obtain the supported
|
|
|
|
|
|
|
|
* video formats, but they must be selected via capDlgVideoFormat().
|
|
|
|
|
|
|
|
*/
|
|
|
|
int VideoDev_VFW::GetDeviceFormats(string device, std::list<string> *formats) {
|
|
|
|
int VideoDev_VFW::GetDeviceFormats(string device, std::list<string> *formats) {
|
|
|
|
|
|
|
|
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
|
|
|
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -334,7 +426,6 @@ int VideoDev_VFW::GetDeviceFormats(string device, std::list<string> *formats) {
|
|
|
|
* set video control identified by id
|
|
|
|
* set video control identified by id
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int VideoDev_VFW::SetDevCtrl(unsigned int id, int value) {
|
|
|
|
int VideoDev_VFW::SetDevCtrl(unsigned int id, int value) {
|
|
|
|
|
|
|
|
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|