yes, i am using DSVL and it works very well.
i had to apply some changes to it to compile on current visual studio, make it more safe and stable, easier to debug, etc.
and i implemented my own framegrabber class which is just my very own rewrite of the reactivision source.
i am sorry i can’t give you the whole code, but this is what the major parts look like.
i am still having a problem with my logitech webcam and DSVL. i get a nasty BSOD, i guess the directshow filter driver is somehow unstable.
header:
#ifndef __FRAMEGRABBER_HPP
#define __FRAMEGRABBER_HPP
#include <string>
//put COM header(s) here
#include "util/NoCopy.hpp"
#include "DSVL.h"
/*
* FrameGrabber class
* aka SampleGrabber, Sampler, ...
*
* can open camera stream (directshow)
* can grab current frame
* can be configured by xml strings -> i.e.: std::string config("<?xml version=\"1.0\" encoding=\"UTF-8\"?><dsvl_input><camera friendly_name=\"AVT 1394 camera\" show_format_dialog=\"true\"><pixel_format><RGB32/></pixel_format></camera></dsvl_input>");
*/
class FrameGrabber : public ext::NoCopy
{
public:
FrameGrabber(const std::string& configXmlString);
~FrameGrabber();
bool Start();
void Stop(bool forceToStop = false);
bool Initialize(const std::string& config);
inline bool IsInitialized() const { return isInitialized; }
void ShowSettings() const;
void GetCurrentFrameData(unsigned char* dst);
uint GetNumberOf8BitChannels() const;
uint GetWidth() const;
uint GetHeight() const;
int HasDroppedFrames() const;
private:
void getMediaFormatValues();
bool isInitialized;
DSVL_VideoSource* videoSource;
MemoryBufferHandle mbHandle;
LONGLONG timeStamp;
uint width;
uint height;
PIXELFORMAT format;
uint numBytes;
float fps;
unsigned char* buffer; //opaque handle to pixels, no need to clean up!
std::string config; //for saving and reloading
};
#endif
implementation:
#include <cassert>
#include <cstdio>
#include "FrameGrabber.hpp"
FrameGrabber::FrameGrabber(const std::string& configXmlString)
: isInitialized(false)
, videoSource (0)
, timeStamp (0)
, width (0)
, height (0)
, format (PIXELFORMAT_UNKNOWN)
, numBytes (0)
, fps (0.f)
, buffer (0)
, config (configXmlString)
{
//put your COM initialization routine here!
videoSource = new DSVL_VideoSource();
assert(videoSource);
if (videoSource)
{
if (Initialize(configXmlString))
{
isInitialized = true;
printf("[INFO] DSVL based framegrabber successfully initialized\n");
}
else
{
printf("[ERROR] could NOT initialize DSVL based framegrabber with configstring:\n\t%s\n\n", configXmlString.c_str());
}
}
else
{
printf("[ERROR] could NOT allocate DSVL video source\n");
}
}
FrameGrabber::~FrameGrabber()
{
Stop();
if (videoSource)
{
videoSource->DisableMemoryBuffer();
delete videoSource;
videoSource = 0;
}
//deinitialize COM here, but could be a problem when you construct more than one instance
}
bool FrameGrabber::Initialize(const std::string& config)
{
assert(videoSource);
if (FAILED(videoSource->BuildGraphFromXMLString(const_cast<char*>(config.c_str()))))
{
printf("[ERROR] could NOT build filtergraph\n");
return false;
}
getMediaFormatValues();
return true;
}
void FrameGrabber::getMediaFormatValues()
{
//get current values
LONG w = 0;
LONG h = 0;
double f = 0.0;
PIXELFORMAT pxf;
assert(videoSource);
if (FAILED(videoSource->GetCurrentMediaFormat(&w, &h, &f, &pxf)))
{
printf("[ERROR] could NOT retrieve media format\n");
return;
}
//assign values back to class members
width = w;
height = h;
fps = f;
format = pxf;
printf("[INFO] chosen mediaformat: w=%d h=%d fps=%.f format=%d\n", w, h, f, pxf);
numBytes = 1; //choose grayscale as default
//print info and set number of bytes (components, channels)
switch (pxf)
{
//--- only handle the two most important cases here!! ---
case PIXELFORMAT_RGB24:
numBytes = 3;
printf("[INFO] current pixel format is RGB24\n");
break;
case PIXELFORMAT_RGB32:
numBytes = 4;
printf("[INFO] current pixel format is RGB32\n");
break;
//--------------------------------------
default:
printf("[WARNING] something is wrong with current pixel format\n");
break;
}
}
bool FrameGrabber::Start()
{
if (!isInitialized)
{
printf("[ERROR] could NOT start streaming, NOT initialized yet\n");
return false;
}
//TODO: replace this naive checks
assert(format != PIXELFORMAT_UNKNOWN);
assert(format != PIXELFORMAT_INVALID);
assert(numBytes > 0);
assert(width > 0);
assert(height > 0);
assert(fps > 0);
assert(videoSource);
printf("[INFO] trying to enable sample memory buffer and start querying threads\n");
if (FAILED(videoSource->EnableMemoryBuffer(3))) //here 3 concurrent threads will concurrently query for samples
{
printf("[ERROR] could NOT start streaming\n");
return false;
}
printf("[INFO] trying to start streaming\n");
if (FAILED(videoSource->Run()))
{
printf("[ERROR] could NOT start streaming\n");
return false;
}
return true;
}
void FrameGrabber::Stop(bool forceToStop)
{
printf("[INFO] trying to stop streaming\n");
assert(videoSource);
if (videoSource)
videoSource->Stop(forceToStop);
}
void FrameGrabber::GetCurrentFrameData(unsigned char* dst)
{
assert(videoSource);
assert(videoSource->IsGraphInitialized());
assert(dst);
if (!videoSource || !videoSource->IsGraphInitialized() || !dst)
{
printf("[WARNING] can NOT grab current frame\n");
return;
}
//taken from reactivision source (dslibcamera.cpp), magic values?, better strategy?
DWORD wait_result = videoSource->WaitForNextSample(/*INFINITE*/ (long)(100.f / fps));
/*if (wait_result != WAIT_OBJECT_0)
{
//wait another 1.5 seconds
wait_result = videoSource->WaitForNextSample(1500);
if (wait_result != WAIT_OBJECT_0)
{
//printf("[WARNING] camera stopped\n");
//Stop();
}
}*/
//if (wait_result == WAIT_OBJECT_0)
{
if (SUCCEEDED(videoSource->CheckoutMemoryBuffer(&mbHandle, &buffer)))
{
timeStamp = videoSource->GetCurrentTimestamp();
//printf("LIVE VIDEO TIMESTAMP: %d\n", timeStamp);
//prepare array
::memcpy(dst, buffer, width*height*numBytes); //3 works with RGB24
videoSource->CheckinMemoryBuffer(mbHandle);
buffer = 0;
}
else
{
printf("[WARNING] could NOT checkout membuffer (get sample)\n");
}
}
/*else
{
printf("[WARNING] could NOT aquire camera input\n");
}*/
}
uint FrameGrabber::GetNumberOf8BitChannels() const
{
return numBytes;
}
uint FrameGrabber::GetWidth() const
{
return width;
}
uint FrameGrabber::GetHeight() const
{
return height;
}
void FrameGrabber::ShowSettings() const
{
assert(videoSource);
if (videoSource && videoSource->IsGraphInitialized())
videoSource->ShowFilterProperties();
else
printf("[ERROR] can NOT show settings, NOT initialized yet\n");
}
int FrameGrabber::HasDroppedFrames() const
{
assert(videoSource);
int numDroppedFrames = 0;
numDroppedFrames = videoSource->HasDroppedFrames();
return numDroppedFrames;
}
USAGE:
you need in your TestApp:
FrameGrabber* framegrabber;
colorImage* video; //for processing further, similar like openframeworks opencv addon image
unsigned char* videoData; //to read out of capture device
in
void TestApp::setup()
{
//...
//debug/test strings, could be external xml file
std::string config = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dsvl_input><camera friendly_name=\"AVT 1394 camera\" show_format_dialog=\"false\"><pixel_format><RGB24 /></pixel_format></camera></dsvl_input>";
framegrabber = new FrameGrabber(config);
assert(framegrabber);
if (framegrabber && framegrabber->IsInitialized())
{
//framegrabber->ShowSettings(); //to force to show settings
framegrabber->Start();
int numChannels = framegrabber->GetNumberOf8BitChannels(); //NOTE: it is very important for the array (char) that it is 8 bit!
if (numChannels == 3) //RGB (RGB24)
{
video = new colorImage(camWidth, camHeight, false, false);
assert(video);
videoData = new unsigned char[camWidth*camHeight*numChannels];
assert(videoData);
ZERO_MEMORY(videoData, camWidth*camHeight*numChannels);
}
else
if (numChannels == 4) //RGBA
{
printf("[ERROR] RGBA format NOT implemented yet\n");
}
else
if (numChannels == 1) //GRAYSCALE, default return value
{
printf("[ERROR] grayscale format NOT implemented yet\n");
}
else //0, ctor default
{
printf("[ERROR] invalid return value for media format / number of channels (%d)\n", numChannels);
}
}
else
{
printf("[FATAL] could NOT allocate or initialize framegrabber\n");
}
}
in
void TestApp::update()
{
assert(framegrabber);
if (framegrabber)
{
assert(videoData);
framegrabber->GetCurrentFrameData(videoData);
assert(video);
if (video)
{
video->setFromNonIppImage(videoData, camWidth, camHeight, camWidth*framegrabber->GetNumberOf8BitChannels());
//video is not ready for drawing!
}
}
}
i hope this helps! tell me if you need the changed DSVL sourcecode (a pity that this software is not mainteined anymore).
cheers, didi