jhshukla
asked on
USB Camera
Hi
I have a USB camera from Logitech (QuickCam 8 for Notebooks Pro) and need to write a C/C++ program to capture frames from it. I have no clue how to start.
Anyone heard of ARToolkit? That is what my boss wants me to use but I cannot find any kind of documentation for it.
Should I open system > device manager and look for the addresses used by the cam? isn't that a potential crash?
I have MS Spy++ that can list the PID, name and memory used by any process. I don't think that to read from some other prgm's mem would be a good idea either.
I have the device driver. if anybody could reverse engineer or hack it, that could be a great help.
thank you.
jaydutt
I have a USB camera from Logitech (QuickCam 8 for Notebooks Pro) and need to write a C/C++ program to capture frames from it. I have no clue how to start.
Anyone heard of ARToolkit? That is what my boss wants me to use but I cannot find any kind of documentation for it.
Should I open system > device manager and look for the addresses used by the cam? isn't that a potential crash?
I have MS Spy++ that can list the PID, name and memory used by any process. I don't think that to read from some other prgm's mem would be a good idea either.
I have the device driver. if anybody could reverse engineer or hack it, that could be a great help.
thank you.
jaydutt
I guess there must be some king of interface so different sorfwate can access the camera. I would try to post to the Programming Forum as it is more a programming issues than a hardware issue...
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
There would be no reason to reverse engineer/debug/hack the device driver unless you wanted to write another one yourself.
The capture functions from the Multimedia SDK seems to be a good idea, but unfortunately it's one I did not have when I needed to write a frame-capture application, so I went the DirectShow way.
Anyway, I have a minimal application (~200 lines) which uses DirectShow (DirectX SDK) to constantly capture frames from a selected capture device. I could also post fragments or the whole code.
The capture functions from the Multimedia SDK seems to be a good idea, but unfortunately it's one I did not have when I needed to write a frame-capture application, so I went the DirectShow way.
Anyway, I have a minimal application (~200 lines) which uses DirectShow (DirectX SDK) to constantly capture frames from a selected capture device. I could also post fragments or the whole code.
Actually, I will post the code anyway. Note that it was designed to be a test/trial code, not production code, and I have added the comments for you just two minutes ago. Most of the COM/DirectShow error-checking should be good, but I have some "quick-n-dirty" code for the "dumping the frame" and the loop parts. (Hell, I have an infinite goto-loop!)
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <objbase.h>
#include <dshow.h>
#include <qedit.h>
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
int main(void)
{
IGraphBuilder *filterGraph = NULL;
ICreateDevEnum *devenum = NULL;
IEnumMoniker *capenum = NULL;
IPropertyBag *capdevinfo = NULL;
IMoniker *capdev = NULL;
IMediaControl *MAC = NULL;
IMediaEvent *MAE = NULL;
ISampleGrabber *samplegrabber = NULL;
IBaseFilter *capfilter = NULL;
IBaseFilter *capgrabber = NULL;
IBaseFilter *capnull = NULL;
VARIANT v;
AM_MEDIA_TYPE mt;
/* Initialize COM */
if (FAILED(CoInitialize(NULL) )) {
printf("Failed to initialize COM.\n");
return -1;
}
/* Finding and selecting a device */
/* Create enumerator */
if (FAILED(CoCreateInstance(C LSID_Syste mDeviceEnu m, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **) &devenum))) {
printf("Failed to create SystemDeviceEnum instance.\n");
return -1;
}
/* Make it a video enumerator */
if (FAILED(devenum->CreateCla ssEnumerat or(CLSID_V ideoInputD eviceCateg ory, &capenum, 0))) {
printf("Failed to enumerate video capture devices.\n");
return -1;
}
if (capenum == NULL) {
printf("There are no video input devices available.\n");
return 1;
}
printf("The devices:\n");
while(capenum->Next(1, &capdev, NULL) == S_OK) {
if (FAILED(capdev->BindToStor age(NULL, NULL, IID_IPropertyBag, (void **) &capdevinfo))) {
printf("Failed to query capture device.\n");
return -1;
}
VariantInit(&v);
capdevinfo->Read(L"Friendl yName", &v, NULL);
printf("%S\n", v.bstrVal);
/* find the first device with the name "cam" in it :) */
if ((wcsstr(v.bstrVal, L"cam")) || (wcsstr(v.bstrVal, L"Cam")) || (wcsstr(v.bstrVal, L"CAM"))) {
if (FAILED(capdev->BindToObje ct(NULL, NULL, IID_IBaseFilter, (void **) &capfilter))) {
printf("Failed to bind to capture device.\n");
return -1;
} else {
break;
}
}
VariantClear(&v);
}
capdevinfo->Release();
capdev->Release();
capenum->Release();
devenum->Release();
/* Finding and selecting a device ends */
/* Create the Filter Graph - the main thing */
if (FAILED(CoCreateInstance(C LSID_Filte rGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) &filterGraph))) {
printf("Unable to create filter graph.\n");
return -1;
}
/* Media Control and Media Event interfaces for running/stopping the graph */
filterGraph->QueryInterfac e(IID_IMed iaControl, (void **) &MAC);
if (MAC == NULL) {
printf("Unable to query media control interface.\n");
return -1;
}
filterGraph->QueryInterfac e(IID_IMed iaEvent, (void **) &MAE);
if (MAE == NULL) {
printf("Unable to query media event interface.\n");
return -1;
}
/* Add the video source to graph */
/* Graph looks like:
Video Source
*/
if (filterGraph->AddFilter(ca pfilter, L"Video Source") != S_OK) {
printf("Unable to add source filter.\n");
return -1;
}
/* Create the BMP grabber */
if (FAILED(CoCreateInstance(C LSID_Sampl eGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **) &capgrabber))) {
printf("Unable to create video grabber.\n");
return -1;
}
capgrabber->QueryInterface (IID_ISamp leGrabber, (void **) &samplegrabber);
if (samplegrabber == NULL) {
printf("Unable to query video grabber interface.\n");
return -1;
}
/* Add grabber to graph */
/* Graph looks like:
Video Source Grabber
*/
if (FAILED(filterGraph->AddFi lter(capgr abber, L"Grabber"))) {
printf("Unable to add grabber filter.\n");
return -1;
}
/* Create the null renderer */
if (FAILED(CoCreateInstance(C LSID_NullR enderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **) &capnull))) {
printf("Unable to create null renderer.\n");
return -1;
}
/* Add null renderer to graph */
/* Graph looks like:
Video Source Grabber Null Renderer
*/
if (FAILED(filterGraph->AddFi lter(capnu ll, L"Null Renderer"))) {
printf("Unable to add null renderer filter.\n");
return -1;
}
/* Create and set up the media format for the capture */
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB32;
/* Webcam uses RGB32 although it has no alpha channel and thus returns '0'
every 4th byte in the frame */
mt.formattype = FORMAT_VideoInfo;
if (FAILED(samplegrabber->Set MediaType( &mt))) {
printf("Unable to set media type.\n");
return -1;
}
/* Get all the pins */
IEnumPins *pinenum;
IPin *cameraOut;
IPin *grabberIn;
IPin *grabberOut;
IPin *nullIn;
/* Find camera output pin */
capfilter->EnumPins(&pinen um);
pinenum->Reset();
pinenum->Next(1, &cameraOut, NULL);
pinenum->Release();
/* Find grabber input/output pins */
capgrabber->EnumPins(&pine num);
pinenum->Reset();
pinenum->Next(1, &grabberIn, NULL);
pinenum->Next(1, &grabberOut, NULL);
pinenum->Release();
/* Find null renderer input pin */
capnull->EnumPins(&pinenum );
pinenum->Reset();
pinenum->Next(1, &nullIn, NULL);
pinenum->Release();
/* Connect all the pins */
if (FAILED(filterGraph->Conne ct(cameraO ut, grabberIn))) {
printf("Unable to connect camera output pin.\n");
return -1;
} /* Graph looks like:
Video Source -> Grabber Null Renderer
*/
if (FAILED(filterGraph->Conne ct(grabber Out, nullIn))) {
printf("Unable to connect grabber output pin.\n");
return -1;
} /* Graph looks like:
Video Source -> Grabber -> Null Renderer
*/
/* Enable internal buffering (internal frame storage) for the grabber */
if (FAILED(samplegrabber->Set BufferSamp les(TRUE)) ) {
printf("Unable to set internal buffering.\n");
return -1;
}
/* We're capturing lots of frames, not 1, comment it out */
/* if (FAILED(samplegrabber->Set OneShot(TR UE))) {
printf("Unable to set one-shot grabbing.\n");
return -1;
}*/
hede:
if (FAILED(MAC->Run())) {
printf("Error running graph.\n");
return -1;
}
Sleep(3000);
/* This is needed for 1-frame capture too, comment it out */
/* long eventCode = 0;
if (FAILED(MAE->WaitForComple tion(INFIN ITE, &eventCode))) {
printf("Error waiting for completion.\n");
return -1;
}*/
long bufsize = 0;
char *buffer;
/* Get current frame from the internal buffer */
samplegrabber->GetCurrentB uffer(&buf size, NULL);
if (bufsize == 0) {
printf("Sample grabber does not have a buffer.\n");
return -1;
} else {
buffer = (char *) malloc(bufsize); /* VS.NET does not like uncasted mallocs, WTF?!? */
if (buffer == NULL) {
printf("Unable to allocate %u bytes of memory.\n", (unsigned) bufsize);
return -1;
}
}
samplegrabber->GetCurrentB uffer(&buf size, (long *) buffer);
/* Dump the frame into a temporary file */
FILE *of;
if ((of = fopen("C:\\TEMP\\test.bin" , "wb")) == NULL) return -2;
fwrite(buffer, bufsize, 1, of);
fclose(of);
free(buffer);
goto hede;
capgrabber->Release();
capfilter->Release();
capnull->Release();
filterGraph->Release();
CoUninitialize();
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <objbase.h>
#include <dshow.h>
#include <qedit.h>
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
int main(void)
{
IGraphBuilder *filterGraph = NULL;
ICreateDevEnum *devenum = NULL;
IEnumMoniker *capenum = NULL;
IPropertyBag *capdevinfo = NULL;
IMoniker *capdev = NULL;
IMediaControl *MAC = NULL;
IMediaEvent *MAE = NULL;
ISampleGrabber *samplegrabber = NULL;
IBaseFilter *capfilter = NULL;
IBaseFilter *capgrabber = NULL;
IBaseFilter *capnull = NULL;
VARIANT v;
AM_MEDIA_TYPE mt;
/* Initialize COM */
if (FAILED(CoInitialize(NULL)
printf("Failed to initialize COM.\n");
return -1;
}
/* Finding and selecting a device */
/* Create enumerator */
if (FAILED(CoCreateInstance(C
printf("Failed to create SystemDeviceEnum instance.\n");
return -1;
}
/* Make it a video enumerator */
if (FAILED(devenum->CreateCla
printf("Failed to enumerate video capture devices.\n");
return -1;
}
if (capenum == NULL) {
printf("There are no video input devices available.\n");
return 1;
}
printf("The devices:\n");
while(capenum->Next(1, &capdev, NULL) == S_OK) {
if (FAILED(capdev->BindToStor
printf("Failed to query capture device.\n");
return -1;
}
VariantInit(&v);
capdevinfo->Read(L"Friendl
printf("%S\n", v.bstrVal);
/* find the first device with the name "cam" in it :) */
if ((wcsstr(v.bstrVal, L"cam")) || (wcsstr(v.bstrVal, L"Cam")) || (wcsstr(v.bstrVal, L"CAM"))) {
if (FAILED(capdev->BindToObje
printf("Failed to bind to capture device.\n");
return -1;
} else {
break;
}
}
VariantClear(&v);
}
capdevinfo->Release();
capdev->Release();
capenum->Release();
devenum->Release();
/* Finding and selecting a device ends */
/* Create the Filter Graph - the main thing */
if (FAILED(CoCreateInstance(C
printf("Unable to create filter graph.\n");
return -1;
}
/* Media Control and Media Event interfaces for running/stopping the graph */
filterGraph->QueryInterfac
if (MAC == NULL) {
printf("Unable to query media control interface.\n");
return -1;
}
filterGraph->QueryInterfac
if (MAE == NULL) {
printf("Unable to query media event interface.\n");
return -1;
}
/* Add the video source to graph */
/* Graph looks like:
Video Source
*/
if (filterGraph->AddFilter(ca
printf("Unable to add source filter.\n");
return -1;
}
/* Create the BMP grabber */
if (FAILED(CoCreateInstance(C
printf("Unable to create video grabber.\n");
return -1;
}
capgrabber->QueryInterface
if (samplegrabber == NULL) {
printf("Unable to query video grabber interface.\n");
return -1;
}
/* Add grabber to graph */
/* Graph looks like:
Video Source Grabber
*/
if (FAILED(filterGraph->AddFi
printf("Unable to add grabber filter.\n");
return -1;
}
/* Create the null renderer */
if (FAILED(CoCreateInstance(C
printf("Unable to create null renderer.\n");
return -1;
}
/* Add null renderer to graph */
/* Graph looks like:
Video Source Grabber Null Renderer
*/
if (FAILED(filterGraph->AddFi
printf("Unable to add null renderer filter.\n");
return -1;
}
/* Create and set up the media format for the capture */
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB32;
/* Webcam uses RGB32 although it has no alpha channel and thus returns '0'
every 4th byte in the frame */
mt.formattype = FORMAT_VideoInfo;
if (FAILED(samplegrabber->Set
printf("Unable to set media type.\n");
return -1;
}
/* Get all the pins */
IEnumPins *pinenum;
IPin *cameraOut;
IPin *grabberIn;
IPin *grabberOut;
IPin *nullIn;
/* Find camera output pin */
capfilter->EnumPins(&pinen
pinenum->Reset();
pinenum->Next(1, &cameraOut, NULL);
pinenum->Release();
/* Find grabber input/output pins */
capgrabber->EnumPins(&pine
pinenum->Reset();
pinenum->Next(1, &grabberIn, NULL);
pinenum->Next(1, &grabberOut, NULL);
pinenum->Release();
/* Find null renderer input pin */
capnull->EnumPins(&pinenum
pinenum->Reset();
pinenum->Next(1, &nullIn, NULL);
pinenum->Release();
/* Connect all the pins */
if (FAILED(filterGraph->Conne
printf("Unable to connect camera output pin.\n");
return -1;
} /* Graph looks like:
Video Source -> Grabber Null Renderer
*/
if (FAILED(filterGraph->Conne
printf("Unable to connect grabber output pin.\n");
return -1;
} /* Graph looks like:
Video Source -> Grabber -> Null Renderer
*/
/* Enable internal buffering (internal frame storage) for the grabber */
if (FAILED(samplegrabber->Set
printf("Unable to set internal buffering.\n");
return -1;
}
/* We're capturing lots of frames, not 1, comment it out */
/* if (FAILED(samplegrabber->Set
printf("Unable to set one-shot grabbing.\n");
return -1;
}*/
hede:
if (FAILED(MAC->Run())) {
printf("Error running graph.\n");
return -1;
}
Sleep(3000);
/* This is needed for 1-frame capture too, comment it out */
/* long eventCode = 0;
if (FAILED(MAE->WaitForComple
printf("Error waiting for completion.\n");
return -1;
}*/
long bufsize = 0;
char *buffer;
/* Get current frame from the internal buffer */
samplegrabber->GetCurrentB
if (bufsize == 0) {
printf("Sample grabber does not have a buffer.\n");
return -1;
} else {
buffer = (char *) malloc(bufsize); /* VS.NET does not like uncasted mallocs, WTF?!? */
if (buffer == NULL) {
printf("Unable to allocate %u bytes of memory.\n", (unsigned) bufsize);
return -1;
}
}
samplegrabber->GetCurrentB
/* Dump the frame into a temporary file */
FILE *of;
if ((of = fopen("C:\\TEMP\\test.bin"
fwrite(buffer, bufsize, 1, of);
fclose(of);
free(buffer);
goto hede;
capgrabber->Release();
capfilter->Release();
capnull->Release();
filterGraph->Release();
CoUninitialize();
return 0;
}
no need for all these things
if ur camera supports TWAIN (and probably it is)
you can use one of many activex controls available on the internet
here u are 3 controls availble to try:
http://www.download.com/3120-20-0.html?qt=webcam&tg=dl-2026
if you're looking for a free/fast solution
install yahoo messenger
and u'll find a control used for video capture installed with it :)
Anyway, no need for reverse engineering, direct communication with the port, or even API calls...
never re-invent the wheels
if ur camera supports TWAIN (and probably it is)
you can use one of many activex controls available on the internet
here u are 3 controls availble to try:
http://www.download.com/3120-20-0.html?qt=webcam&tg=dl-2026
if you're looking for a free/fast solution
install yahoo messenger
and u'll find a control used for video capture installed with it :)
Anyway, no need for reverse engineering, direct communication with the port, or even API calls...
never re-invent the wheels
ASKER
I have posted a link to this question is C/C++ forums as suggested by valadas2.
and i will try out the things suggested by all of you. i have to go to work now so i will post the further development tomorrow.
thx for help so far and if possible please try to locate ARToolkit documentation for me. (Google: ARToolkit Download)
thx again.
jaydutt
and i will try out the things suggested by all of you. i have to go to work now so i will post the further development tomorrow.
thx for help so far and if possible please try to locate ARToolkit documentation for me. (Google: ARToolkit Download)
thx again.
jaydutt
Note that most of the TWAIN-compatible cameras pop up a camera driver-supplied "capture" dialog which ruins the "capture frames without intervention from the user" aspect of such projects.
ASKER
Ok I tried out everything that was suggested here and would prefer to follow Alex's suggestions.
@Alex (but everyone is welcome!)
I was going through SDK Documentation and found this variable called DeviceDriverIndex/DriverIn dex/wIndex etc that can range from 0-9.
How can I find the index of the driver I want to use?
thx
@Alex (but everyone is welcome!)
I was going through SDK Documentation and found this variable called DeviceDriverIndex/DriverIn
How can I find the index of the driver I want to use?
thx
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I tried using capCreateCaptureWindow but it gives me "unresolved external" error. Apparently, it is replaced by _capCreateCaptureWindowA in compiler-generated symbol table. I included the header file that contains the prototype but that does not help. Am I missing something?
Jaydutt
Jaydutt
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
thx
ASKER
I can now create a CaptureWindow (i haven't tried connecting to the driver yet) but the window thus created is 100% transparent except for the titleBar and border. It does no close on Alt+F4 nor does it have Minimize/Maximixe/Close buttons. I know that I have to modify the window class for doing so but how can I do so?
The prototype for capCreateCaptureWindow is:
capCreateCaptureWindow(LPC TSTR, DWORD dwStyle, int, int, int, int, HWND Parent, int ID)
also how do I specify the WindowProcedure. Through window class?
thx
jaydutt
The prototype for capCreateCaptureWindow is:
capCreateCaptureWindow(LPC
also how do I specify the WindowProcedure. Through window class?
thx
jaydutt
CaptureWindow should be child window. Create it as dialog or frame window child.
Check out CapTest and VidCap samples which are available in MSDN Library.
Check out CapTest and VidCap samples which are available in MSDN Library.
ASKER
can't we specify wndProc for a child window?
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
thanks for all the help. I finally figured out how to use ARtoolkit. I found a tutorial for it. It's very easy to use provided you read the source code carefully. It is open source and is actually a partial wrapper for Windows Multimedia and IO. thx anyways.
now i have this question about Visual Studio. As you told me earlier,
> Add Vfw32.lib to the list of libraries for linker: Project - Settings - Link - Library modules.
I added libarvideo.lib to my proj. It compiles and links perfectly but when I try to run the exe it complains about missing "libarvideo.dll". how do i go about solving this problem?
thanks
now i have this question about Visual Studio. As you told me earlier,
> Add Vfw32.lib to the list of libraries for linker: Project - Settings - Link - Library modules.
I added libarvideo.lib to my proj. It compiles and links perfectly but when I try to run the exe it complains about missing "libarvideo.dll". how do i go about solving this problem?
thanks
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
thanks. I learned a lot.