You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SimpleSkyCam/videodev-vfw.cc

280 lines
7.4 KiB

/*
* module to read video data from vfw.
*/
#include "config.h"
#include <windows.h>
#include <windowsx.h>
#include <vfw.h>
#include <aviriff.h>
#include <list>
#include <string>
#include "convert.h"
#include "videodev-vfw.h"
VideoDev_VFW::VideoDev_VFW() {
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
cap = NULL;
};
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<std::string> *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 + "]";
list->push_back(device);
}
return VDEV_STATUS_OK;
}
/*
* Open Device
* prepare the buffer
*/
int VideoDev_VFW::Open() {
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);
cap = capCreateCaptureWindow("VfW", /*WS_CHILD|WS_VISIBLE*/0, 0, 0, 0, 0, 0/*HWND_MESSAGE*/, 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;
}
capDlgVideoFormat(cap);
// get current valid width/height
BITMAPINFO bi;
int w, h, 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_pixfmt = convert_to_pixelformat(conf_format);
// 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, 1024}, {1920, 1080}, {-1, -1}};
while(sizes[i][0] != -1) {
w = bi.bmiHeader.biWidth = sizes[i][0];
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;
}
}
i++;
}
}
printf ("%s:%d %s Current capture format is %s\n", __FILE__, __LINE__, __FUNCTION__, conf_format.c_str());
return VDEV_STATUS_OK;
};
/*
* Close Device
* Free videobuffer
*/
int VideoDev_VFW::Close() {
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
capDriverDisconnect(cap);
return VDEV_STATUS_OK;
};
/*****************************************************************************************************
* 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);
return TRUE;
}
LRESULT VFW_error_callback(HWND h, int nID, LPCSTR lpsz) {
printf("error callback: %d (%s)\n", 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__);
if(!capSetCallbackOnError(cap, VFW_error_callback)) {
printf ("%s:%d %s Could not set error callback to VfW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
}
if(!capSetCallbackOnFrame(cap, VFW_frame_callback)) {
printf ("%s:%d %s Could not set frame callback to VfW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
}
ConvertStart(&cdata, inframe_pixfmt);
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);
ConvertStop(&cdata, inframe_pixfmt);
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(VideoFrame *vf) {
//if (inframe == NULL) return VDEV_STATUS_ERROR;
LockMutex();
Convert(&cdata, vf, VFW_frame_buffer, VFW_frame_size, inframe_pixfmt, conf_width, conf_height);
UnLockMutex();
return VDEV_STATUS_OK;
}
int VideoDev_VFW::GetDeviceFormats(string device, std::list<string> *formats) {
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
camid = atoi (conf_device.c_str());
cap = capCreateCaptureWindow("VfW", /*WS_CHILD|WS_VISIBLE*/0, 0, 0, 0, 0, 0/*HWND_MESSAGE*/, 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;
}
BITMAPINFO bi;
capGetVideoFormat(cap, &bi, sizeof(BITMAPINFO));
string vfwformat;
DWORD f = bi.bmiHeader.biCompression;
vfwformat = convert_from_pixelformat(f);
printf ("%s:%d %s Current capture format is %s\n", __FILE__, __LINE__, __FUNCTION__, vfwformat.c_str());
formats->push_back(vfwformat);
#if 0
int i = 0;
DWORD vfwformats[][2] = {{MAKEFOURCC('M','J','P','G'), V4L2_PIX_FMT_MJPEG},
{MAKEFOURCC('Y','U','V','2'), V4L2_PIX_FMT_YUV2},
{0, 0}};
while(vfwformats[i][0] != 0) {
bi.bmiHeader.biCompression = vfwformats[i][0];
if(capSetVideoFormat(cap, &bi, sizeof(BITMAPINFO))) {
vfwformat = convert_from_pixelformat(vfwformats[i][1]);
printf ("%s:%d %s Capture format %s works\n", __FILE__, __LINE__, __FUNCTION__, vfwformat.c_str());
formats->push_back(vfwformat.c_str());
}
else {
vfwformat = convert_from_pixelformat(vfwformats[i][1]);
printf ("%s:%d %s Capture format %s does not work\n", __FILE__, __LINE__, __FUNCTION__, vfwformat.c_str());
}
i++;
}
#endif
capDriverDisconnect(cap);
cap = NULL;
camid = -1;
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;
};